# HG changeset patch # User casties # Date 1341343397 -7200 # Node ID bbf0cc5bee294ae880b76c3464a28826d992a52a # Parent 3599b29c393f1915e53f674f6ff4907d7b39c629 version 0.2 really works now diff -r 3599b29c393f -r bbf0cc5bee29 pom.xml --- a/pom.xml Mon Jul 02 22:39:46 2012 +0200 +++ b/pom.xml Tue Jul 03 21:23:17 2012 +0200 @@ -3,7 +3,7 @@ 4.0.0 de.mpiwg.itgroup.annotations AnnotationManagerN4J - 0.0.1-SNAPSHOT + 0.2.0-SNAPSHOT UTF-8 1.7.1 @@ -21,11 +21,11 @@ false - - maven-restlet - Public online Restlet repository - http://maven.restlet.org - + + maven-restlet + Public online Restlet repository + http://maven.restlet.org + @@ -70,18 +70,19 @@ - - log4j - log4j - 1.2.14 - - - commons-codec - commons-codec - 1.4 - + + log4j + log4j + 1.2.14 + + + commons-codec + commons-codec + 1.4 + + AnnotationManager diff -r 3599b29c393f -r bbf0cc5bee29 src/main/java/de/mpiwg/itgroup/annotations/Annotation.java --- a/src/main/java/de/mpiwg/itgroup/annotations/Annotation.java Mon Jul 02 22:39:46 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/Annotation.java Tue Jul 03 21:23:17 2012 +0200 @@ -52,6 +52,11 @@ protected String creatorUri; /** + * The full name of the creator of this annotation. + */ + protected String creatorName; + + /** * The creation date of this annotation. */ protected String created; @@ -155,6 +160,20 @@ } /** + * @return the creatorName + */ + public String getCreatorName() { + return creatorName; + } + + /** + * @param creatorName the creatorName to set + */ + public void setCreatorName(String creatorName) { + this.creatorName = creatorName; + } + + /** * @return the created */ public String getCreated() { diff -r 3599b29c393f -r bbf0cc5bee29 src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java --- a/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java Mon Jul 02 22:39:46 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java Tue Jul 03 21:23:17 2012 +0200 @@ -8,6 +8,7 @@ import java.util.List; import org.apache.log4j.Logger; +import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; @@ -58,9 +59,12 @@ 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) { + // get annotation target from relation + Iterable targetRels = annotNode.getRelationships(RelationTypes.ANNOTATES); + for (Relationship targetRel : targetRels) { + Node target = targetRel.getEndNode(); annot.setTargetBaseUri((String) target.getProperty("uri", null)); + // just the first one break; } annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null)); @@ -68,9 +72,13 @@ if (ft != null) { annot.setFragmentType(FragmentTypes.valueOf(ft)); } - Iterable creators = annotNode.getRelationships(RelationTypes.CREATED); - for (Relationship creator : creators) { + // get creator form relation + Iterable creatorRels = annotNode.getRelationships(RelationTypes.CREATED); + for (Relationship creatorRel : creatorRels) { + Node creator = creatorRel.getStartNode(); annot.setCreatorUri((String) creator.getProperty("uri", null)); + annot.setCreatorName((String) creator.getProperty("name", null)); + // just the first one break; } annot.setCreated((String) annotNode.getProperty("created", null)); @@ -85,16 +93,18 @@ * @return */ public Annotation storeAnnotation(Annotation annot) { + Node annotNode = null; Transaction tx = graphDb.beginTx(); - Node annotNode = null; - String id = annot.getUri(); - if (id == null) { - id = createRessourceURI("annot:"); - } - annotNode = createAnnotationNode(id); + try { + /* + * create or get the annotation + */ + String id = annot.getUri(); + if (id == null) { + id = createRessourceURI("annot:"); + } + annotNode = getOrCreateAnnotationNode(id); - try { - // Mutating operations go here /* * the annotation body */ @@ -112,8 +122,8 @@ */ String targetBaseUri = annot.getTargetBaseUri(); if (targetBaseUri != null) { - Node target = createTargetNode(targetBaseUri); - annotNode.createRelationshipTo(target, RelationTypes.ANNOTATES); + Node target = getOrCreateTargetNode(targetBaseUri); + getOrCreateRelation(annotNode, RelationTypes.ANNOTATES, target); } /* @@ -127,12 +137,17 @@ } /* + * The name of the creator of this annotation. + */ + String creatorName = annot.getCreatorName(); + + /* * 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); + Node creator = getOrCreatePersonNode(creatorUri, creatorName); + getOrCreateRelation(creator, RelationTypes.CREATED, annotNode); } /* @@ -180,13 +195,13 @@ Node target = targetIdx.get("uri", targetUri).getSingle(); if (target != null) { Iterable relations = target.getRelationships(RelationTypes.ANNOTATES); - for (Relationship relation: relations) { + 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); + logger.error("ANNOTATES relation does not start with ANNOTATION: " + ann); } } } @@ -197,13 +212,13 @@ Node person = persIdx.get("uri", userUri).getSingle(); if (person != null) { Iterable relations = person.getRelationships(RelationTypes.CREATED); - for (Relationship relation: relations) { + 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); + logger.error("CREATED relation does not end with ANNOTATION: " + ann); } } } @@ -211,7 +226,30 @@ return annotations; } - protected Node createAnnotationNode(String id) { + protected Relationship getOrCreateRelation(Node start, RelationshipType type, Node end) { + if (start.hasRelationship()) { + // there are relations + Iterable rels = start.getRelationships(type, Direction.OUTGOING); + for (Relationship rel : rels) { + if (rel.getEndNode().equals(end)) { + // relation exists + return rel; + } + } + } + // create new one + Relationship rel; + Transaction tx = graphDb.beginTx(); + try { + rel = start.createRelationshipTo(end, type); + tx.success(); + } finally { + tx.finish(); + } + return rel; + } + + protected Node getOrCreateAnnotationNode(String id) { Index idx = graphDb.index().forNodes("annotations"); IndexHits annotations = idx.get("id", id); Node annotation = annotations.getSingle(); @@ -231,7 +269,7 @@ return annotation; } - protected Node createTargetNode(String uri) { + protected Node getOrCreateTargetNode(String uri) { Index idx = graphDb.index().forNodes("targets"); IndexHits targets = idx.get("uri", uri); Node target = targets.getSingle(); @@ -251,7 +289,7 @@ return target; } - protected Node createPersonNode(String uri, String name) { + protected Node getOrCreatePersonNode(String uri, String name) { Index idx = graphDb.index().forNodes("persons"); // Person is identified by URI IndexHits persons = idx.get("uri", uri); @@ -290,5 +328,4 @@ } - } diff -r 3599b29c393f -r bbf0cc5bee29 src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java --- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java Mon Jul 02 22:39:46 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java Tue Jul 03 21:23:17 2012 +0200 @@ -8,7 +8,9 @@ import java.net.URLEncoder; import java.security.InvalidKeyException; import java.security.SignatureException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -177,6 +179,7 @@ * @return */ public JSONObject createAnnotatorJson(Annotation annot) { + // return user as a JSON object (otherwise just as string) boolean makeUserObject = true; JSONObject jo = new JSONObject(); try { @@ -197,8 +200,11 @@ // save as id userObject.put("id", userId); // get full name - RestServer restServer = (RestServer) getApplication(); - String userName = restServer.getUserNameFromLdap(userId); + String userName = annot.getCreatorName(); + if (userName == null) { + RestServer restServer = (RestServer) getApplication(); + userName = restServer.getFullNameFromLdap(userId); + } userObject.put("name", userName); // save user object jo.put("user", userObject); @@ -240,7 +246,8 @@ try { for (String xpointer : xpointers) { - String decoded = URLDecoder.decode(xpointer, "utf-8"); + //String decoded = URLDecoder.decode(xpointer, "utf-8"); + String decoded = xpointer; Matcher m = rg.matcher(decoded); if (m.find()) { @@ -265,11 +272,7 @@ } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } - return ja; } @@ -281,7 +284,8 @@ try { for (String xpointer : xpointers) { - String decoded = URLDecoder.decode(xpointer, "utf-8"); + //String decoded = URLDecoder.decode(xpointer, "utf-8"); + String decoded = xpointer; Matcher m = rg.matcher(decoded); if (m.find()) { @@ -299,15 +303,11 @@ } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } - return ja; } - protected String parseArea(JSONObject area) throws JSONException, UnsupportedEncodingException { + protected String parseArea(JSONObject area) throws JSONException { String x = area.getString("x"); String y = area.getString("y"); String width = "0"; @@ -316,24 +316,24 @@ 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"); + String fragment = String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height); return fragment; } - protected String parseRange(JSONObject range) throws JSONException, UnsupportedEncodingException { + protected String parseRange(JSONObject range) throws JSONException { 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( + String fragment = 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"); + startOffset, end, endOffset); return fragment; } /** - * creates an Annotation object with data from JSON. + * Creates an Annotation object with data from JSON. * * uses the specification from the annotator project: {@link https * ://github.com/okfn/annotator/wiki/Annotation-format} @@ -351,9 +351,25 @@ return updateAnnotation(new Annotation(), jo, entity); } + /** + * Updates an Annotation object with data from JSON. + * + * 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 + * de.mpiwg.itgroup.annotationManager.Constants.NS + * + * @param annot + * @param jo + * @return + * @throws JSONException + * @throws UnsupportedEncodingException + */ public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException, UnsupportedEncodingException { - // annotated uri + // target uri if (jo.has("uri")) { annot.setTargetBaseUri(jo.getString("uri")); } @@ -396,9 +412,13 @@ if (username == null) { username = authUser; } - // username should be a URI, if not it will set to the MPIWG namespace - // defined in - // de.mpiwg.itgroup.annotationManager.Constants.NS + // try to get full name + if (username != null) { + RestServer restServer = (RestServer) getApplication(); + String fullName = restServer.getFullNameFromLdap(username); + annot.setCreatorName(fullName); + } + // userUri should be a URI, if not it will set to the MPIWG namespace if (userUri == null) { if (username.startsWith("http")) { userUri = username; @@ -407,6 +427,16 @@ } } // TODO: should we overwrite the creator? + if (annot.getCreatorUri() == null) { + annot.setCreatorUri(userUri); + } + + if (annot.getCreated() == null) { + // set creation date + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + String ct = format.format(Calendar.getInstance().getTime()); + annot.setCreated(ct); + } // create xpointer from the first range/area if (jo.has("ranges")) { diff -r 3599b29c393f -r bbf0cc5bee29 src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java --- a/src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java Mon Jul 02 22:39:46 2012 +0200 +++ b/src/main/java/de/mpiwg/itgroup/annotations/restlet/RestServer.java Tue Jul 03 21:23:17 2012 +0200 @@ -40,9 +40,13 @@ private Properties consumerKeys; public String CONSUMER_KEYS_PATH = "WEB-INF/consumerkeys.property"; + private Properties serverConfig; + public String CONFIG_PROPS_PATH = "WEB-INF/serverconfig.property"; + private GraphDatabaseService graphDb; public static final String GRAPHDB_KEY = "annotationmanager.graphdb"; - public String DB_PATH = "WEB-INF/neo4j-annotation-db"; + public static final String GRAPHDB_PATH_KEY = "annotationmanager.graphdb.path"; + public String graphdbPath = "WEB-INF/neo4j-annotation-db"; private WrappingNeoServerBootstrapper srv; public static final String GRAPHDBSRV_KEY = "annotationmanager.graphdb.srv"; @@ -63,13 +67,33 @@ ServletContext sc = (ServletContext) getContext().getServerDispatcher().getContext().getAttributes() .get("org.restlet.ext.servlet.ServletContext"); if (sc != null) { + /* + * read config from webapp + */ + serverConfig = new Properties(); + InputStream ps1 = getResourceAsStream(sc, CONFIG_PROPS_PATH); + if (ps1 != null) { + logger.debug("loading config from " + CONFIG_PROPS_PATH); + try { + serverConfig.load(ps1); + /* + * read serverconfig options + */ + graphdbPath = serverConfig.getProperty(GRAPHDB_PATH_KEY, graphdbPath); + } catch (IOException e) { + logger.warn("Error loading server config: ", e); + } + logger.debug("config: " + serverConfig); + } else { + logger.error("Unable to get resource " + CONFIG_PROPS_PATH); + } // look for database service in context graphDb = (GraphDatabaseService) sc.getAttribute(GRAPHDB_KEY); if (graphDb == null) { /* * open database */ - String dbFn = getResourcePath(sc, DB_PATH); + String dbFn = getResourcePath(sc, graphdbPath); if (dbFn != null) { logger.debug("opening DB " + dbFn); graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(dbFn); @@ -86,18 +110,18 @@ sc.setAttribute(GRAPHDBSRV_KEY, srv); srv.start(); } else { - logger.error("Unable to get resource " + DB_PATH); + logger.error("Unable to get resource " + dbFn); } } /* * read consumerKeys from webapp */ consumerKeys = new Properties(); - InputStream ps = getResourceAsStream(sc, CONSUMER_KEYS_PATH); - if (ps != null) { + InputStream ps2 = getResourceAsStream(sc, CONSUMER_KEYS_PATH); + if (ps2 != null) { logger.debug("loading consumer keys from " + CONSUMER_KEYS_PATH); try { - consumerKeys.load(ps); + consumerKeys.load(ps2); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -154,7 +178,7 @@ * @param creator * @return */ - public String getUserNameFromLdap(String creator) { + public String getFullNameFromLdap(String creator) { String retString = creator; // falls nichts gefunden wird einfach den // creator zurueckgeben Hashtable env = new Hashtable(); @@ -162,7 +186,7 @@ env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, sp); // TODO: should go into config file - String ldapUrl = "ldap://ldapreplik.mpiwg-berlin.mpg.de/dc=mpiwg-berlin,dc=mpg,dc=de"; + String ldapUrl = "ldap://ldap.mpiwg-berlin.mpg.de/dc=mpiwg-berlin,dc=mpg,dc=de"; env.put(javax.naming.Context.PROVIDER_URL, ldapUrl); DirContext dctx; @@ -174,7 +198,7 @@ return retString; } - String base = "ou=People"; + String base = "ou=people"; SearchControls sc = new SearchControls(); String[] attributeFilter = { "cn", "mail" };