source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java @ 86:e3f0613b2f2d

Last change on this file since 86:e3f0613b2f2d was 86:e3f0613b2f2d, checked in by casties, 9 years ago

renamed getFullname to make it configurable.
fixed Restlet at 2.2.3.

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