# HG changeset patch
# User casties
# Date 1341261586 -7200
# Node ID 3599b29c393f1915e53f674f6ff4907d7b39c629
# Parent 47b53ae385d1f9e3491a07bbab97d9f35ca494ec
store seems to work now :-)
diff -r 47b53ae385d1 -r 3599b29c393f pom.xml
--- a/pom.xml Fri Jun 29 20:38:27 2012 +0200
+++ b/pom.xml Mon Jul 02 22:39:46 2012 +0200
@@ -96,4 +96,5 @@
war
+ AnnotationManager
\ No newline at end of file
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/Annotation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/mpiwg/itgroup/annotations/Annotation.java Mon Jul 02 22:39:46 2012 +0200
@@ -0,0 +1,172 @@
+/**
+ *
+ */
+package de.mpiwg.itgroup.annotations;
+
+/**
+ * @author casties
+ *
+ */
+public class Annotation {
+ /**
+ * The URI of this annotation.
+ */
+ protected String uri;
+
+ /**
+ * The annotation (body) text.
+ */
+ protected String bodyText;
+
+ /**
+ * The URI of the annotation text
+ */
+ protected String bodyUri;
+
+ /**
+ * The base URI of the annotation target.
+ */
+ protected String targetBaseUri;
+
+ /**
+ * The fragment part of the annotation target.
+ */
+ protected String targetFragment;
+
+ /**
+ * The types of annotation targets.
+ *
+ */
+ public static enum FragmentTypes {
+ XPOINTER, AREA
+ };
+
+ /**
+ * The type of the annotation target fragment.
+ */
+ protected FragmentTypes fragmentType;
+
+ /**
+ * The URI of the creator of this annotation.
+ */
+ protected String creatorUri;
+
+ /**
+ * The creation date of this annotation.
+ */
+ protected String created;
+
+ /**
+ * @return the uri
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * @param uri the uri to set
+ */
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * @return the bodyText
+ */
+ public String getBodyText() {
+ return bodyText;
+ }
+
+ /**
+ * @param bodyText the bodyText to set
+ */
+ public void setBodyText(String bodyText) {
+ this.bodyText = bodyText;
+ }
+
+ /**
+ * @return the bodyUri
+ */
+ public String getBodyUri() {
+ return bodyUri;
+ }
+
+ /**
+ * @param bodyUri the bodyUri to set
+ */
+ public void setBodyUri(String bodyUri) {
+ this.bodyUri = bodyUri;
+ }
+
+ /**
+ * @return the targetBaseUri
+ */
+ public String getTargetBaseUri() {
+ return targetBaseUri;
+ }
+
+ /**
+ * @param targetBaseUri the targetBaseUri to set
+ */
+ public void setTargetBaseUri(String targetBaseUri) {
+ this.targetBaseUri = targetBaseUri;
+ }
+
+ /**
+ * @return the targetFragment
+ */
+ public String getTargetFragment() {
+ return targetFragment;
+ }
+
+ /**
+ * @param targetFragment the targetFragment to set
+ */
+ public void setTargetFragment(String targetFragment) {
+ this.targetFragment = targetFragment;
+ }
+
+ /**
+ * @return the targetType
+ */
+ public FragmentTypes getFragmentType() {
+ return fragmentType;
+ }
+
+ /**
+ * @param fragmentType the fragmentType to set
+ */
+ public void setFragmentType(FragmentTypes fragmentType) {
+ this.fragmentType = fragmentType;
+ }
+
+ /**
+ * @return the creatorUri
+ */
+ public String getCreatorUri() {
+ return creatorUri;
+ }
+
+ /**
+ * @param creatorUri the creatorUri to set
+ */
+ public void setCreatorUri(String creatorUri) {
+ this.creatorUri = creatorUri;
+ }
+
+ /**
+ * @return the created
+ */
+ public String getCreated() {
+ return created;
+ }
+
+ /**
+ * @param created the created to set
+ */
+ public void setCreated(String created) {
+ this.created = created;
+ }
+
+
+}
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java Mon Jul 02 22:39:46 2012 +0200
@@ -0,0 +1,294 @@
+/**
+ *
+ */
+package de.mpiwg.itgroup.annotations.neo4j;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.graphdb.Transaction;
+import org.neo4j.graphdb.index.Index;
+import org.neo4j.graphdb.index.IndexHits;
+
+import de.mpiwg.itgroup.annotations.Annotation;
+import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;
+
+/**
+ * @author casties
+ *
+ */
+public class AnnotationStore {
+
+ protected static Logger logger = Logger.getLogger(AnnotationStore.class);
+
+ protected GraphDatabaseService graphDb;
+
+ public static enum RelationTypes implements RelationshipType {
+ ANNOTATES, CREATED
+ }
+
+ public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/";
+
+ public AnnotationStore(GraphDatabaseService graphDb) {
+ super();
+ this.graphDb = graphDb;
+ }
+
+ public Annotation getAnnotationById(String id) {
+ Index idx = graphDb.index().forNodes("annotations");
+ Node annotNode = idx.get("id", id).getSingle();
+ Annotation annot = createAnnotation(annotNode);
+ return annot;
+ }
+
+ /**
+ * Returns an Annotation object from an annotation-Node.
+ *
+ * @param annotNode
+ * @return
+ */
+ public Annotation createAnnotation(Node annotNode) {
+ Annotation annot = new Annotation();
+ annot.setUri((String) annotNode.getProperty("id", null));
+ annot.setBodyText((String) annotNode.getProperty("bodyText", null));
+ annot.setBodyUri((String) annotNode.getProperty("bodyUri", null));
+ Iterable targets = annotNode.getRelationships(RelationTypes.ANNOTATES);
+ for (Relationship target : targets) {
+ annot.setTargetBaseUri((String) target.getProperty("uri", null));
+ break;
+ }
+ annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null));
+ String ft = (String) annotNode.getProperty("fragmentType", null);
+ if (ft != null) {
+ annot.setFragmentType(FragmentTypes.valueOf(ft));
+ }
+ Iterable creators = annotNode.getRelationships(RelationTypes.CREATED);
+ for (Relationship creator : creators) {
+ annot.setCreatorUri((String) creator.getProperty("uri", null));
+ break;
+ }
+ annot.setCreated((String) annotNode.getProperty("created", null));
+ return annot;
+ }
+
+ /**
+ * Store a new annotation in the store or update an existing one. Returns
+ * the stored annotation.
+ *
+ * @param annot
+ * @return
+ */
+ public Annotation storeAnnotation(Annotation annot) {
+ Transaction tx = graphDb.beginTx();
+ Node annotNode = null;
+ String id = annot.getUri();
+ if (id == null) {
+ id = createRessourceURI("annot:");
+ }
+ annotNode = createAnnotationNode(id);
+
+ try {
+ // Mutating operations go here
+ /*
+ * the annotation body
+ */
+ String bodyText = annot.getBodyText();
+ if (bodyText != null) {
+ annotNode.setProperty("bodyText", bodyText);
+ }
+ String bodyUri = annot.getBodyUri();
+ if (bodyUri != null) {
+ annotNode.setProperty("bodyUri", bodyUri);
+ }
+
+ /*
+ * the annotation target
+ */
+ String targetBaseUri = annot.getTargetBaseUri();
+ if (targetBaseUri != null) {
+ Node target = createTargetNode(targetBaseUri);
+ annotNode.createRelationshipTo(target, RelationTypes.ANNOTATES);
+ }
+
+ /*
+ * The fragment part of the annotation target.
+ */
+ String targetFragment = annot.getTargetFragment();
+ FragmentTypes fragmentType = annot.getFragmentType();
+ if (targetFragment != null) {
+ annotNode.setProperty("targetFragment", targetFragment);
+ annotNode.setProperty("fragmentType", fragmentType.name());
+ }
+
+ /*
+ * The URI of the creator of this annotation.
+ */
+ String creatorUri = annot.getCreatorUri();
+ if (creatorUri != null) {
+ Node creator = createPersonNode(creatorUri, null);
+ creator.createRelationshipTo(annotNode, RelationTypes.CREATED);
+ }
+
+ /*
+ * The creation date of this annotation.
+ */
+ String created = annot.getCreated();
+ if (created != null) {
+ annotNode.setProperty("created", created);
+ }
+
+ tx.success();
+ } finally {
+ tx.finish();
+ }
+
+ // re-read and return annotation
+ Annotation storedAnnot = createAnnotation(annotNode);
+ return storedAnnot;
+ }
+
+ /**
+ * Deletes the annotation with the id.
+ *
+ * @param id
+ */
+ public void deleteById(String id) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Returns all annotations with the given uri and/or user.
+ *
+ * @param uri
+ * @param userUri
+ * @param limit
+ * @param offset
+ * @return
+ */
+ public List searchByUriUser(String targetUri, String userUri, String limit, String offset) {
+ List annotations = new ArrayList();
+ if (targetUri != null) {
+ Index targetIdx = graphDb.index().forNodes("targets");
+ // there should be only one
+ Node target = targetIdx.get("uri", targetUri).getSingle();
+ if (target != null) {
+ Iterable relations = target.getRelationships(RelationTypes.ANNOTATES);
+ for (Relationship relation: relations) {
+ Node ann = relation.getStartNode();
+ if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
+ Annotation annot = createAnnotation(ann);
+ annotations.add(annot);
+ } else {
+ logger.error("ANNOTATES relation does not start with ANNOTATION: "+ann);
+ }
+ }
+ }
+ }
+ if (userUri != null) {
+ Index persIdx = graphDb.index().forNodes("persons");
+ // there should be only one
+ Node person = persIdx.get("uri", userUri).getSingle();
+ if (person != null) {
+ Iterable relations = person.getRelationships(RelationTypes.CREATED);
+ for (Relationship relation: relations) {
+ Node ann = relation.getEndNode();
+ if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
+ Annotation annot = createAnnotation(ann);
+ annotations.add(annot);
+ } else {
+ logger.error("CREATED relation does not end with ANNOTATION: "+ann);
+ }
+ }
+ }
+ }
+ return annotations;
+ }
+
+ protected Node createAnnotationNode(String id) {
+ Index idx = graphDb.index().forNodes("annotations");
+ IndexHits annotations = idx.get("id", id);
+ Node annotation = annotations.getSingle();
+ if (annotation == null) {
+ // does not exist yet
+ Transaction tx = graphDb.beginTx();
+ try {
+ annotation = graphDb.createNode();
+ annotation.setProperty("TYPE", "ANNOTATION");
+ annotation.setProperty("id", id);
+ idx.add(annotation, "id", id);
+ tx.success();
+ } finally {
+ tx.finish();
+ }
+ }
+ return annotation;
+ }
+
+ protected Node createTargetNode(String uri) {
+ Index idx = graphDb.index().forNodes("targets");
+ IndexHits targets = idx.get("uri", uri);
+ Node target = targets.getSingle();
+ if (target == null) {
+ // does not exist yet
+ Transaction tx = graphDb.beginTx();
+ try {
+ target = graphDb.createNode();
+ target.setProperty("TYPE", "TARGET");
+ target.setProperty("uri", uri);
+ idx.add(target, "uri", uri);
+ tx.success();
+ } finally {
+ tx.finish();
+ }
+ }
+ return target;
+ }
+
+ protected Node createPersonNode(String uri, String name) {
+ Index idx = graphDb.index().forNodes("persons");
+ // Person is identified by URI
+ IndexHits persons = idx.get("uri", uri);
+ Node person = persons.getSingle();
+ if (person == null) {
+ // does not exist yet
+ Transaction tx = graphDb.beginTx();
+ try {
+ person = graphDb.createNode();
+ person.setProperty("TYPE", "PERSON");
+ person.setProperty("uri", uri);
+ idx.add(person, "uri", uri);
+ if (name != null) {
+ person.setProperty("name", name);
+ }
+ tx.success();
+ } finally {
+ tx.finish();
+ }
+ }
+ return person;
+ }
+
+ /**
+ * Erzeuge eine urn aus der aktuellen Zeit in millis
+ *
+ * @return
+ */
+ private String createRessourceURI(String prefix) {
+
+ Calendar cal = Calendar.getInstance();
+
+ long time = cal.getTimeInMillis();
+
+ return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);
+
+ }
+
+
+}
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/old/NS.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/mpiwg/itgroup/annotations/old/NS.java Mon Jul 02 22:39:46 2012 +0200
@@ -0,0 +1,15 @@
+package de.mpiwg.itgroup.annotations.old;
+
+public class NS {
+ public static final String MPIWG_PERSONS_URL = "http://entities.mpiwg-berlin.mpg.de/persons/";
+ // public static String
+ // ANNOTATION_TYPE="http://www.w3.org/2000/10/annotationType#";
+ public static final String OAC_NS = "http://www.openannotation.org/ns/";
+ public static final String CNT_NS = "http://www.w3.org/2011/content#";
+ public static final String DCTERMS_NS = "http://www.purl.org/dc/terms/";
+ public static final String RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ public static final String MPIWG_ANNOT_NS = "http://ontologies.mpiwg-berlin.mpg.de/annotations/";
+ public static final String MPIWG_ANNOT_URL = "http://entities.mpiwg-berlin.mpg.de/annotations/";
+ public static final String MPIWG_ANNOT_CTX = "file:///annotations2";
+
+}
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java Fri Jun 29 20:38:27 2012 +0200
+++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java Mon Jul 02 22:39:46 2012 +0200
@@ -5,38 +5,24 @@
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;
+import de.mpiwg.itgroup.annotations.Annotation;
+import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
/**
- * Implements the "annotations" uri of the Annotator API. see
+ * Implements the "annotations" uri of the Annotator API. see
+ *
*
* @author dwinter, casties
*
@@ -68,49 +54,28 @@
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 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;
+ Annotation annots = getAnnotationStore().getAnnotationById(id);
+ if (annots != null) {
+ // there should be only one
+ JSONObject result = createAnnotatorJson(annots);
+ logger.debug("sending:");
+ logger.debug(result);
+ return new JsonRepresentation(result);
+ } else {
+ JSONArray results = new JSONArray();
+ // annotator read request returns a list of annotation objects
+ logger.debug("sending:");
+ logger.debug(results);
+ return new JsonRepresentation(results);
}
}
/**
* 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
+ * 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
*/
@@ -138,22 +103,16 @@
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return null;
}
- if (annot == null || annot.xpointer == null || annot.creator == null) {
+ if (annot == 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.
+ // store Annotation
+ storedAnnot = getAnnotationStore().storeAnnotation(annot);
+ /*
+ * 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);
@@ -161,129 +120,6 @@
}
/**
- * 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("%s", retVal.replace(">", "").replace("<", ""),
- retVal.replace(">", ">").replace("<", "<"));
- 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
@@ -303,10 +139,11 @@
logger.debug("request authenticated=" + authenticated);
if (!authenticated) {
setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
- return null;
+ return null;
}
Annotation annot = null;
+ AnnotationStore store = getAnnotationStore();
try {
JsonRepresentation jrep = new JsonRepresentation(entity);
JSONObject jo = jrep.getJsonObject();
@@ -314,37 +151,27 @@
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 annots = searcher.searchById(id);
- if (annots.size() < 1) {
+ Annotation storedAnnot = store.getAnnotationById(id);
+ if (storedAnnot == null) {
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); */
+ storedAnnot = store.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);
@@ -375,24 +202,13 @@
logger.debug("request authenticated=" + authenticated);
if (!authenticated) {
setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
- return null;
+ 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");
- }
+ // delete annotation
+ getAnnotationStore().deleteById(id);
+ setStatus(Status.SUCCESS_NO_CONTENT);
return null;
}
-
}
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java Fri Jun 29 20:38:27 2012 +0200
+++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java Mon Jul 02 22:39:46 2012 +0200
@@ -13,6 +13,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.servlet.ServletContext;
+
import net.oauth.jsontoken.Checker;
import net.oauth.jsontoken.JsonToken;
import net.oauth.jsontoken.JsonTokenParser;
@@ -25,16 +27,16 @@
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import org.restlet.data.ClientInfo;
import org.restlet.data.Form;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.Options;
import org.restlet.resource.ServerResource;
-import org.restlet.security.User;
-import de.mpiwg.itgroup.annotationManager.Constants.NS;
-import de.mpiwg.itgroup.annotationManager.RDFHandling.Annotation;
+import de.mpiwg.itgroup.annotations.Annotation;
+import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;
+import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
+import de.mpiwg.itgroup.annotations.old.NS;
/**
* Base class for Annotator resource classes.
@@ -44,12 +46,24 @@
*/
public abstract class AnnotatorResourceImpl extends ServerResource {
- protected Logger logger = Logger.getRootLogger();
+ protected static Logger logger = Logger.getLogger(AnnotatorResourceImpl.class);
+
+ private AnnotationStore store;
protected String getAllowedMethodsForHeader() {
return "OPTIONS,GET,POST";
}
+ protected AnnotationStore getAnnotationStore() {
+ if (store == null) {
+ ServletContext sc = (ServletContext) getContext().getServerDispatcher().getContext().getAttributes()
+ .get("org.restlet.ext.servlet.ServletContext");
+ logger.debug("Getting AnnotationStore from Context");
+ store = (AnnotationStore) sc.getAttribute(RestServer.ANNSTORE_KEY);
+ }
+ return store;
+ }
+
public String encodeJsonId(String id) {
try {
return Base64.encodeBase64URLSafeString(id.getBytes("UTF-8"));
@@ -114,7 +128,8 @@
}
/**
- * checks Annotator Auth plugin authentication information from headers. returns userId if successful.
+ * checks Annotator Auth plugin authentication information from headers.
+ * returns userId if successful.
*
* @param entity
* @return
@@ -165,52 +180,46 @@
boolean makeUserObject = true;
JSONObject jo = new JSONObject();
try {
- jo.put("text", annot.text);
- jo.put("uri", annot.url);
+ jo.put("text", annot.getBodyText());
+ jo.put("uri", annot.getTargetBaseUri());
if (makeUserObject) {
// create user object
JSONObject userObject = new JSONObject();
// save creator as uri
- userObject.put("uri", annot.creator);
+ userObject.put("uri", annot.getCreatorUri());
// make short user id
- String userID = annot.creator;
- if (userID.startsWith(NS.MPIWG_PERSONS_URL)) {
- userID = userID.replace(NS.MPIWG_PERSONS_URL, ""); // entferne
+ String userId = annot.getCreatorUri();
+ if (userId != null && userId.startsWith(NS.MPIWG_PERSONS_URL)) {
+ userId = userId.replace(NS.MPIWG_PERSONS_URL, ""); // entferne
// NAMESPACE
}
// save as id
- userObject.put("id", userID);
+ userObject.put("id", userId);
// get full name
RestServer restServer = (RestServer) getApplication();
- String userName = restServer.getUserNameFromLdap(userID);
+ String userName = restServer.getUserNameFromLdap(userId);
userObject.put("name", userName);
// save user object
jo.put("user", userObject);
} else {
// save user as string
- jo.put("user", annot.creator);
+ jo.put("user", annot.getCreatorUri());
}
- List xpointers = new ArrayList();
- if (annot.xpointers == null || annot.xpointers.size() == 0)
- xpointers.add(annot.xpointer);
- else {
- for (String xpointerString : annot.xpointers) {
- xpointers.add(xpointerString);
- }
- }
- if (!xpointers.isEmpty()) {
+ if (annot.getTargetFragment() != null) {
// we only look at the first xpointer
- String xt = getXpointerType(xpointers.get(0));
- if (xt == "range") {
- jo.put("ranges", transformToRanges(xpointers));
- } else if (xt == "area") {
- jo.put("areas", transformToAreas(xpointers));
+ List fragments = new ArrayList();
+ fragments.add(annot.getTargetFragment());
+ FragmentTypes xt = annot.getFragmentType();
+ if (xt == FragmentTypes.XPOINTER) {
+ jo.put("ranges", transformToRanges(fragments));
+ } else if (xt == FragmentTypes.AREA) {
+ jo.put("areas", transformToAreas(fragments));
}
}
// encode Annotation URL (=id) in base64
- String annotUrl = annot.getAnnotationUri();
+ String annotUrl = annot.getUri();
String annotId = encodeJsonId(annotUrl);
jo.put("id", annotId);
return jo;
@@ -221,22 +230,13 @@
return null;
}
- private String getXpointerType(String xpointer) {
- if (xpointer.contains("#xpointer")) {
- return "range";
- } else if (xpointer.contains("#xywh")) {
- return "area";
- }
- return null;
- }
-
private JSONArray transformToRanges(List xpointers) {
JSONArray ja = new JSONArray();
Pattern rg = Pattern
- .compile("#xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)/range-to\\(end-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)\\)");
- Pattern rg1 = Pattern.compile("#xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)");
+ .compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)/range-to\\(end-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)\\)");
+ Pattern rg1 = Pattern.compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)");
try {
for (String xpointer : xpointers) {
@@ -277,7 +277,7 @@
JSONArray ja = new JSONArray();
- Pattern rg = Pattern.compile("#xywh=(\\w*:)([\\d\\.]+),([\\d\\.]+),([\\d\\.]+),([\\d\\.]+)");
+ Pattern rg = Pattern.compile("xywh=(\\w*:)([\\d\\.]+),([\\d\\.]+),([\\d\\.]+),([\\d\\.]+)");
try {
for (String xpointer : xpointers) {
@@ -307,47 +307,76 @@
return ja;
}
+ protected String parseArea(JSONObject area) throws JSONException, UnsupportedEncodingException {
+ String x = area.getString("x");
+ String y = area.getString("y");
+ String width = "0";
+ String height = "0";
+ if (area.has("width")) {
+ width = area.getString("width");
+ height = area.getString("height");
+ }
+ String fragment = URLEncoder.encode(String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height), "utf-8");
+ return fragment;
+ }
+
+ protected String parseRange(JSONObject range) throws JSONException, UnsupportedEncodingException {
+ String start = range.getString("start");
+ String end = range.getString("end");
+ String startOffset = range.getString("startOffset");
+ String endOffset = range.getString("endOffset");
+
+ String fragment = URLEncoder.encode(String.format(
+ "xpointer(start-point(string-range(\"%s\",%s,1))/range-to(end-point(string-range(\"%s\",%s,1))))", start,
+ startOffset, end, endOffset), "utf-8");
+ return fragment;
+ }
+
/**
* creates an Annotation object with data from JSON.
*
- * uses the specification from the annotator project: {@link https ://github.com/okfn/annotator/wiki/Annotation-format}
+ * uses the specification from the annotator project: {@link https
+ * ://github.com/okfn/annotator/wiki/Annotation-format}
*
- * The username will be transformed to an URI if not given already as URI, if not it will set to the MPIWG namespace defined in
+ * The username will be transformed to an URI if not given already as URI,
+ * if not it will set to the MPIWG namespace defined in
* de.mpiwg.itgroup.annotationManager.Constants.NS
*
* @param jo
* @return
* @throws JSONException
+ * @throws UnsupportedEncodingException
*/
- public Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException {
+ public Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException, UnsupportedEncodingException {
return updateAnnotation(new Annotation(), jo, entity);
}
- public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException {
+ public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException,
+ UnsupportedEncodingException {
// annotated uri
- String url = annot.url;
if (jo.has("uri")) {
- url = jo.getString("uri");
+ annot.setTargetBaseUri(jo.getString("uri"));
}
// annotation text
- String text = annot.text;
if (jo.has("text")) {
- text = jo.getString("text");
+ annot.setBodyText(jo.getString("text"));
}
// check authentication
String authUser = checkAuthToken(entity);
if (authUser == null) {
- // try http auth
- User httpUser = getHttpAuthUser(entity);
- if (httpUser == null) {
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return null;
- }
- authUser = httpUser.getIdentifier();
+ /*
+ * // try http auth User httpUser = getHttpAuthUser(entity); if
+ * (httpUser == null) {
+ */
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ /*
+ * } authUser = httpUser.getIdentifier();
+ */
}
// username not required, if no username given authuser will be used
String username = null;
- String userUri = annot.creator;
+ String userUri = annot.getCreatorUri();
if (jo.has("user")) {
if (jo.get("user") instanceof String) {
// user is just a String
@@ -380,64 +409,19 @@
// TODO: should we overwrite the creator?
// create xpointer from the first range/area
- String xpointer = annot.xpointer;
if (jo.has("ranges")) {
JSONObject ranges = jo.getJSONArray("ranges").getJSONObject(0);
- String start = ranges.getString("start");
- String end = ranges.getString("end");
- String startOffset = ranges.getString("startOffset");
- String endOffset = ranges.getString("endOffset");
-
- try {
- xpointer = url
- + "#"
- + URLEncoder.encode(String.format(
- "xpointer(start-point(string-range(\"%s\",%s,1))/range-to(end-point(string-range(\"%s\",%s,1))))",
- start, startOffset, end, endOffset), "utf-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
+ annot.setFragmentType(FragmentTypes.XPOINTER);
+ String fragment = parseRange(ranges);
+ annot.setTargetFragment(fragment);
}
if (jo.has("areas")) {
JSONObject area = jo.getJSONArray("areas").getJSONObject(0);
- String x = area.getString("x");
- String y = area.getString("y");
- String width = "0";
- String height = "0";
- if (area.has("width")) {
- width = area.getString("width");
- height = area.getString("height");
- }
- try {
- xpointer = url + "#" + URLEncoder.encode(String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height), "utf-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
+ annot.setFragmentType(FragmentTypes.AREA);
+ String fragment = parseArea(area);
+ annot.setTargetFragment(fragment);
}
- return new Annotation(xpointer, userUri, annot.time, text, annot.type);
- }
-
- /**
- * returns the logged in User.
- *
- * @param entity
- * @return
- */
- protected User getHttpAuthUser(Representation entity) {
- RestServer restServer = (RestServer) getApplication();
- if (!restServer.authenticate(getRequest(), getResponse())) {
- // Not authenticated
- return null;
- }
-
- ClientInfo ci = getRequest().getClientInfo();
- logger.debug(ci);
- return getRequest().getClientInfo().getUser();
-
+ return annot;
}
}
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorSearch.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorSearch.java Mon Jul 02 22:39:46 2012 +0200
@@ -0,0 +1,87 @@
+/**
+ * Implements the "search" uri of the Annotator API.
+ */
+package de.mpiwg.itgroup.annotations.restlet;
+
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.restlet.data.Form;
+import org.restlet.data.Status;
+import org.restlet.ext.json.JsonRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Get;
+
+import de.mpiwg.itgroup.annotations.Annotation;
+import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
+
+/**
+ * Implements the "search" uri of the Annotator API. see
+ *
+ *
+ * @author casties
+ *
+ */
+public class AnnotatorSearch extends AnnotatorResourceImpl {
+
+ protected String getAllowedMethodsForHeader() {
+ return "OPTIONS,GET";
+ }
+
+ /**
+ * result for JSON content-type. optional search parameters: uri user limit
+ * offset
+ *
+ * @param entity
+ * @return
+ */
+ @Get("json")
+ public Representation doGetJSON(Representation entity) {
+ logger.debug("AnnotatorSearch doGetJSON!");
+ setCorsHeaders();
+ // TODO: what to do with authentication?
+ boolean authenticated = isAuthenticated(entity);
+ logger.debug("request authenticated=" + authenticated);
+
+ Form form = getRequest().getResourceRef().getQueryAsForm();
+ String uri = form.getFirstValue("uri");
+ String user = form.getFirstValue("user");
+
+ String limit = form.getFirstValue("limit");
+ String offset = form.getFirstValue("offset");
+
+ AnnotationStore searcher = getAnnotationStore();
+
+ JSONArray ja;
+
+ List annots = searcher.searchByUriUser(uri, user, limit, offset);
+
+ ja = new JSONArray();
+ for (Annotation annot : annots) {
+ JSONObject jo = createAnnotatorJson(annot);
+ if (jo != null) {
+ ja.put(createAnnotatorJson(annot));
+ } else {
+ setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error");
+ return null;
+ }
+ }
+
+ JSONObject result = new JSONObject();
+ try {
+ result.put("rows", ja);
+ result.put("total", ja.length());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error");
+ return null;
+ }
+
+ logger.debug("sending:");
+ logger.debug(result);
+ return new JsonRepresentation(result);
+ }
+
+}
diff -r 47b53ae385d1 -r 3599b29c393f src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java
--- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java Fri Jun 29 20:38:27 2012 +0200
+++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java Mon Jul 02 22:39:46 2012 +0200
@@ -27,15 +27,12 @@
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.routing.Router;
-import org.restlet.security.ChallengeAuthenticator;
-import scala.sys.process.ProcessBuilderImpl.Dummy;
+import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
public class RestServer extends Application {
- public static Logger logger = Logger.getRootLogger();
-
- private ChallengeAuthenticator authenticator;
+ public static Logger logger = Logger.getLogger(RestServer.class);
/**
* Properties holding consumer keys and secrets
@@ -47,6 +44,12 @@
public static final String GRAPHDB_KEY = "annotationmanager.graphdb";
public String DB_PATH = "WEB-INF/neo4j-annotation-db";
+ private WrappingNeoServerBootstrapper srv;
+ public static final String GRAPHDBSRV_KEY = "annotationmanager.graphdb.srv";
+
+ private AnnotationStore store;
+ public static final String ANNSTORE_KEY = "annotationmanager.store";
+
/**
* constructor
*
@@ -70,10 +73,17 @@
if (dbFn != null) {
logger.debug("opening DB " + dbFn);
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(dbFn);
+ registerShutdownHook(graphDb);
// store in context
sc.setAttribute(GRAPHDB_KEY, graphDb);
- WrappingNeoServerBootstrapper srv = new WrappingNeoServerBootstrapper((AbstractGraphDatabase) graphDb);
+ // AnnotationStore
+ store = new AnnotationStore(graphDb);
+ sc.setAttribute(ANNSTORE_KEY, store);
+ // admin server
+ srv = new WrappingNeoServerBootstrapper((AbstractGraphDatabase) graphDb);
logger.debug("Starting DB admin server...");
+ // store in context
+ sc.setAttribute(GRAPHDBSRV_KEY, srv);
srv.start();
} else {
logger.error("Unable to get resource " + DB_PATH);
@@ -126,7 +136,7 @@
router.attach("/annotator/annotations", AnnotatorAnnotations.class);
router.attach("/annotator/annotations/{id}", AnnotatorAnnotations.class);
- // router.attach("/annotator/search", AnnotatorSearch.class);
+ router.attach("/annotator/search", AnnotatorSearch.class);
// router.attach("",redirector); router.attach("/annotator",
// ExtendedAnnotationInput.class);
@@ -240,4 +250,38 @@
return filename;
}
+ /* (non-Javadoc)
+ * @see org.restlet.Application#stop()
+ */
+ @Override
+ public synchronized void stop() throws Exception {
+ /*
+ * trying to clean up databases, nur sure if this is the right way...
+ */
+ if (srv != null) {
+ logger.debug("Stopping DB admin server...");
+ srv.stop();
+ srv = null;
+ }
+ if (graphDb != null) {
+ logger.debug("Stopping DB...");
+ graphDb.shutdown();
+ graphDb = null;
+ }
+ super.stop();
+ }
+
+ private static void registerShutdownHook(final GraphDatabaseService graphDb) {
+ // Registers a shutdown hook for the Neo4j instance so that it
+ // shuts down nicely when the VM exits (even if you "Ctrl-C" the
+ // running example before it's completed)
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ graphDb.shutdown();
+ }
+ });
+ }
+
+
}