diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java	Fri Jun 29 20:38:27 2012 +0200
@@ -0,0 +1,398 @@
+/**
+ * Implements the "annotations" uri of the Annotator API. see
+ * <https://github.com/okfn/annotator/wiki/Storage>
+ */
+package de.mpiwg.itgroup.annotations.restlet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.restlet.Context;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+import org.restlet.data.Reference;
+import org.restlet.data.Status;
+import org.restlet.ext.json.JsonRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Delete;
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.restlet.resource.Put;
+import org.restlet.security.User;
+
+import de.mpiwg.itgroup.annotationManager.Constants.NS;
+import de.mpiwg.itgroup.annotationManager.Errors.TripleStoreSearchError;
+import de.mpiwg.itgroup.annotationManager.Errors.TripleStoreStoreError;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Annotation;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.RDFSearcher;
+import de.mpiwg.itgroup.annotationManager.drupal.AnnotationHandler;
+import de.mpiwg.itgroup.annotationManager.drupal.UnknowUserException;
+import de.mpiwg.itgroup.triplestoremanager.exceptions.TripleStoreHandlerException;
+
+/**
+ * Implements the "annotations" uri of the Annotator API. see <https://github.com/okfn/annotator/wiki/Storage>
+ * 
+ * @author dwinter, casties
+ * 
+ */
+public class AnnotatorAnnotations extends AnnotatorResourceImpl {
+
+    protected String getAllowedMethodsForHeader() {
+        return "OPTIONS,GET,POST,PUT,DELETE";
+    }
+
+    /**
+     * GET with JSON content-type.
+     * 
+     * @param entity
+     * @return
+     */
+    @Get("json")
+    public Representation doGetJSON(Representation entity) {
+        logger.debug("AnnotatorAnnotations doGetJSON!");
+        setCorsHeaders();
+        // id from URI /annotations/{id}
+        String jsonId = (String) getRequest().getAttributes().get("id");
+        String id = decodeJsonId(jsonId);
+        logger.debug("annotation-id=" + id);
+
+        // TODO: what to return without id - list of all annotations?
+
+        // TODO: what to do with authentication?
+        boolean authenticated = isAuthenticated(entity);
+        logger.debug("request authenticated=" + authenticated);
+
+        RDFSearcher searcher = new RDFSearcher(NS.MPIWG_ANNOT_CTX); // TODO should ge into config file
+
+        try {
+            List<Annotation> annots = searcher.searchById(id);
+            if (annots.size() == 1) {
+                // there should be only one
+                JSONObject result = createAnnotatorJson(annots.get(0));
+                logger.debug("sending:");
+                logger.debug(result);
+                return new JsonRepresentation(result);
+            } else {
+                JSONArray results;
+                results = new JSONArray();
+                for (Annotation annot : annots) {
+                    JSONObject jo = createAnnotatorJson(annot);
+                    if (jo != null) {
+                        results.put(createAnnotatorJson(annot));
+                    } else {
+                        setStatus(Status.SERVER_ERROR_INTERNAL, "JSon Error");
+                        return null;
+                    }
+                }
+                // annotator read request returns a list of annotation objects
+                logger.debug("sending:");
+                logger.debug(results);
+                return new JsonRepresentation(results);
+            }
+        } catch (TripleStoreHandlerException e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreHandler Error");
+            return null;
+        } catch (TripleStoreSearchError e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreSearch Error");
+            return null;
+        }
+    }
+
+    /**
+     * POST with JSON content-type.
+     * 
+     * json hash: username: name des users xpointer: xpointer auf den Ausschnitt (incl. der URL des Dokumentes) text: text der
+     * annotation annoturl: url auf eine Annotation falls extern
+     * 
+     * @return
+     */
+    @Post("json")
+    public Representation doPostJson(Representation entity) {
+        logger.debug("AnnotatorAnnotations doPostJSON!");
+        // set headers
+        setCorsHeaders();
+        Annotation annot = null;
+        try {
+            JsonRepresentation jrep = new JsonRepresentation(entity);
+            JSONObject jo = jrep.getJsonObject();
+            if (jo == null) {
+                setStatus(Status.SERVER_ERROR_INTERNAL);
+                return null;
+            }
+            // make sure id is not set for POST
+            jo.remove("id");
+            // get Annotation object from posted JSON
+            annot = createAnnotation(jo, entity);
+        } catch (IOException e1) {
+            setStatus(Status.SERVER_ERROR_INTERNAL);
+            return null;
+        } catch (JSONException e) {
+            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+            return null;
+        }
+        if (annot == null || annot.xpointer == null || annot.creator == null) {
+            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+            return null;
+        }
+        Annotation storedAnnot;
+        try {
+            // store Annotation
+            storedAnnot = new Convert(NS.MPIWG_ANNOT_CTX).storeAnnotation(annot);
+        } catch (TripleStoreStoreError e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error");
+            return null;
+        }
+        /* according to https://github.com/okfn/annotator/wiki/Storage
+         * we should return 303: see other.
+         * For now we return the annotation.
+         */
+        JSONObject jo = createAnnotatorJson(storedAnnot);
+        JsonRepresentation retRep = new JsonRepresentation(jo);
+        return retRep;
+    }
+
+    /**
+     * POST with HTML content-type.
+     * 
+     * @param entity
+     * @return
+     */
+    @Post("html")
+    public Representation doPostHtml(Representation entity) {
+        logger.debug("AnnotatorAnnotations doPostHtml!");
+        Annotation annot;
+        annot = handleForm(entity);
+        if (annot.xpointer == null || annot.creator == null) {
+            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+
+            return null;
+        }
+
+        Annotation retValAnnot;
+        try {
+            retValAnnot = new Convert(NS.MPIWG_ANNOT_CTX).storeAnnotation(annot);
+        } catch (TripleStoreStoreError e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error");
+            return null;
+        }
+        if (retValAnnot == null) {
+            return null;
+        }
+        String retVal = retValAnnot.getAnnotationUri();
+        if (retVal == null) {
+            return null;
+        }
+
+        String text = String.format("<html><body><a href=\"%s\">%s</a></body></html>", retVal.replace(">", "").replace("<", ""),
+                retVal.replace(">", "&gt;").replace("<", "&lt;"));
+        Representation retRep = new StringRepresentation(text, MediaType.TEXT_HTML);
+        return retRep;
+    }
+
+    /**
+     * 
+     * @param entity
+     *            should contain a form with the parameters "username", "password", "xpointer","text","uri","type"
+     * 
+     *            username,password is optional, if not given BasicAuthentification is used.
+     * 
+     *            If username given as a URI, the username will be transformed to an URI, username will be added to the MPIWG
+     *            namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
+     * 
+     * @return
+     */
+    protected Annotation handleForm(Representation entity) {
+        Annotation annot;
+        Form form = new Form(entity);
+        String username = form.getValues("username");
+        String mode = form.getValues("mode");
+        String password = form.getValues("password");
+        String xpointer = form.getValues("xpointer");
+        String text = form.getValues("text");
+        String title = form.getValues("title");
+        String url = form.getValues("url");
+        String type = form.getValues("type");
+        RestServer restServer = (RestServer) getApplication();
+
+        // falls user and password nicht null sind:
+        User userFromForm = null;
+        if (username != null && password != null) {
+            if (restServer.authenticate(username, password, getRequest())) {
+                userFromForm = new User(username);
+            }
+        }
+        User authUser = null;
+
+        if (userFromForm == null) {
+            authUser = getHttpAuthUser(entity);
+        }
+
+        // weder BasicAuth noch FormAuth
+        if (authUser == null && userFromForm == null) {
+            setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+            return null;
+        }
+
+        if (userFromForm != null) {
+            username = userFromForm.getIdentifier();
+        } else {
+            username = authUser.getIdentifier();
+        }
+
+        // username should be a URI, if not it will set to the MPIWG namespace defined in
+        // de.mpiwg.itgroup.annotationManager.Constants.NS
+        String usernameOrig = username;
+        if (!username.startsWith("http"))
+            username = NS.MPIWG_PERSONS_URL + username;
+
+        if (mode.equals("complexAnnotation")) {// Annotation mit text in externer ressource
+
+            Context context = getContext();
+            String drupalPath = context.getParameters().getFirstValue("de.mpiwg.itgroup.annotationManager.drupalServer");
+
+            AnnotationHandler ah = new AnnotationHandler(drupalPath);
+            JSONObject newAnnot;
+            try {
+                newAnnot = ah.createAnnotation(title, text, usernameOrig, password);
+            } catch (UnknowUserException e1) {
+                setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+                e1.printStackTrace();
+                return null;
+            }
+            try {
+                annot = new Annotation(xpointer, username, null, text, type, newAnnot.getString("node_uri"));
+            } catch (JSONException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+                setStatus(Status.SERVER_ERROR_INTERNAL);
+                return null;
+            }
+        } else
+            annot = new Annotation(xpointer, username, null, text, type, url);
+        return annot;
+    }
+
+
+    /**
+     * PUT with JSON content-type.
+     * 
+     * @param entity
+     * @return
+     */
+    @Put("json")
+    public Representation doPutJSON(Representation entity) {
+        logger.debug("AnnotatorAnnotations doPutJSON!");
+        setCorsHeaders();
+        // id from URI /annotations/{id}
+        String jsonId = (String) getRequest().getAttributes().get("id");
+        String id = decodeJsonId(jsonId);
+        logger.debug("annotation-id=" + id);
+
+        // TODO: what to do with authentication? we should check the owner
+        boolean authenticated = isAuthenticated(entity);
+        logger.debug("request authenticated=" + authenticated);
+        if (!authenticated) {
+            setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
+            return null;            
+        }
+
+        Annotation annot = null;
+        try {
+            JsonRepresentation jrep = new JsonRepresentation(entity);
+            JSONObject jo = jrep.getJsonObject();
+            if (jo == null) {
+                setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+                return null;
+            }
+            RDFSearcher searcher = new RDFSearcher(NS.MPIWG_ANNOT_CTX); // TODO should ge into config file
+            // get stored Annotation
+            List<Annotation> annots = searcher.searchById(id);
+            if (annots.size() < 1) {
+                setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+                return null;
+            }
+            Annotation storedAnnot = annots.get(0);
+            // delete
+            searcher.deleteById(id);
+            // update from posted JSON
+            annot = updateAnnotation(storedAnnot, jo, entity);
+            // store Annotation
+            storedAnnot = new Convert(NS.MPIWG_ANNOT_CTX).storeAnnotation(annot);
+            /* according to https://github.com/okfn/annotator/wiki/Storage
+             * we should return 303: see other.
+             * but the client doesn't like it
+            setStatus(Status.REDIRECTION_SEE_OTHER);
+            // go to same URL as this one
+            Reference thisUrl = this.getReference();
+            this.getResponse().setLocationRef(thisUrl); */
+            // return new annotation
+            jo = createAnnotatorJson(storedAnnot);
+            JsonRepresentation retRep = new JsonRepresentation(jo);
+            return retRep;
+        } catch (TripleStoreHandlerException e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreHandler Error");
+        } catch (TripleStoreSearchError e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreSearch Error");
+        } catch (JSONException e) {
+            e.printStackTrace();
+            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+        } catch (IOException e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "Other Error");
+        }
+        return null;
+    }
+
+    /**
+     * DELETE with JSON content-type.
+     * 
+     * @param entity
+     * @return
+     */
+    @Delete("json")
+    public Representation doDeleteJSON(Representation entity) {
+        logger.debug("AnnotatorAnnotations doDeleteJSON!");
+        setCorsHeaders();
+        // id from URI /annotations/{id}
+        String jsonId = (String) getRequest().getAttributes().get("id");
+        String id = decodeJsonId(jsonId);
+        logger.debug("annotation-id=" + id);
+
+        // TODO: what to do with authentication? we should check the owner
+        boolean authenticated = isAuthenticated(entity);
+        logger.debug("request authenticated=" + authenticated);
+        if (!authenticated) {
+            setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
+            return null;            
+        }
+        
+        RDFSearcher searcher = new RDFSearcher(NS.MPIWG_ANNOT_CTX); // TODO should ge into config file
+
+        try {
+            // delete annotation
+            searcher.deleteById(id);
+            setStatus(Status.SUCCESS_NO_CONTENT);
+        } catch (TripleStoreHandlerException e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreHandler Error");
+        } catch (TripleStoreSearchError e) {
+            e.printStackTrace();
+            setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStoreSearch Error");
+        }
+        return null;
+    }
+    
+
+}