Mercurial > hg > AnnotationManagerN4J
comparison src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java @ 3:47b53ae385d1
merging old code
| author | casties |
|---|---|
| date | Fri, 29 Jun 2012 20:38:27 +0200 |
| parents | |
| children | 3599b29c393f |
comparison
equal
deleted
inserted
replaced
| 2:f2d44c41eedf | 3:47b53ae385d1 |
|---|---|
| 1 /** | |
| 2 * Implements the "annotations" uri of the Annotator API. see | |
| 3 * <https://github.com/okfn/annotator/wiki/Storage> | |
| 4 */ | |
| 5 package de.mpiwg.itgroup.annotations.restlet; | |
| 6 | |
| 7 import java.io.IOException; | |
| 8 import java.util.ArrayList; | |
| 9 import java.util.List; | |
| 10 | |
| 11 import org.json.JSONArray; | |
| 12 import org.json.JSONException; | |
| 13 import org.json.JSONObject; | |
| 14 import org.restlet.Context; | |
| 15 import org.restlet.data.Form; | |
| 16 import org.restlet.data.MediaType; | |
| 17 import org.restlet.data.Reference; | |
| 18 import org.restlet.data.Status; | |
| 19 import org.restlet.ext.json.JsonRepresentation; | |
| 20 import org.restlet.representation.Representation; | |
| 21 import org.restlet.representation.StringRepresentation; | |
| 22 import org.restlet.resource.Delete; | |
| 23 import org.restlet.resource.Get; | |
| 24 import org.restlet.resource.Post; | |
| 25 import org.restlet.resource.Put; | |
| 26 import org.restlet.security.User; | |
| 27 | |
| 28 import de.mpiwg.itgroup.annotationManager.Constants.NS; | |
| 29 import de.mpiwg.itgroup.annotationManager.Errors.TripleStoreSearchError; | |
| 30 import de.mpiwg.itgroup.annotationManager.Errors.TripleStoreStoreError; | |
| 31 import de.mpiwg.itgroup.annotationManager.RDFHandling.Annotation; | |
| 32 import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert; | |
| 33 import de.mpiwg.itgroup.annotationManager.RDFHandling.RDFSearcher; | |
| 34 import de.mpiwg.itgroup.annotationManager.drupal.AnnotationHandler; | |
| 35 import de.mpiwg.itgroup.annotationManager.drupal.UnknowUserException; | |
| 36 import de.mpiwg.itgroup.triplestoremanager.exceptions.TripleStoreHandlerException; | |
| 37 | |
| 38 /** | |
| 39 * Implements the "annotations" uri of the Annotator API. see <https://github.com/okfn/annotator/wiki/Storage> | |
| 40 * | |
| 41 * @author dwinter, casties | |
| 42 * | |
| 43 */ | |
| 44 public class AnnotatorAnnotations extends AnnotatorResourceImpl { | |
| 45 | |
| 46 protected String getAllowedMethodsForHeader() { | |
| 47 return "OPTIONS,GET,POST,PUT,DELETE"; | |
| 48 } | |
| 49 | |
| 50 /** | |
| 51 * GET with JSON content-type. | |
| 52 * | |
| 53 * @param entity | |
| 54 * @return | |
| 55 */ | |
| 56 @Get("json") | |
| 57 public Representation doGetJSON(Representation entity) { | |
| 58 logger.debug("AnnotatorAnnotations doGetJSON!"); | |
| 59 setCorsHeaders(); | |
| 60 // id from URI /annotations/{id} | |
| 61 String jsonId = (String) getRequest().getAttributes().get("id"); | |
| 62 String id = decodeJsonId(jsonId); | |
| 63 logger.debug("annotation-id=" + id); | |
| 64 | |
| 65 // TODO: what to return without id - list of all annotations? | |
| 66 | |
| 67 // TODO: what to do with authentication? | |
| 68 boolean authenticated = isAuthenticated(entity); | |
| 69 logger.debug("request authenticated=" + authenticated); | |
| 70 | |
| 71 RDFSearcher searcher = new RDFSearcher(NS.MPIWG_ANNOT_CTX); // TODO should ge into config file | |
| 72 | |
| 73 try { | |
| 74 List<Annotation> annots = searcher.searchById(id); | |
| 75 if (annots.size() == 1) { | |
| 76 // there should be only one | |
| 77 JSONObject result = createAnnotatorJson(annots.get(0)); | |
| 78 logger.debug("sending:"); | |
| 79 logger.debug(result); | |
| 80 return new JsonRepresentation(result); | |
| 81 } else { | |
| 82 JSONArray results; | |
| 83 results = new JSONArray(); | |
| 84 for (Annotation annot : annots) { | |
| 85 JSONObject jo = createAnnotatorJson(annot); | |
| 86 if (jo != null) { | |
| 87 results.put(createAnnotatorJson(annot)); | |
| 88 } else { | |
| 89 setStatus(Status.SERVER_ERROR_INTERNAL, "JSon Error"); | |
| 90 return null; | |
| 91 } | |
| 92 } | |
| 93 // annotator read request returns a list of annotation objects | |
| 94 logger.debug("sending:"); | |
| 95 logger.debug(results); | |
| 96 return new JsonRepresentation(results); | |
| 97 } | |
| 98 } catch (TripleStoreHandlerException e) { | |
| 99 e.printStackTrace(); | |
| 100 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreHandler Error"); | |
| 101 return null; | |
| 102 } catch (TripleStoreSearchError e) { | |
| 103 e.printStackTrace(); | |
| 104 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreSearch Error"); | |
| 105 return null; | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 /** | |
| 110 * POST with JSON content-type. | |
| 111 * | |
| 112 * json hash: username: name des users xpointer: xpointer auf den Ausschnitt (incl. der URL des Dokumentes) text: text der | |
| 113 * annotation annoturl: url auf eine Annotation falls extern | |
| 114 * | |
| 115 * @return | |
| 116 */ | |
| 117 @Post("json") | |
| 118 public Representation doPostJson(Representation entity) { | |
| 119 logger.debug("AnnotatorAnnotations doPostJSON!"); | |
| 120 // set headers | |
| 121 setCorsHeaders(); | |
| 122 Annotation annot = null; | |
| 123 try { | |
| 124 JsonRepresentation jrep = new JsonRepresentation(entity); | |
| 125 JSONObject jo = jrep.getJsonObject(); | |
| 126 if (jo == null) { | |
| 127 setStatus(Status.SERVER_ERROR_INTERNAL); | |
| 128 return null; | |
| 129 } | |
| 130 // make sure id is not set for POST | |
| 131 jo.remove("id"); | |
| 132 // get Annotation object from posted JSON | |
| 133 annot = createAnnotation(jo, entity); | |
| 134 } catch (IOException e1) { | |
| 135 setStatus(Status.SERVER_ERROR_INTERNAL); | |
| 136 return null; | |
| 137 } catch (JSONException e) { | |
| 138 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); | |
| 139 return null; | |
| 140 } | |
| 141 if (annot == null || annot.xpointer == null || annot.creator == null) { | |
| 142 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); | |
| 143 return null; | |
| 144 } | |
| 145 Annotation storedAnnot; | |
| 146 try { | |
| 147 // store Annotation | |
| 148 storedAnnot = new Convert(NS.MPIWG_ANNOT_CTX).storeAnnotation(annot); | |
| 149 } catch (TripleStoreStoreError e) { | |
| 150 e.printStackTrace(); | |
| 151 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error"); | |
| 152 return null; | |
| 153 } | |
| 154 /* according to https://github.com/okfn/annotator/wiki/Storage | |
| 155 * we should return 303: see other. | |
| 156 * For now we return the annotation. | |
| 157 */ | |
| 158 JSONObject jo = createAnnotatorJson(storedAnnot); | |
| 159 JsonRepresentation retRep = new JsonRepresentation(jo); | |
| 160 return retRep; | |
| 161 } | |
| 162 | |
| 163 /** | |
| 164 * POST with HTML content-type. | |
| 165 * | |
| 166 * @param entity | |
| 167 * @return | |
| 168 */ | |
| 169 @Post("html") | |
| 170 public Representation doPostHtml(Representation entity) { | |
| 171 logger.debug("AnnotatorAnnotations doPostHtml!"); | |
| 172 Annotation annot; | |
| 173 annot = handleForm(entity); | |
| 174 if (annot.xpointer == null || annot.creator == null) { | |
| 175 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); | |
| 176 | |
| 177 return null; | |
| 178 } | |
| 179 | |
| 180 Annotation retValAnnot; | |
| 181 try { | |
| 182 retValAnnot = new Convert(NS.MPIWG_ANNOT_CTX).storeAnnotation(annot); | |
| 183 } catch (TripleStoreStoreError e) { | |
| 184 e.printStackTrace(); | |
| 185 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error"); | |
| 186 return null; | |
| 187 } | |
| 188 if (retValAnnot == null) { | |
| 189 return null; | |
| 190 } | |
| 191 String retVal = retValAnnot.getAnnotationUri(); | |
| 192 if (retVal == null) { | |
| 193 return null; | |
| 194 } | |
| 195 | |
| 196 String text = String.format("<html><body><a href=\"%s\">%s</a></body></html>", retVal.replace(">", "").replace("<", ""), | |
| 197 retVal.replace(">", ">").replace("<", "<")); | |
| 198 Representation retRep = new StringRepresentation(text, MediaType.TEXT_HTML); | |
| 199 return retRep; | |
| 200 } | |
| 201 | |
| 202 /** | |
| 203 * | |
| 204 * @param entity | |
| 205 * should contain a form with the parameters "username", "password", "xpointer","text","uri","type" | |
| 206 * | |
| 207 * username,password is optional, if not given BasicAuthentification is used. | |
| 208 * | |
| 209 * If username given as a URI, the username will be transformed to an URI, username will be added to the MPIWG | |
| 210 * namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS | |
| 211 * | |
| 212 * @return | |
| 213 */ | |
| 214 protected Annotation handleForm(Representation entity) { | |
| 215 Annotation annot; | |
| 216 Form form = new Form(entity); | |
| 217 String username = form.getValues("username"); | |
| 218 String mode = form.getValues("mode"); | |
| 219 String password = form.getValues("password"); | |
| 220 String xpointer = form.getValues("xpointer"); | |
| 221 String text = form.getValues("text"); | |
| 222 String title = form.getValues("title"); | |
| 223 String url = form.getValues("url"); | |
| 224 String type = form.getValues("type"); | |
| 225 RestServer restServer = (RestServer) getApplication(); | |
| 226 | |
| 227 // falls user and password nicht null sind: | |
| 228 User userFromForm = null; | |
| 229 if (username != null && password != null) { | |
| 230 if (restServer.authenticate(username, password, getRequest())) { | |
| 231 userFromForm = new User(username); | |
| 232 } | |
| 233 } | |
| 234 User authUser = null; | |
| 235 | |
| 236 if (userFromForm == null) { | |
| 237 authUser = getHttpAuthUser(entity); | |
| 238 } | |
| 239 | |
| 240 // weder BasicAuth noch FormAuth | |
| 241 if (authUser == null && userFromForm == null) { | |
| 242 setStatus(Status.CLIENT_ERROR_FORBIDDEN); | |
| 243 return null; | |
| 244 } | |
| 245 | |
| 246 if (userFromForm != null) { | |
| 247 username = userFromForm.getIdentifier(); | |
| 248 } else { | |
| 249 username = authUser.getIdentifier(); | |
| 250 } | |
| 251 | |
| 252 // username should be a URI, if not it will set to the MPIWG namespace defined in | |
| 253 // de.mpiwg.itgroup.annotationManager.Constants.NS | |
| 254 String usernameOrig = username; | |
| 255 if (!username.startsWith("http")) | |
| 256 username = NS.MPIWG_PERSONS_URL + username; | |
| 257 | |
| 258 if (mode.equals("complexAnnotation")) {// Annotation mit text in externer ressource | |
| 259 | |
| 260 Context context = getContext(); | |
| 261 String drupalPath = context.getParameters().getFirstValue("de.mpiwg.itgroup.annotationManager.drupalServer"); | |
| 262 | |
| 263 AnnotationHandler ah = new AnnotationHandler(drupalPath); | |
| 264 JSONObject newAnnot; | |
| 265 try { | |
| 266 newAnnot = ah.createAnnotation(title, text, usernameOrig, password); | |
| 267 } catch (UnknowUserException e1) { | |
| 268 setStatus(Status.CLIENT_ERROR_FORBIDDEN); | |
| 269 e1.printStackTrace(); | |
| 270 return null; | |
| 271 } | |
| 272 try { | |
| 273 annot = new Annotation(xpointer, username, null, text, type, newAnnot.getString("node_uri")); | |
| 274 } catch (JSONException e) { | |
| 275 // TODO Auto-generated catch block | |
| 276 e.printStackTrace(); | |
| 277 setStatus(Status.SERVER_ERROR_INTERNAL); | |
| 278 return null; | |
| 279 } | |
| 280 } else | |
| 281 annot = new Annotation(xpointer, username, null, text, type, url); | |
| 282 return annot; | |
| 283 } | |
| 284 | |
| 285 | |
| 286 /** | |
| 287 * PUT with JSON content-type. | |
| 288 * | |
| 289 * @param entity | |
| 290 * @return | |
| 291 */ | |
| 292 @Put("json") | |
| 293 public Representation doPutJSON(Representation entity) { | |
| 294 logger.debug("AnnotatorAnnotations doPutJSON!"); | |
| 295 setCorsHeaders(); | |
| 296 // id from URI /annotations/{id} | |
| 297 String jsonId = (String) getRequest().getAttributes().get("id"); | |
| 298 String id = decodeJsonId(jsonId); | |
| 299 logger.debug("annotation-id=" + id); | |
| 300 | |
| 301 // TODO: what to do with authentication? we should check the owner | |
| 302 boolean authenticated = isAuthenticated(entity); | |
| 303 logger.debug("request authenticated=" + authenticated); | |
| 304 if (!authenticated) { | |
| 305 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); | |
| 306 return null; | |
| 307 } | |
| 308 | |
| 309 Annotation annot = null; | |
| 310 try { | |
| 311 JsonRepresentation jrep = new JsonRepresentation(entity); | |
| 312 JSONObject jo = jrep.getJsonObject(); | |
| 313 if (jo == null) { | |
| 314 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); | |
| 315 return null; | |
| 316 } | |
| 317 RDFSearcher searcher = new RDFSearcher(NS.MPIWG_ANNOT_CTX); // TODO should ge into config file | |
| 318 // get stored Annotation | |
| 319 List<Annotation> annots = searcher.searchById(id); | |
| 320 if (annots.size() < 1) { | |
| 321 setStatus(Status.CLIENT_ERROR_NOT_FOUND); | |
| 322 return null; | |
| 323 } | |
| 324 Annotation storedAnnot = annots.get(0); | |
| 325 // delete | |
| 326 searcher.deleteById(id); | |
| 327 // update from posted JSON | |
| 328 annot = updateAnnotation(storedAnnot, jo, entity); | |
| 329 // store Annotation | |
| 330 storedAnnot = new Convert(NS.MPIWG_ANNOT_CTX).storeAnnotation(annot); | |
| 331 /* according to https://github.com/okfn/annotator/wiki/Storage | |
| 332 * we should return 303: see other. | |
| 333 * but the client doesn't like it | |
| 334 setStatus(Status.REDIRECTION_SEE_OTHER); | |
| 335 // go to same URL as this one | |
| 336 Reference thisUrl = this.getReference(); | |
| 337 this.getResponse().setLocationRef(thisUrl); */ | |
| 338 // return new annotation | |
| 339 jo = createAnnotatorJson(storedAnnot); | |
| 340 JsonRepresentation retRep = new JsonRepresentation(jo); | |
| 341 return retRep; | |
| 342 } catch (TripleStoreHandlerException e) { | |
| 343 e.printStackTrace(); | |
| 344 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreHandler Error"); | |
| 345 } catch (TripleStoreSearchError e) { | |
| 346 e.printStackTrace(); | |
| 347 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreSearch Error"); | |
| 348 } catch (JSONException e) { | |
| 349 e.printStackTrace(); | |
| 350 setStatus(Status.CLIENT_ERROR_BAD_REQUEST); | |
| 351 } catch (IOException e) { | |
| 352 e.printStackTrace(); | |
| 353 setStatus(Status.SERVER_ERROR_INTERNAL, "Other Error"); | |
| 354 } | |
| 355 return null; | |
| 356 } | |
| 357 | |
| 358 /** | |
| 359 * DELETE with JSON content-type. | |
| 360 * | |
| 361 * @param entity | |
| 362 * @return | |
| 363 */ | |
| 364 @Delete("json") | |
| 365 public Representation doDeleteJSON(Representation entity) { | |
| 366 logger.debug("AnnotatorAnnotations doDeleteJSON!"); | |
| 367 setCorsHeaders(); | |
| 368 // id from URI /annotations/{id} | |
| 369 String jsonId = (String) getRequest().getAttributes().get("id"); | |
| 370 String id = decodeJsonId(jsonId); | |
| 371 logger.debug("annotation-id=" + id); | |
| 372 | |
| 373 // TODO: what to do with authentication? we should check the owner | |
| 374 boolean authenticated = isAuthenticated(entity); | |
| 375 logger.debug("request authenticated=" + authenticated); | |
| 376 if (!authenticated) { | |
| 377 setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!"); | |
| 378 return null; | |
| 379 } | |
| 380 | |
| 381 RDFSearcher searcher = new RDFSearcher(NS.MPIWG_ANNOT_CTX); // TODO should ge into config file | |
| 382 | |
| 383 try { | |
| 384 // delete annotation | |
| 385 searcher.deleteById(id); | |
| 386 setStatus(Status.SUCCESS_NO_CONTENT); | |
| 387 } catch (TripleStoreHandlerException e) { | |
| 388 e.printStackTrace(); | |
| 389 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreHandler Error"); | |
| 390 } catch (TripleStoreSearchError e) { | |
| 391 e.printStackTrace(); | |
| 392 setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreSearch Error"); | |
| 393 } | |
| 394 return null; | |
| 395 } | |
| 396 | |
| 397 | |
| 398 } |
