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