Mercurial > hg > AnnotationManagerN4J
annotate src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java @ 22:b1fb0d117877
adding and listing groups via html works now.
no editing of group membership yet.
no authentication yet.
author | casties |
---|---|
date | Thu, 20 Sep 2012 17:42:26 +0200 |
parents | f0f55ab768c9 |
children | 03e0f7574224 |
rev | line source |
---|---|
3 | 1 /** |
2 * Base class for Annotator resource classes. | |
3 */ | |
4 package de.mpiwg.itgroup.annotations.restlet; | |
5 | |
6 import java.io.UnsupportedEncodingException; | |
7 import java.security.InvalidKeyException; | |
8 import java.security.SignatureException; | |
5 | 9 import java.text.SimpleDateFormat; |
3 | 10 import java.util.ArrayList; |
5 | 11 import java.util.Calendar; |
16 | 12 import java.util.HashSet; |
3 | 13 import java.util.List; |
16 | 14 import java.util.Set; |
3 | 15 import java.util.regex.Matcher; |
16 import java.util.regex.Pattern; | |
17 | |
18 import net.oauth.jsontoken.Checker; | |
19 import net.oauth.jsontoken.JsonToken; | |
20 import net.oauth.jsontoken.JsonTokenParser; | |
21 import net.oauth.jsontoken.SystemClock; | |
22 import net.oauth.jsontoken.crypto.HmacSHA256Verifier; | |
23 import net.oauth.jsontoken.crypto.Verifier; | |
24 | |
25 import org.apache.commons.codec.binary.Base64; | |
26 import org.apache.log4j.Logger; | |
27 import org.json.JSONArray; | |
28 import org.json.JSONException; | |
29 import org.json.JSONObject; | |
30 import org.restlet.data.Form; | |
31 import org.restlet.data.Status; | |
32 import org.restlet.representation.Representation; | |
33 import org.restlet.resource.Options; | |
34 import org.restlet.resource.ServerResource; | |
35 | |
9 | 36 import de.mpiwg.itgroup.annotations.Actor; |
4 | 37 import de.mpiwg.itgroup.annotations.Annotation; |
38 import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes; | |
10 | 39 import de.mpiwg.itgroup.annotations.Group; |
19 | 40 import de.mpiwg.itgroup.annotations.NS; |
10 | 41 import de.mpiwg.itgroup.annotations.Person; |
4 | 42 import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; |
3 | 43 |
44 /** | |
45 * Base class for Annotator resource classes. | |
46 * | |
47 * @author dwinter, casties | |
48 * | |
49 */ | |
50 public abstract class AnnotatorResourceImpl extends ServerResource { | |
51 | |
4 | 52 protected static Logger logger = Logger.getLogger(AnnotatorResourceImpl.class); |
53 | |
54 private AnnotationStore store; | |
3 | 55 |
56 protected String getAllowedMethodsForHeader() { | |
57 return "OPTIONS,GET,POST"; | |
58 } | |
59 | |
4 | 60 protected AnnotationStore getAnnotationStore() { |
61 if (store == null) { | |
19 | 62 store = ((BaseRestlet) getApplication()).getAnnotationStore(); |
4 | 63 } |
64 return store; | |
65 } | |
66 | |
3 | 67 public String encodeJsonId(String id) { |
22 | 68 if (id == null) return null; |
3 | 69 try { |
70 return Base64.encodeBase64URLSafeString(id.getBytes("UTF-8")); | |
71 } catch (UnsupportedEncodingException e) { | |
72 return null; | |
73 } | |
74 } | |
75 | |
76 public String decodeJsonId(String id) { | |
22 | 77 if (id == null) return null; |
3 | 78 try { |
79 return new String(Base64.decodeBase64(id), "UTF-8"); | |
80 } catch (UnsupportedEncodingException e) { | |
81 return null; | |
82 } | |
83 } | |
84 | |
85 /** | |
86 * Handle options request to allow CORS for AJAX. | |
87 * | |
88 * @param entity | |
89 */ | |
90 @Options | |
91 public void doOptions(Representation entity) { | |
92 logger.debug("AnnotatorResourceImpl doOptions!"); | |
93 setCorsHeaders(); | |
94 } | |
95 | |
96 /** | |
97 * set headers to allow CORS for AJAX. | |
98 */ | |
99 protected void setCorsHeaders() { | |
100 Form responseHeaders = (Form) getResponse().getAttributes().get("org.restlet.http.headers"); | |
101 if (responseHeaders == null) { | |
102 responseHeaders = new Form(); | |
103 getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders); | |
104 } | |
105 responseHeaders.add("Access-Control-Allow-Methods", getAllowedMethodsForHeader()); | |
106 // echo back Origin and Request-Headers | |
107 Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers"); | |
108 String origin = requestHeaders.getFirstValue("Origin", true); | |
109 if (origin == null) { | |
110 responseHeaders.add("Access-Control-Allow-Origin", "*"); | |
111 } else { | |
112 responseHeaders.add("Access-Control-Allow-Origin", origin); | |
113 } | |
114 String allowHeaders = requestHeaders.getFirstValue("Access-Control-Request-Headers", true); | |
115 if (allowHeaders != null) { | |
116 responseHeaders.add("Access-Control-Allow-Headers", allowHeaders); | |
117 } | |
118 responseHeaders.add("Access-Control-Allow-Credentials", "true"); | |
119 responseHeaders.add("Access-Control-Max-Age", "60"); | |
120 } | |
121 | |
122 /** | |
123 * returns if authentication information from headers is valid. | |
124 * | |
125 * @param entity | |
126 * @return | |
127 */ | |
128 public boolean isAuthenticated(Representation entity) { | |
129 return (checkAuthToken(entity) != null); | |
130 } | |
131 | |
132 /** | |
4 | 133 * checks Annotator Auth plugin authentication information from headers. |
134 * returns userId if successful. | |
3 | 135 * |
136 * @param entity | |
137 * @return | |
138 */ | |
139 public String checkAuthToken(Representation entity) { | |
140 Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers"); | |
141 String authToken = requestHeaders.getFirstValue("x-annotator-auth-token", true); | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
142 if (authToken == null) return null; |
3 | 143 // decode token first to get consumer key |
144 JsonToken token = new JsonTokenParser(null, null).deserialize(authToken); | |
145 String userId = token.getParamAsPrimitive("userId").getAsString(); | |
146 String consumerKey = token.getParamAsPrimitive("consumerKey").getAsString(); | |
147 // get stored consumer secret for key | |
18 | 148 BaseRestlet restServer = (BaseRestlet) getApplication(); |
3 | 149 String consumerSecret = restServer.getConsumerSecret(consumerKey); |
150 logger.debug("requested consumer key=" + consumerKey + " secret=" + consumerSecret); | |
151 if (consumerSecret == null) { | |
152 return null; | |
153 } | |
154 // logger.debug(String.format("token=%s tokenString=%s signatureAlgorithm=%s",token,token.getTokenString(),token.getSignatureAlgorithm())); | |
155 try { | |
156 List<Verifier> verifiers = new ArrayList<Verifier>(); | |
157 // we only do HS256 yet | |
158 verifiers.add(new HmacSHA256Verifier(consumerSecret.getBytes("UTF-8"))); | |
159 // verify token signature(should really be static...) | |
160 new JsonTokenParser(new SystemClock(), null, (Checker[]) null).verify(token, verifiers); | |
161 } catch (SignatureException e) { | |
162 // TODO Auto-generated catch block | |
163 e.printStackTrace(); | |
164 } catch (InvalidKeyException e) { | |
165 // TODO Auto-generated catch block | |
166 e.printStackTrace(); | |
167 } catch (UnsupportedEncodingException e) { | |
168 // TODO Auto-generated catch block | |
169 e.printStackTrace(); | |
170 } | |
171 // must be ok then | |
172 logger.debug("auth OK! user=" + userId); | |
173 return userId; | |
174 } | |
175 | |
176 /** | |
177 * creates Annotator-JSON from an Annotation object. | |
178 * | |
179 * @param annot | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
180 * @param forAnonymous TODO |
3 | 181 * @return |
182 */ | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
183 public JSONObject createAnnotatorJson(Annotation annot, boolean forAnonymous) { |
5 | 184 // return user as a JSON object (otherwise just as string) |
3 | 185 boolean makeUserObject = true; |
186 JSONObject jo = new JSONObject(); | |
187 try { | |
4 | 188 jo.put("text", annot.getBodyText()); |
189 jo.put("uri", annot.getTargetBaseUri()); | |
3 | 190 |
16 | 191 /* |
192 * user | |
193 */ | |
3 | 194 if (makeUserObject) { |
195 // create user object | |
196 JSONObject userObject = new JSONObject(); | |
10 | 197 Actor creator = annot.getCreator(); |
3 | 198 // save creator as uri |
10 | 199 userObject.put("uri", creator.getUri()); |
3 | 200 // make short user id |
10 | 201 String userId = creator.getIdString(); |
9 | 202 // set as id |
4 | 203 userObject.put("id", userId); |
3 | 204 // get full name |
10 | 205 String userName = creator.getName(); |
5 | 206 if (userName == null) { |
18 | 207 BaseRestlet restServer = (BaseRestlet) getApplication(); |
5 | 208 userName = restServer.getFullNameFromLdap(userId); |
209 } | |
3 | 210 userObject.put("name", userName); |
211 // save user object | |
212 jo.put("user", userObject); | |
213 } else { | |
214 // save user as string | |
4 | 215 jo.put("user", annot.getCreatorUri()); |
3 | 216 } |
217 | |
16 | 218 /* |
219 * ranges | |
220 */ | |
4 | 221 if (annot.getTargetFragment() != null) { |
3 | 222 // we only look at the first xpointer |
4 | 223 List<String> fragments = new ArrayList<String>(); |
224 fragments.add(annot.getTargetFragment()); | |
225 FragmentTypes xt = annot.getFragmentType(); | |
226 if (xt == FragmentTypes.XPOINTER) { | |
227 jo.put("ranges", transformToRanges(fragments)); | |
228 } else if (xt == FragmentTypes.AREA) { | |
229 jo.put("areas", transformToAreas(fragments)); | |
3 | 230 } |
231 } | |
10 | 232 |
16 | 233 /* |
234 * permissions | |
235 */ | |
10 | 236 JSONObject perms = new JSONObject(); |
237 jo.put("permissions", perms); | |
238 // admin | |
239 JSONArray adminPerms = new JSONArray(); | |
240 perms.put("admin", adminPerms); | |
241 Actor adminPerm = annot.getAdminPermission(); | |
242 if (adminPerm != null) { | |
243 adminPerms.put(adminPerm.getIdString()); | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
244 } else if (forAnonymous) { |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
245 // set something because its not allowed for anonymous |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
246 adminPerms.put("not-you"); |
10 | 247 } |
248 // delete | |
249 JSONArray deletePerms = new JSONArray(); | |
250 perms.put("delete", deletePerms); | |
251 Actor deletePerm = annot.getDeletePermission(); | |
252 if (deletePerm != null) { | |
253 deletePerms.put(deletePerm.getIdString()); | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
254 } else if (forAnonymous) { |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
255 // set something because its not allowed for anonymous |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
256 deletePerms.put("not-you"); |
10 | 257 } |
258 // update | |
259 JSONArray updatePerms = new JSONArray(); | |
260 perms.put("update", updatePerms); | |
261 Actor updatePerm = annot.getUpdatePermission(); | |
262 if (updatePerm != null) { | |
263 updatePerms.put(updatePerm.getIdString()); | |
14
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
264 } else if (forAnonymous) { |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
265 // set something because its not allowed for anonymous |
629e15b345aa
permissions mostly work. need more server-side checking.
casties
parents:
10
diff
changeset
|
266 updatePerms.put("not-you"); |
10 | 267 } |
268 // read | |
269 JSONArray readPerms = new JSONArray(); | |
270 perms.put("read", readPerms); | |
271 Actor readPerm = annot.getReadPermission(); | |
272 if (readPerm != null) { | |
273 readPerms.put(readPerm.getIdString()); | |
274 } | |
275 | |
16 | 276 /* |
277 * tags | |
278 */ | |
279 Set<String> tagset = annot.getTags(); | |
280 if (tagset != null) { | |
281 JSONArray tags = new JSONArray(); | |
282 jo.put("tags", tags); | |
283 for (String tag : tagset) { | |
284 tags.put(tag); | |
285 } | |
286 } | |
287 | |
288 /* | |
289 * id | |
290 */ | |
3 | 291 // encode Annotation URL (=id) in base64 |
4 | 292 String annotUrl = annot.getUri(); |
3 | 293 String annotId = encodeJsonId(annotUrl); |
294 jo.put("id", annotId); | |
295 return jo; | |
296 } catch (JSONException e) { | |
297 // TODO Auto-generated catch block | |
298 e.printStackTrace(); | |
299 } | |
300 return null; | |
301 } | |
302 | |
303 private JSONArray transformToRanges(List<String> xpointers) { | |
304 | |
305 JSONArray ja = new JSONArray(); | |
306 | |
307 Pattern rg = Pattern | |
4 | 308 .compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)/range-to\\(end-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)\\)"); |
309 Pattern rg1 = Pattern.compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)"); | |
3 | 310 |
311 try { | |
312 for (String xpointer : xpointers) { | |
10 | 313 // String decoded = URLDecoder.decode(xpointer, "utf-8"); |
5 | 314 String decoded = xpointer; |
3 | 315 Matcher m = rg.matcher(decoded); |
316 | |
317 if (m.find()) { | |
318 { | |
319 JSONObject jo = new JSONObject(); | |
320 jo.put("start", m.group(1)); | |
321 jo.put("startOffset", m.group(2)); | |
322 jo.put("end", m.group(3)); | |
323 jo.put("endOffset", m.group(4)); | |
324 ja.put(jo); | |
325 } | |
326 } | |
327 m = rg1.matcher(xpointer); | |
328 if (m.find()) { | |
329 JSONObject jo = new JSONObject(); | |
330 jo.put("start", m.group(1)); | |
331 jo.put("startOffset", m.group(2)); | |
332 | |
333 ja.put(jo); | |
334 } | |
335 } | |
336 } catch (JSONException e) { | |
337 // TODO Auto-generated catch block | |
338 e.printStackTrace(); | |
339 } | |
340 return ja; | |
341 } | |
342 | |
343 private JSONArray transformToAreas(List<String> xpointers) { | |
344 | |
345 JSONArray ja = new JSONArray(); | |
346 | |
4 | 347 Pattern rg = Pattern.compile("xywh=(\\w*:)([\\d\\.]+),([\\d\\.]+),([\\d\\.]+),([\\d\\.]+)"); |
3 | 348 |
349 try { | |
350 for (String xpointer : xpointers) { | |
10 | 351 // String decoded = URLDecoder.decode(xpointer, "utf-8"); |
5 | 352 String decoded = xpointer; |
3 | 353 Matcher m = rg.matcher(decoded); |
354 | |
355 if (m.find()) { | |
356 { | |
357 JSONObject jo = new JSONObject(); | |
10 | 358 @SuppressWarnings("unused") |
3 | 359 String unit = m.group(1); |
360 jo.put("x", m.group(2)); | |
361 jo.put("y", m.group(3)); | |
362 jo.put("width", m.group(4)); | |
363 jo.put("height", m.group(5)); | |
364 ja.put(jo); | |
365 } | |
366 } | |
367 } | |
368 } catch (JSONException e) { | |
369 // TODO Auto-generated catch block | |
370 e.printStackTrace(); | |
371 } | |
372 return ja; | |
373 } | |
374 | |
5 | 375 protected String parseArea(JSONObject area) throws JSONException { |
4 | 376 String x = area.getString("x"); |
377 String y = area.getString("y"); | |
378 String width = "0"; | |
379 String height = "0"; | |
380 if (area.has("width")) { | |
381 width = area.getString("width"); | |
382 height = area.getString("height"); | |
383 } | |
5 | 384 String fragment = String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height); |
4 | 385 return fragment; |
386 } | |
387 | |
5 | 388 protected String parseRange(JSONObject range) throws JSONException { |
4 | 389 String start = range.getString("start"); |
390 String end = range.getString("end"); | |
391 String startOffset = range.getString("startOffset"); | |
392 String endOffset = range.getString("endOffset"); | |
393 | |
5 | 394 String fragment = String.format( |
4 | 395 "xpointer(start-point(string-range(\"%s\",%s,1))/range-to(end-point(string-range(\"%s\",%s,1))))", start, |
5 | 396 startOffset, end, endOffset); |
4 | 397 return fragment; |
398 } | |
399 | |
3 | 400 /** |
5 | 401 * Creates an Annotation object with data from JSON. |
3 | 402 * |
4 | 403 * uses the specification from the annotator project: {@link https |
404 * ://github.com/okfn/annotator/wiki/Annotation-format} | |
3 | 405 * |
4 | 406 * The username will be transformed to an URI if not given already as URI, |
407 * if not it will set to the MPIWG namespace defined in | |
3 | 408 * de.mpiwg.itgroup.annotationManager.Constants.NS |
409 * | |
410 * @param jo | |
411 * @return | |
412 * @throws JSONException | |
4 | 413 * @throws UnsupportedEncodingException |
3 | 414 */ |
4 | 415 public Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException, UnsupportedEncodingException { |
3 | 416 return updateAnnotation(new Annotation(), jo, entity); |
417 } | |
418 | |
5 | 419 /** |
420 * Updates an Annotation object with data from JSON. | |
421 * | |
422 * uses the specification from the annotator project: {@link https | |
423 * ://github.com/okfn/annotator/wiki/Annotation-format} | |
424 * | |
425 * The username will be transformed to an URI if not given already as URI, | |
426 * if not it will set to the MPIWG namespace defined in | |
427 * de.mpiwg.itgroup.annotationManager.Constants.NS | |
428 * | |
429 * @param annot | |
430 * @param jo | |
431 * @return | |
432 * @throws JSONException | |
433 * @throws UnsupportedEncodingException | |
434 */ | |
4 | 435 public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException, |
436 UnsupportedEncodingException { | |
16 | 437 /* |
438 * target uri | |
439 */ | |
3 | 440 if (jo.has("uri")) { |
4 | 441 annot.setTargetBaseUri(jo.getString("uri")); |
3 | 442 } |
16 | 443 /* |
444 * annotation text | |
445 */ | |
3 | 446 if (jo.has("text")) { |
4 | 447 annot.setBodyText(jo.getString("text")); |
3 | 448 } |
16 | 449 /* |
450 * check authentication | |
451 */ | |
3 | 452 String authUser = checkAuthToken(entity); |
453 if (authUser == null) { | |
4 | 454 /* |
455 * // try http auth User httpUser = getHttpAuthUser(entity); if | |
456 * (httpUser == null) { | |
457 */ | |
458 setStatus(Status.CLIENT_ERROR_FORBIDDEN); | |
459 return null; | |
460 /* | |
461 * } authUser = httpUser.getIdentifier(); | |
462 */ | |
3 | 463 } |
16 | 464 /* |
465 * get or create creator object | |
466 */ | |
9 | 467 Actor creator = annot.getCreator(); |
468 if (creator == null) { | |
10 | 469 creator = new Person(); |
9 | 470 annot.setCreator(creator); |
471 } | |
3 | 472 // username not required, if no username given authuser will be used |
473 String username = null; | |
10 | 474 String userUri = creator.getUri(); |
3 | 475 if (jo.has("user")) { |
476 if (jo.get("user") instanceof String) { | |
477 // user is just a String | |
478 username = jo.getString("user"); | |
10 | 479 creator.setId(username); |
3 | 480 // TODO: what if username and authUser are different? |
481 } else { | |
482 // user is an object | |
483 JSONObject user = jo.getJSONObject("user"); | |
484 if (user.has("id")) { | |
10 | 485 String id = user.getString("id"); |
486 creator.setId(id); | |
487 username = id; | |
3 | 488 } |
489 if (user.has("uri")) { | |
490 userUri = user.getString("uri"); | |
491 } | |
492 } | |
493 } | |
494 if (username == null) { | |
495 username = authUser; | |
496 } | |
5 | 497 // try to get full name |
9 | 498 if (creator.getName() == null && username != null) { |
18 | 499 BaseRestlet restServer = (BaseRestlet) getApplication(); |
5 | 500 String fullName = restServer.getFullNameFromLdap(username); |
9 | 501 creator.setName(fullName); |
5 | 502 } |
503 // userUri should be a URI, if not it will set to the MPIWG namespace | |
3 | 504 if (userUri == null) { |
505 if (username.startsWith("http")) { | |
506 userUri = username; | |
507 } else { | |
508 userUri = NS.MPIWG_PERSONS_URL + username; | |
509 } | |
510 } | |
511 // TODO: should we overwrite the creator? | |
9 | 512 if (creator.getUri() == null) { |
513 creator.setUri(userUri); | |
5 | 514 } |
16 | 515 /* |
516 * creation date | |
517 */ | |
5 | 518 if (annot.getCreated() == null) { |
519 // set creation date | |
520 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); | |
521 String ct = format.format(Calendar.getInstance().getTime()); | |
522 annot.setCreated(ct); | |
523 } | |
3 | 524 |
16 | 525 /* |
526 * create xpointer from the first range/area | |
527 */ | |
3 | 528 if (jo.has("ranges")) { |
529 JSONObject ranges = jo.getJSONArray("ranges").getJSONObject(0); | |
4 | 530 annot.setFragmentType(FragmentTypes.XPOINTER); |
531 String fragment = parseRange(ranges); | |
532 annot.setTargetFragment(fragment); | |
3 | 533 } |
534 if (jo.has("areas")) { | |
535 JSONObject area = jo.getJSONArray("areas").getJSONObject(0); | |
4 | 536 annot.setFragmentType(FragmentTypes.AREA); |
537 String fragment = parseArea(area); | |
538 annot.setTargetFragment(fragment); | |
3 | 539 } |
10 | 540 |
16 | 541 /* |
542 * permissions | |
543 */ | |
10 | 544 if (jo.has("permissions")) { |
545 JSONObject permissions = jo.getJSONObject("permissions"); | |
546 if (permissions.has("admin")) { | |
547 JSONArray perms = permissions.getJSONArray("admin"); | |
548 Actor actor = getActorFromPermissions(perms); | |
549 annot.setAdminPermission(actor); | |
550 } | |
551 if (permissions.has("delete")) { | |
552 JSONArray perms = permissions.getJSONArray("delete"); | |
553 Actor actor = getActorFromPermissions(perms); | |
554 annot.setDeletePermission(actor); | |
555 } | |
556 if (permissions.has("update")) { | |
557 JSONArray perms = permissions.getJSONArray("update"); | |
558 Actor actor = getActorFromPermissions(perms); | |
559 annot.setUpdatePermission(actor); | |
560 } | |
561 if (permissions.has("read")) { | |
562 JSONArray perms = permissions.getJSONArray("read"); | |
563 Actor actor = getActorFromPermissions(perms); | |
564 annot.setReadPermission(actor); | |
565 } | |
566 } | |
567 | |
16 | 568 /* |
569 * tags | |
570 */ | |
571 if (jo.has("tags")) { | |
572 HashSet<String> tagset = new HashSet<String>(); | |
573 JSONArray tags = jo.getJSONArray("tags"); | |
574 for (int i = 0; i < tags.length(); ++i) { | |
575 tagset.add(tags.getString(i)); | |
576 } | |
577 annot.setTags(tagset); | |
578 } | |
579 | |
580 | |
4 | 581 return annot; |
3 | 582 } |
583 | |
15 | 584 @SuppressWarnings("unused") // i in for loop |
10 | 585 protected Actor getActorFromPermissions(JSONArray perms) throws JSONException { |
586 Actor actor = null; | |
587 for (int i = 0; i < perms.length(); ++i) { | |
588 String perm = perms.getString(i); | |
589 if (perm.toLowerCase().startsWith("group:")) { | |
590 String groupId = perm.substring(6); | |
591 actor = new Group(groupId); | |
592 } else { | |
593 actor = new Person(perm); | |
594 } | |
595 // we just take the first one | |
596 break; | |
597 } | |
598 return actor; | |
599 } | |
600 | |
3 | 601 } |