source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java @ 89:247cbbb385de

Last change on this file since 89:247cbbb385de was 89:247cbbb385de, checked in by casties, 9 years ago

improved logging.

File size: 29.4 KB
Line 
1package de.mpiwg.itgroup.annotations.restlet;
2
3/*
4 * #%L
5 * AnnotationManager
6 * %%
7 * Copyright (C) 2012 - 2014 MPIWG Berlin
8 * %%
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program.  If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * #L%
23 */
24
25import java.io.UnsupportedEncodingException;
26import java.text.SimpleDateFormat;
27import java.util.ArrayList;
28import java.util.Calendar;
29import java.util.HashSet;
30import java.util.List;
31import java.util.Set;
32import java.util.logging.Logger;
33import java.util.regex.Matcher;
34import java.util.regex.Pattern;
35
36import net.oauth.jsontoken.Checker;
37import net.oauth.jsontoken.JsonToken;
38import net.oauth.jsontoken.JsonTokenParser;
39import net.oauth.jsontoken.SystemClock;
40import net.oauth.jsontoken.crypto.HmacSHA256Verifier;
41import net.oauth.jsontoken.crypto.Verifier;
42
43import org.apache.commons.codec.binary.Base64;
44import org.json.JSONArray;
45import org.json.JSONException;
46import org.json.JSONObject;
47import org.restlet.data.Status;
48import org.restlet.engine.header.Header;
49import org.restlet.representation.Representation;
50import org.restlet.resource.Options;
51import org.restlet.resource.ServerResource;
52import org.restlet.util.Series;
53
54import com.google.gson.JsonArray;
55import com.google.gson.JsonElement;
56import com.google.gson.JsonObject;
57
58import de.mpiwg.itgroup.annotations.Actor;
59import de.mpiwg.itgroup.annotations.Annotation;
60import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;
61import de.mpiwg.itgroup.annotations.Group;
62import de.mpiwg.itgroup.annotations.Person;
63import de.mpiwg.itgroup.annotations.Resource;
64import de.mpiwg.itgroup.annotations.Target;
65import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
66
67/**
68 * Base class for Annotator resource classes.
69 *
70 * @author dwinter, casties
71 *
72 */
73public abstract class AnnotatorResourceImpl extends ServerResource {
74
75        protected static Logger logger = Logger.getLogger(AnnotatorResourceImpl.class.getCanonicalName());
76
77    private AnnotationStore store;
78
79    protected String getAllowedMethodsForHeader() {
80        return "OPTIONS,GET,POST";
81    }
82
83    protected AnnotationStore getAnnotationStore() {
84        if (store == null) {
85            store = ((BaseRestlet) getApplication()).getAnnotationStore();
86        }
87        return store;
88    }
89
90    public String encodeJsonId(String id) {
91        if (id == null)
92            return null;
93        try {
94            return Base64.encodeBase64URLSafeString(id.getBytes("UTF-8"));
95        } catch (UnsupportedEncodingException e) {
96            return null;
97        }
98    }
99
100    public String decodeJsonId(String id) {
101        if (id == null)
102            return null;
103        try {
104            return new String(Base64.decodeBase64(id), "UTF-8");
105        } catch (UnsupportedEncodingException e) {
106            return null;
107        }
108    }
109
110    /**
111     * Handle options request to allow CORS for AJAX.
112     *
113     * @param entity
114     */
115    @Options
116    public void doOptions(Representation entity) {
117        logger.fine("AnnotatorResourceImpl doOptions!");
118        setCorsHeaders();
119    }
120
121    /**
122     * set headers to allow CORS for AJAX.
123     */
124    protected void setCorsHeaders() {
125        @SuppressWarnings("unchecked")
126        Series<Header> responseHeaders = (Series<Header>) getResponse().getAttributes().get("org.restlet.http.headers");
127        if (responseHeaders == null) {
128            responseHeaders = new Series<Header>(Header.class);
129            getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
130        }
131        responseHeaders.add("Access-Control-Allow-Methods", getAllowedMethodsForHeader());
132        // echo back Origin and Request-Headers
133        @SuppressWarnings("unchecked")
134        Series<Header> requestHeaders = (Series<Header>) getRequest().getAttributes().get("org.restlet.http.headers");
135        String origin = requestHeaders.getFirstValue("Origin", true);
136        if (origin == null) {
137            responseHeaders.add("Access-Control-Allow-Origin", "*");
138        } else {
139            responseHeaders.add("Access-Control-Allow-Origin", origin);
140        }
141        String allowHeaders = requestHeaders.getFirstValue("Access-Control-Request-Headers", true);
142        if (allowHeaders != null) {
143            responseHeaders.add("Access-Control-Allow-Headers", allowHeaders);
144        }
145        responseHeaders.add("Access-Control-Allow-Credentials", "true");
146        responseHeaders.add("Access-Control-Max-Age", "60");
147    }
148
149    /**
150     * returns if authentication information from headers is valid.
151     *
152     * @param entity
153     * @return
154     */
155    public boolean isAuthenticated(Representation entity) {
156        return (getUserFromAuthToken(entity) != null);
157    }
158
159    /**
160     * Checks Annotator Auth plugin authentication information from headers.
161     * Returns userId if successful. Returns "anonymous" in non-authorization
162     * mode.
163     *
164     * @param entity
165     * @return user-id
166     */
167    public Person getUserFromAuthToken(Representation entity) {
168        @SuppressWarnings("unchecked")
169        Series<Header> requestHeaders = (Series<Header>) getRequest().getAttributes().get("org.restlet.http.headers");
170        String authToken = requestHeaders.getFirstValue("x-annotator-auth-token", true);
171        if (authToken == null) {
172            if (!((BaseRestlet) getApplication()).isAuthorizationMode()) {
173                // no token, no-auth mode -> anonymous
174                return Person.getAnonymous();
175            }
176            // no token, auth mode -> null
177            return null;
178        }
179                try {
180                        // decode token first to get consumer key
181            JsonToken token = new JsonTokenParser(null, null).deserialize(authToken);
182            String consumerKey = token.getParamAsPrimitive("consumerKey").getAsString();
183            // get stored consumer secret for key
184            BaseRestlet restServer = (BaseRestlet) getApplication();
185            String consumerSecret = restServer.getConsumerSecret(consumerKey);
186            logger.fine("requested consumer key=" + consumerKey + " secret=" + consumerSecret);
187                        if (consumerSecret == null) {
188                            logger.warning("Error: unknown consumer key: "+consumerKey);
189                                return null;
190                        }
191                        // logger.fine(String.format("token=%s tokenString=%s signatureAlgorithm=%s",token,token.getTokenString(),token.getSignatureAlgorithm()));
192            List<Verifier> verifiers = new ArrayList<Verifier>();
193            // we only do HS256 yet
194            verifiers.add(new HmacSHA256Verifier(consumerSecret.getBytes("UTF-8")));
195            // verify token signature(should really be static...)
196            new JsonTokenParser(new SystemClock(), null, (Checker[]) null).verify(token, verifiers);
197            // create Person
198            JsonObject payload = token.getPayloadAsJsonObject();
199            // userId is mandatory
200            String userId = payload.get("userId").getAsString();
201            Person user = new Person(userId);
202            // displayName is optional
203            if (payload.has("displayName")) {
204                user.name = payload.get("displayName").getAsString();
205            }
206            // memberOf groups is optional
207            if (payload.has("memberOf")) {
208                Set<String> groups = new HashSet<String>();
209                JsonArray jgroups = payload.get("memberOf").getAsJsonArray();
210                for (JsonElement jgroup : jgroups) {
211                    groups.add(jgroup.getAsString());
212                }
213                user.groups = groups;
214            }
215            logger.fine("auth OK! user=" + user);
216            return user;
217        } catch (Exception e) {
218            logger.warning("Error checking auth token: "+e.toString());
219        }
220        return null;
221    }
222
223    /**
224     * creates Annotator-JSON from an Annotation object.
225     *
226     * @param annot annotation object
227     * @param forAnonymous
228     * @return Annotator-JSON
229     */
230    public JSONObject createAnnotatorJson(Annotation annot, boolean forAnonymous) {
231        // return user as a JSON object (otherwise just as string)
232        boolean makeUserObject = true;
233        JSONObject jo = new JSONObject();
234        try {
235            jo.put("text", annot.getBodyText());
236            jo.put("uri", annot.getTargetBaseUri());
237            if (annot.getResourceUri() != null) {
238                jo.put("resource", annot.getResourceUri());
239            }
240            if (annot.getQuote() != null) {
241                jo.put("quote", annot.getQuote());
242            }
243
244            /*
245             * user
246             */
247            Actor creator = annot.getCreator();
248            if (creator != null) {
249                if (makeUserObject) {
250                    // create user object
251                    JSONObject userObject = new JSONObject();
252                    // save creator as uri
253                    userObject.put("uri", creator.getUri());
254                    // make short user id
255                    String userId = creator.getIdString();
256                    // set as id
257                    userObject.put("id", userId);
258                    // get full name
259                    String userName = creator.getName();
260                    if (userName == null) {
261                        BaseRestlet restServer = (BaseRestlet) getApplication();
262                        userName = restServer.getFullNameForId(userId);
263                    }
264                    userObject.put("name", userName);
265                    // save user object
266                    jo.put("user", userObject);
267                } else {
268                    // save user as string
269                    jo.put("user", annot.getCreatorUri());
270                }
271            }
272
273            /*
274             * ranges
275             */
276            if (annot.getTargetFragment() != null) {
277                // we only look at the first xpointer
278                List<String> fragments = new ArrayList<String>();
279                fragments.add(annot.getTargetFragment());
280                FragmentTypes xt = annot.getFragmentType();
281                if (xt == FragmentTypes.XPOINTER) {
282                    jo.put("ranges", transformToRanges(fragments));
283                } else if (xt == FragmentTypes.AREA) {
284                    jo.put("shapes", transformToShapes(fragments));
285                } else if (xt == FragmentTypes.WKT) {
286                    jo.put("shapes", transformToShapes(fragments));
287                }
288            }
289
290            /*
291             * permissions
292             */
293            JSONObject perms = new JSONObject();
294            jo.put("permissions", perms);
295            // admin
296            JSONArray adminPerms = new JSONArray();
297            perms.put("admin", adminPerms);
298            Actor adminPerm = annot.getAdminPermission();
299            if (adminPerm != null) {
300                adminPerms.put(adminPerm.getIdString());
301            } else if (forAnonymous) {
302                // set something because its not allowed for anonymous
303                adminPerms.put("not-you");
304            }
305            // delete
306            JSONArray deletePerms = new JSONArray();
307            perms.put("delete", deletePerms);
308            Actor deletePerm = annot.getDeletePermission();
309            if (deletePerm != null) {
310                deletePerms.put(deletePerm.getIdString());
311            } else if (forAnonymous) {
312                // set something because its not allowed for anonymous
313                deletePerms.put("not-you");
314            }
315            // update
316            JSONArray updatePerms = new JSONArray();
317            perms.put("update", updatePerms);
318            Actor updatePerm = annot.getUpdatePermission();
319            if (updatePerm != null) {
320                updatePerms.put(updatePerm.getIdString());
321            } else if (forAnonymous) {
322                // set something because its not allowed for anonymous
323                updatePerms.put("not-you");
324            }
325            // read
326            JSONArray readPerms = new JSONArray();
327            perms.put("read", readPerms);
328            Actor readPerm = annot.getReadPermission();
329            if (readPerm != null) {
330                readPerms.put(readPerm.getIdString());
331            }
332
333            /*
334             * tags
335             */
336            Set<String> tagset = annot.getTags();
337            if (tagset != null) {
338                JSONArray tags = new JSONArray();
339                jo.put("tags", tags);
340                for (String tag : tagset) {
341                    tags.put(tag);
342                }
343            }
344
345            /*
346             * id
347             */
348            // encode Annotation URL (=id) in base64
349            String annotUrl = annot.getUri();
350            String annotId = encodeJsonId(annotUrl);
351            jo.put("id", annotId);
352            return jo;
353        } catch (JSONException e) {
354            logger.severe("Unable to create AnnotatorJSON! "+e);
355        }
356        return null;
357    }
358
359    private JSONArray transformToRanges(List<String> xpointers) {
360        JSONArray ja = new JSONArray();
361        Pattern rg = Pattern
362                .compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)/range-to\\(end-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)\\)");
363        Pattern rg1 = Pattern.compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)");
364        try {
365            for (String xpointer : xpointers) {
366                // String decoded = URLDecoder.decode(xpointer, "utf-8");
367                String decoded = xpointer;
368                Matcher m = rg.matcher(decoded);
369                if (m.find()) {
370                    JSONObject jo = new JSONObject();
371                    jo.put("start", m.group(1));
372                    jo.put("startOffset", m.group(2));
373                    jo.put("end", m.group(3));
374                    jo.put("endOffset", m.group(4));
375                    ja.put(jo);
376                }
377                m = rg1.matcher(xpointer);
378                if (m.find()) {
379                    JSONObject jo = new JSONObject();
380                    jo.put("start", m.group(1));
381                    jo.put("startOffset", m.group(2));
382                    ja.put(jo);
383                }
384            }
385        } catch (JSONException e) {
386            logger.severe("Unable to transform to ranges! "+e);
387        }
388        return ja;
389    }
390
391    private JSONArray transformToShapes(List<String> fragments) {
392        JSONArray ja = new JSONArray();
393        Pattern xywhPattern = Pattern.compile("xywh=(\\w*):([\\d\\.]+),([\\d\\.]+),([\\d\\.]+),([\\d\\.]+)");
394        Pattern wktPattern = Pattern.compile("wkt=(\\w+)\\(+([\\d\\.\\,\\ ]+)\\)+");
395        try {
396            for (String fragment : fragments) {
397                Matcher xywhMatch = xywhPattern.matcher(fragment);
398                Matcher wktMatch = wktPattern.matcher(fragment);
399                if (xywhMatch.find()) {
400                        // xywh rectangle fragment
401                    String units = xywhMatch.group(1);
402                    float x = getFloat(xywhMatch.group(2));
403                    float y = getFloat(xywhMatch.group(3));
404                    float width = getFloat(xywhMatch.group(4));
405                    float height = getFloat(xywhMatch.group(5));
406                    JSONObject shape = new JSONObject();
407                    JSONObject geom = new JSONObject();
408                    geom.put("units", units);
409                    geom.put("x", x);
410                    geom.put("y", y);
411                    if (width == 0 || height == 0) {
412                        shape.put("type", "point");
413                        shape.put("geometry", geom);
414                    } else {
415                        shape.put("type", "rectangle");
416                        geom.put("width", width);
417                        geom.put("height", height);
418                        shape.put("geometry", geom);
419                    }
420                    ja.put(shape);
421                } else if (wktMatch.find()) {
422                        // wkt shape fragment
423                        String type = wktMatch.group(1);
424                        String coordString = wktMatch.group(2);
425                    JSONObject shape = new JSONObject();
426                    JSONObject geom = new JSONObject();
427                    shape.put("type", type.toLowerCase());
428                    // TODO: add units/crs to fragment?
429                    geom.put("units", "fraction");
430                    JSONArray coords = new JSONArray();
431                    String[] coordPairs = coordString.split(", *");
432                    for (String coordPairString : coordPairs) {
433                        String[] coordPair = coordPairString.split(" +");
434                        coords.put(new JSONArray(coordPair));
435                    }
436                    geom.put("coordinates", coords);
437                        shape.put("geometry", geom);
438                        ja.put(shape);
439                }
440            }
441        } catch (JSONException e) {
442            logger.severe("Unable to transform to shapes! "+e);
443        }
444        return ja;
445    }
446
447    protected String parseShape(JSONObject shape) throws JSONException {
448        String fragment = null;
449        String type = shape.getString("type");
450        JSONObject geom = shape.getJSONObject("geometry");
451        if (type.equalsIgnoreCase("point")) {
452                // point shape
453            String x = geom.getString("x");
454            String y = geom.getString("y");
455            fragment = String.format("xywh=fraction:%s,%s,0,0", x, y);
456        } else if (type.equalsIgnoreCase("rectangle")) {
457                // rectangle shape
458            String x = geom.getString("x");
459            String y = geom.getString("y");
460            String width = geom.getString("width");
461            String height = geom.getString("height");
462            fragment = String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height);
463        } else if (type.equalsIgnoreCase("polygon")) {
464                // polygon shape
465                JSONArray coordArray = geom.getJSONArray("coordinates");
466            StringBuilder coords = new StringBuilder();
467            int numCoords = coordArray.length();
468                for (int i = 0; i < numCoords; ++i) {
469                        JSONArray coordPair = coordArray.getJSONArray(i);
470                        coords.append(coordPair.getString(0));
471                        coords.append(" ");
472                        coords.append(coordPair.getString(1));
473                        if (i < numCoords-1) {
474                                coords.append(", ");
475                        }
476                }
477                // TODO: add units/crs to wkt
478                // assume polygon with outer ring
479            fragment = String.format("wkt=POLYGON((%s))", coords);
480        } else if (type.equalsIgnoreCase("linestring")) {
481                // linestring (polyline) shape
482                JSONArray coordArray = geom.getJSONArray("coordinates");
483            StringBuilder coords = new StringBuilder();
484            int numCoords = coordArray.length();
485                for (int i = 0; i < numCoords; ++i) {
486                        JSONArray coordPair = coordArray.getJSONArray(i);
487                        coords.append(coordPair.getString(0));
488                        coords.append(" ");
489                        coords.append(coordPair.getString(1));
490                        if (i < numCoords-1) {
491                                coords.append(", ");
492                        }
493                }
494                // TODO: add units/crs to wkt
495            fragment = String.format("wkt=LINESTRING(%s)", coords);
496        } else {
497            logger.severe("Unable to parse this shape: " + shape);
498        }
499        return fragment;
500    }
501
502    protected String parseArea(JSONObject area) throws JSONException {
503        String x = area.getString("x");
504        String y = area.getString("y");
505        String width = "0";
506        String height = "0";
507        if (area.has("width")) {
508            width = area.getString("width");
509            height = area.getString("height");
510        }
511        String fragment = String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height);
512        return fragment;
513    }
514
515    protected String parseRange(JSONObject range) throws JSONException {
516        String start = range.getString("start");
517        String end = range.getString("end");
518        String startOffset = range.getString("startOffset");
519        String endOffset = range.getString("endOffset");
520        String fragment = String.format(
521                "xpointer(start-point(string-range(\"%s\",%s,1))/range-to(end-point(string-range(\"%s\",%s,1))))", start,
522                startOffset, end, endOffset);
523        return fragment;
524    }
525
526    /**
527     * Creates an Annotation object with data from JSON.
528     *
529     * uses the specification from the annotator project: {@link https
530     * ://github.com/okfn/annotator/wiki/Annotation-format}
531     *
532     * The username will be transformed to an URI if not given already as URI,
533     * if not it will set to the MPIWG namespace defined in
534     * de.mpiwg.itgroup.annotationManager.Constants.NS
535     *
536     * @param jo
537     * @return
538     * @throws JSONException
539     * @throws UnsupportedEncodingException
540     */
541    public Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException, UnsupportedEncodingException {
542        return updateAnnotation(new Annotation(), jo, entity);
543    }
544
545    /**
546     * Updates an Annotation object with data from JSON.
547     *
548     * uses the specification from the annotator project: {@link https
549     * ://github.com/okfn/annotator/wiki/Annotation-format}
550     *
551     * The username will be transformed to an URI if not given already as URI,
552     * if not it will set to the MPIWG namespace defined in
553     * de.mpiwg.itgroup.annotationManager.Constants.NS
554     *
555     * @param annot
556     * @param jo
557     * @return
558     * @throws JSONException
559     * @throws UnsupportedEncodingException
560     */
561    public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException,
562            UnsupportedEncodingException {
563        /*
564         * target uri
565         */
566        if (jo.has("uri")) {
567            annot.setTarget(new Target(jo.getString("uri")));
568        }
569        /*
570         * resource uri
571         */
572        if (jo.has("resource")) {
573            annot.setResource(new Resource(jo.getString("resource")));
574        }
575        /*
576         * annotation text
577         */
578        if (jo.has("text")) {
579            annot.setBodyText(jo.getString("text"));
580        }
581        /*
582         * annotation quote
583         */
584        if (jo.has("quote")) {
585            annot.setQuote(jo.getString("quote"));
586        }
587        /*
588         * check authentication
589         */
590        Person authUser = getUserFromAuthToken(entity);
591        if (authUser == null) {
592            /*
593             * // try http auth User httpUser = getHttpAuthUser(entity); if
594             * (httpUser == null) {
595             */
596            setStatus(Status.CLIENT_ERROR_FORBIDDEN);
597            return null;
598            /*
599             * } authUser = httpUser.getIdentifier();
600             */
601        }
602        /*
603         * get or create creator object
604         */
605        Actor creator = annot.getCreator();
606        if (creator == null) {
607            creator = new Person();
608            annot.setCreator(creator);
609        }
610        // username not required, if no username given authuser will be used
611        String username = null;
612        String userUri = creator.getUri();
613        if (jo.has("user")) {
614            if (jo.get("user") instanceof String) {
615                // user is just a String
616                username = jo.getString("user");
617                creator.setId(username);
618                // TODO: what if username and authUser are different?
619            } else {
620                // user is an object
621                JSONObject user = jo.getJSONObject("user");
622                if (user.has("id")) {
623                    String id = user.getString("id");
624                    creator.setId(id);
625                    username = id;
626                }
627                if (user.has("uri")) {
628                    userUri = user.getString("uri");
629                }
630            }
631        }
632        if (username == null) {
633            username = authUser.getName();
634        }
635        // try to get full name
636        if (creator.getName() == null && username != null) {
637            BaseRestlet restServer = (BaseRestlet) getApplication();
638            String fullName = restServer.getFullNameForId(username);
639            creator.setName(fullName);
640        }
641        // userUri should be a URI, if not it will set to the MPIWG namespace
642        if (userUri == null) {
643            if (username.startsWith("http")) {
644                userUri = username;
645            } else {
646                userUri = BaseRestlet.PERSONS_URI_PREFIX + username;
647            }
648        }
649        // TODO: should we overwrite the creator?
650        if (creator.getUri() == null) {
651            creator.setUri(userUri);
652        }
653        /*
654         * creation date
655         */
656        if (annot.getCreated() == null) {
657            // set creation date
658            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
659            String ct = format.format(Calendar.getInstance().getTime());
660            annot.setCreated(ct);
661        }
662
663        /*
664         * create fragment from the first range/area
665         */
666        try {
667            if (jo.has("ranges")) {
668                JSONArray ranges = jo.getJSONArray("ranges");
669                if (ranges.length() > 0) {
670                    JSONObject range = ranges.getJSONObject(0);
671                    annot.setFragmentType(FragmentTypes.XPOINTER);
672                    String fragment = parseRange(range);
673                    annot.setTargetFragment(fragment);
674                }
675            }
676        } catch (JSONException e) {
677            // nothing to do
678        }
679        try {
680            if (jo.has("shapes")) {
681                JSONArray shapes = jo.getJSONArray("shapes");
682                if (shapes.length() > 0) {
683                    JSONObject shape = shapes.getJSONObject(0);
684                    String fragment = parseShape(shape);
685                    annot.setTargetFragment(fragment);
686                    if (fragment.startsWith("wkt=")) {
687                        annot.setFragmentType(FragmentTypes.WKT);
688                    } else {
689                        annot.setFragmentType(FragmentTypes.AREA);
690                    }
691                }
692            }
693        } catch (JSONException e) {
694            // nothing to do
695        }
696        // deprecated areas type
697        try {
698            if (jo.has("areas")) {
699                JSONArray areas = jo.getJSONArray("areas");
700                if (areas.length() > 0) {
701                    JSONObject area = areas.getJSONObject(0);
702                    annot.setFragmentType(FragmentTypes.AREA);
703                    String fragment = parseArea(area);
704                    annot.setTargetFragment(fragment);
705                }
706            }
707        } catch (JSONException e) {
708            // nothing to do
709        }
710        // no fragment is an error
711        if (annot.getFragmentType() == null || annot.getTargetFragment() == null) {
712            throw new JSONException("Annotation has no valid target fragment!");
713        }
714
715        /*
716         * permissions
717         */
718        if (jo.has("permissions")) {
719            JSONObject permissions = jo.getJSONObject("permissions");
720            if (permissions.has("admin")) {
721                JSONArray perms = permissions.getJSONArray("admin");
722                Actor actor = getActorFromPermissions(perms);
723                annot.setAdminPermission(actor);
724            }
725            if (permissions.has("delete")) {
726                JSONArray perms = permissions.getJSONArray("delete");
727                Actor actor = getActorFromPermissions(perms);
728                annot.setDeletePermission(actor);
729            }
730            if (permissions.has("update")) {
731                JSONArray perms = permissions.getJSONArray("update");
732                Actor actor = getActorFromPermissions(perms);
733                annot.setUpdatePermission(actor);
734            }
735            if (permissions.has("read")) {
736                JSONArray perms = permissions.getJSONArray("read");
737                Actor actor = getActorFromPermissions(perms);
738                annot.setReadPermission(actor);
739            }
740        }
741
742        /*
743         * tags
744         */
745        if (jo.has("tags")) {
746            HashSet<String> tagset = new HashSet<String>();
747            JSONArray tags = jo.getJSONArray("tags");
748            for (int i = 0; i < tags.length(); ++i) {
749                tagset.add(tags.getString(i));
750            }
751            annot.setTags(tagset);
752        }
753
754        return annot;
755    }
756
757    @SuppressWarnings("unused")
758    // i in for loop
759    protected Actor getActorFromPermissions(JSONArray perms) throws JSONException {
760        Actor actor = null;
761        for (int i = 0; i < perms.length(); ++i) {
762            String perm = perms.getString(i);
763            if (perm.toLowerCase().startsWith("group:")) {
764                String groupId = perm.substring(6);
765                actor = new Group(groupId);
766            } else {
767                actor = new Person(perm);
768            }
769            // we just take the first one
770            break;
771        }
772        return actor;
773    }
774
775    public static float getFloat(String s) {
776        try {
777            return Float.parseFloat(s);
778        } catch (NumberFormatException e) {
779        }
780        return 0f;
781    }
782
783    public static int getInt(String s) {
784        try {
785            return Integer.parseInt(s);
786        } catch (NumberFormatException e) {
787        }
788        return 0;
789    }
790}
Note: See TracBrowser for help on using the repository browser.