# HG changeset patch
# User casties
# Date 1332154899 -3600
# Node ID 97f68ab3430ffc1534332fb406057f155c5a621a
# Parent 5bb7cc86069c56d40f230af8e967e4c2451d098b
support both read and search api of Annotator.
some cleanup of imports.
diff -r 5bb7cc86069c -r 97f68ab3430f .classpath
--- a/.classpath Wed Mar 14 16:21:45 2012 +0100
+++ b/.classpath Mon Mar 19 12:01:39 2012 +0100
@@ -1,16 +1,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -46,5 +36,7 @@
+
+
diff -r 5bb7cc86069c -r 97f68ab3430f .settings/org.eclipse.wst.common.project.facet.core.xml
--- a/.settings/org.eclipse.wst.common.project.facet.core.xml Wed Mar 14 16:21:45 2012 +0100
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml Mon Mar 19 12:01:39 2012 +0100
@@ -1,6 +1,5 @@
-
diff -r 5bb7cc86069c -r 97f68ab3430f src/de/mpiwg/itgroup/annotationManager/RDFHandling/RDFSearcher.java
--- a/src/de/mpiwg/itgroup/annotationManager/RDFHandling/RDFSearcher.java Wed Mar 14 16:21:45 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/RDFHandling/RDFSearcher.java Mon Mar 19 12:01:39 2012 +0100
@@ -4,14 +4,11 @@
import java.util.List;
import org.apache.log4j.Logger;
-import org.apache.tiles.context.ListAttribute;
import org.openrdf.query.BindingSet;
import org.openrdf.query.TupleQueryResult;
import org.restlet.Context;
import org.restlet.engine.component.ChildContext;
-import sun.security.action.GetBooleanAction;
-
import de.mpiwg.itgroup.annotationManager.Errors.TripleStoreSearchError;
import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert.Annotation;
import de.mpiwg.itgroup.triplestoremanager.exceptions.TripleStoreHandlerException;
diff -r 5bb7cc86069c -r 97f68ab3430f src/de/mpiwg/itgroup/annotationManager/restlet/AddAndReadAnnotations.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/AddAndReadAnnotations.java Mon Mar 19 12:01:39 2012 +0100
@@ -0,0 +1,683 @@
+//TODO: handle XML-Post des Annoteaprotocolls http://www.w3.org/2001/Annotea/User/Protocol.html
+
+package de.mpiwg.itgroup.annotationManager.restlet;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.restlet.Context;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+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.Get;
+import org.restlet.resource.Options;
+import org.restlet.resource.Post;
+import org.restlet.resource.ServerResource;
+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.Convert;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert.Annotation;
+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;
+
+
+public class AddAndReadAnnotations extends ServerResource {
+
+ private Logger logger = Logger.getRootLogger();
+
+
+
+ @Options
+ public void doOptions(Representation entity) {
+ Form responseHeaders = (Form) getResponse().getAttributes().get(
+ "org.restlet.http.headers");
+ if (responseHeaders == null) {
+ responseHeaders = new Form();
+ getResponse().getAttributes().put("org.restlet.http.headers",
+ responseHeaders);
+ }
+ Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers");
+ String origin = requestHeaders.getFirstValue("Origin", true);
+ if (origin == null) {
+ responseHeaders.add("Access-Control-Allow-Origin", "*");
+ } else {
+ responseHeaders.add("Access-Control-Allow-Origin", origin);
+ }
+ String allowHeaders = requestHeaders.getFirstValue("Access-Control-Request-Headers", true);
+ if (allowHeaders != null) {
+ responseHeaders.add("Access-Control-Allow-Headers", allowHeaders);
+ }
+ responseHeaders.add("Access-Control-Allow-Methods", "POST,OPTIONS,GET");
+ responseHeaders.add("Access-Control-Allow-Credentials", "true");
+ responseHeaders.add("Access-Control-Max-Age", "60");
+ }
+
+ @Get("html")
+ public Representation doGetHTML(Representation entity){
+
+ doOptions(entity);
+ 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");
+
+ try {
+ if (uri!=null){
+ uri = URLDecoder.decode(uri, "utf-8");
+ }
+ } catch (UnsupportedEncodingException e1) {
+ e1.printStackTrace();
+ setStatus(Status.CLIENT_ERROR_NOT_ACCEPTABLE);
+ return null;
+ }
+
+//
+ RDFSearcher searcher = new RDFSearcher("file:///annotations"); //TODO should ge into config file
+
+ String retString="";
+ String lineFormat="%s | " +
+ "%s | %s | %s | %s | %s | ";
+ try {
+
+ List annots=searcher.search(uri,user,limit,offset);
+
+ for (Convert.Annotation annot:annots){
+
+
+ RestServer restServer = (RestServer) getApplication();
+ String userName=restServer.getUserNameFromLdap(annot.creator);
+ List xpointer = new ArrayList();
+
+ if (annot.xpointers==null || annot.xpointers.size()==0)
+ retString+=String.format(lineFormat, userName,userName,annot.url,annot.url,annot.time,annot.text,annot.xpointer,annot.xpointer,annot.annotationUri,annot.annotationUri);
+ else {
+ for(String xpointerString:annot.xpointers){
+ retString+=String.format(lineFormat, userName,userName,annot.url,annot.url,annot.time,annot.text,xpointerString,xpointerString,annot.annotationUri,annot.annotationUri);
+ }
+ }
+
+ }
+ } catch (TripleStoreHandlerException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreHandler Error");
+ return null;
+ } catch (TripleStoreSearchError e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreSearch Error");
+ return null;
+ }
+
+ retString+="
";
+
+ logger.debug("sending:");
+ logger.debug(retString);
+ return new StringRepresentation(retString,MediaType.TEXT_HTML);
+ }
+
+ /**
+ * Erzeugt aus einer Annotation, das f�r den Annotator notwendige JSON-Format
+ * @param annot
+ * @return
+ */
+ public JSONObject annot2AnnotatorJSON(Convert.Annotation annot){
+ JSONObject jo = new JSONObject();
+ try {
+ jo.put("text", annot.text);
+ jo.put("uri",annot.url);
+
+ JSONObject userObject= new JSONObject();
+ userObject.put("id",annot.creator);
+
+ RestServer restServer = (RestServer) getApplication();
+
+ String userID= annot.creator;
+ if (userID.startsWith(NS.MPIWG_PERSONS)){
+ userID=userID.replace(NS.MPIWG_PERSONS, ""); //entferne NAMESPACE
+ }
+ String userName=restServer.getUserNameFromLdap(userID);
+ userObject.put("name",userName);
+
+ jo.put("user",userObject);
+
+ List xpointer = new ArrayList();
+
+ if (annot.xpointers==null || annot.xpointers.size()==0)
+ xpointer.add(annot.xpointer);
+ else {
+ for(String xpointerString:annot.xpointers){
+ xpointer.add(xpointerString);
+ }
+ }
+ jo.put("ranges", transformToRanges(xpointer));
+ jo.put("id", annot.annotationUri);
+ return jo;
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Get("json")
+ public Representation doGetJSON(Representation entity){
+
+ doOptions(entity);
+ //TODO: Annotator read request does not use parameters
+ 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");
+
+
+//
+ RDFSearcher searcher = new RDFSearcher("file:///annotations"); //TODO should ge into config file
+
+ JSONArray ja;
+ try {
+
+ List annots=searcher.search(uri,user,limit,offset);
+
+ ja = new JSONArray();
+ for (Convert.Annotation annot:annots){
+// JSONObject jo = new JSONObject();
+// jo.put("text", annot.text);
+// jo.put("uri",annot.url);
+//
+// JSONObject userObject= new JSONObject();
+// userObject.put("id",annot.creator);
+//
+// RestServer restServer = (RestServer) getApplication();
+//
+// String userID= annot.creator;
+// if (userID.startsWith(NS.MPIWG_PERSONS)){
+// userID=userID.replace(NS.MPIWG_PERSONS, ""); //entferne NAMESPACE
+// }
+// String userName=restServer.getUserNameFromLdap(userID);
+// userObject.put("name",userName);
+//
+// jo.put("user",userObject);
+//
+// List xpointer = new ArrayList();
+//
+// if (annot.xpointers==null || annot.xpointers.size()==0)
+// xpointer.add(annot.xpointer);
+// else {
+// for(String xpointerString:annot.xpointers){
+// xpointer.add(xpointerString);
+// }
+// }
+// jo.put("ranges", transformToRanges(xpointer));
+ JSONObject jo = annot2AnnotatorJSON(annot);
+ if (jo!=null){
+ ja.put(annot2AnnotatorJSON(annot));
+ } else {
+ setStatus(Status.SERVER_ERROR_INTERNAL,"JSon Error");
+ return null;
+ }
+ }
+ } catch (TripleStoreHandlerException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreHandler Error");
+ return null;
+ } catch (TripleStoreSearchError e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreSearch Error");
+ return null;
+ }
+
+ // annotator read request returns a list of annotation objects
+ logger.debug("sending:");
+ logger.debug(ja);
+ return new JsonRepresentation(ja);
+ }
+
+ 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\\)\\)\\)");
+
+
+
+ try {
+ for(String xpointer:xpointers){
+ String decoded =URLDecoder.decode(xpointer,"utf-8");
+ Matcher m=rg.matcher(decoded);
+
+ if (m.find()){
+ {
+ JSONObject jo = new JSONObject();
+ jo.put("start", m.group(1));
+ jo.put("startOffset", m.group(2));
+ jo.put("end", m.group(3));
+ jo.put("endOffset", m.group(4));
+ ja.put(jo);
+ }
+ }
+ m=rg1.matcher(xpointer);
+ if (m.find()){
+ JSONObject jo = new JSONObject();
+ jo.put("start", m.group(1));
+ jo.put("startOffset", m.group(2));
+
+ ja.put(jo);
+ }
+
+
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+
+ return ja;
+
+
+
+
+
+ }
+
+
+ /**
+ *
+ * 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) {
+
+ Annotation retVal = doPost(entity);
+
+
+// JSONObject jo;
+// try {
+// jo = new JSONObject("{\"annotUrl\":\"" + retVal + "\"}");
+// } catch (JSONException e) {
+// setStatus(Status.SERVER_ERROR_INTERNAL);
+// return null;
+// }
+
+ if (retVal==null)
+ return null;
+ JSONObject jo = annot2AnnotatorJSON(retVal);
+ JsonRepresentation retRep = new JsonRepresentation(jo);
+ return retRep;
+ }
+
+ @Post("html")
+ public Representation doPostHtml(Representation entity) {
+ Annotation retValAnnot = doPost(entity);
+ if (retValAnnot == null) {
+ return null;
+ }
+
+
+ String retVal=retValAnnot.annotationUri;
+ 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;
+ }
+
+ public Convert.Annotation doPost(Representation entity) {
+
+ doOptions(entity);
+ Convert.Annotation annot;
+ // versuche basic authentifizierung und hole den Benutzer von dort.
+
+ // User authUser;= handleBasicAuthentification(entity);
+
+ if (entity.getMediaType().equals(MediaType.APPLICATION_JSON)) {
+
+ JsonRepresentation jrep;
+ try {
+ jrep = new JsonRepresentation(entity);
+ } catch (IOException e1) {
+ setStatus(Status.SERVER_ERROR_INTERNAL);
+ return null;
+ }
+
+ // try {
+ // logger.debug(jrep.getText());
+ // } catch (IOException e1) {
+ // // TODO Auto-generated catch block
+ // e1.printStackTrace();
+ // }
+ //
+
+ try {
+ JSONObject jo = jrep.getJsonObject();
+ if(jo==null){
+ setStatus(Status.SERVER_ERROR_INTERNAL);
+ return null;
+ }
+
+ String mode=null;
+ if(jo.has("mode")){
+ mode = jo.getString("mode"); // hole modus
+ }
+ if (mode==null || mode.equals(""))
+ mode="annotea"; // default mode (annotea) TODO make this configurable
+
+ if (mode.equals("annotator") ) { // annotator format
+ annot = handleAnnotatorSchema(jo, entity);
+ logger.debug("storing annotator object");
+ logger.debug(jo);
+ } else if (mode.equals("annotea")){
+ annot = handleAnnotea(jo, entity);
+ } else {
+ setStatus(Status.CLIENT_ERROR_BAD_REQUEST,"mode "+mode+"not supported!");
+ return null;
+ }
+
+ } catch (JSONException e) {
+ setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+ return null;
+ }
+
+ } else if (entity.getMediaType().equals(MediaType.APPLICATION_WWW_FORM)) {
+ annot = handleForm(entity);
+
+ } else {
+ setStatus(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE);
+
+ return null;
+ }
+
+ if (annot==null){
+ return null;
+ }
+ if (annot.xpointer == null || annot.creator == null) {
+ setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+
+ return null;
+ }
+
+
+
+ try {
+ return new Convert("file:///annotations").storeAnnotation(annot);
+ } catch (TripleStoreStoreError e) {
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error");
+ return null;
+ }
+ }
+
+
+ /**
+ *
+ * @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 Convert.Annotation handleForm(Representation entity) {
+ Convert.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 = handleBasicAuthentification(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+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 Convert.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 Convert.Annotation(xpointer, username, null, text,
+ type, url);
+ return annot;
+ }
+
+ @Post
+ public Representation doPostHtml2(Representation entity) {
+ return doPostHtml(entity);
+ }
+
+ private User handleBasicAuthentification(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();
+
+ }
+
+ /**
+ * using a minimal annotation format based on the annotea specification
+ *
+ * @param jo
+ * must contain xpointer, text,url,type and can contain a
+ * username, if not the username form the authentification will
+ * be used.
+ * @param authUser
+ * user object
+ * 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
+
+ * @return
+ * @throws JSONException
+ */
+ public Annotation handleAnnotea(JSONObject jo, Representation entity)
+ throws JSONException {
+
+ User authUser = handleBasicAuthentification(entity);
+ String username = jo.getString("username"); // not required, if no
+ // username given authuser
+ // will be used.
+ String xpointer = jo.getString("xpointer");
+ String text = null;
+ if (jo.has("text"))
+ text = jo.getString("text");
+
+ String url = null;
+ if (jo.has("url"))
+ url = jo.getString("url");
+
+ String type = null;
+ if (jo.has("type"))
+ type = jo.getString("type");
+
+ if (username == null)
+ 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
+ if (!username.startsWith("http"))
+ username=NS.MPIWG_PERSONS+username;
+
+ return new Convert.Annotation(xpointer, username, null, text, type, url);
+ }
+
+ /**
+ * uses the specification from the annotator project.
+ *
+ * @see{https://github.com/okfn/annotator/wiki/Annotation-format} The user
+ * object must
+ * contain an
+ * id and
+ * password or
+ * basic
+ * authentification
+ * is used.
+ * 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
+ * @param authUser
+ * @return
+ * @throws JSONException
+ */
+ public Convert.Annotation handleAnnotatorSchema(JSONObject jo,
+ Representation entity) throws JSONException {
+ Convert.Annotation annot;
+ String url = jo.getString("uri");
+ String text = jo.getString("text");
+
+ String username = null;
+ if (jo.has("user")) { // not required, if no username given authuser
+ // will be used otherwise username and password
+ // has to be submitted
+ JSONObject user = jo.getJSONObject("user");
+ if (user.has("id")) {
+ username = user.getString("id");
+ if(!user.has("password")){
+ User authUser = handleBasicAuthentification(entity);
+ if (authUser==null){
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ }
+ username = authUser.getIdentifier();
+ } else {
+ String password = user.getString("password");
+ if (!((RestServer) getApplication()).authenticate(username,
+ password, getRequest())) {
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ }
+ }
+ }
+
+ } else {
+ User authUser = handleBasicAuthentification(entity);
+ if (authUser == null) {
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ }
+ username = authUser.getIdentifier();
+ }
+
+ String 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;
+ }
+ } else {
+ xpointer = url;
+ }
+
+ //username should be a URI, if not it will set to the MPIWG namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
+ if (!username.startsWith("http"))
+ username=NS.MPIWG_PERSONS+username;
+
+ return new Convert.Annotation(xpointer, username, null, text, null);
+ }
+
+}
diff -r 5bb7cc86069c -r 97f68ab3430f src/de/mpiwg/itgroup/annotationManager/restlet/AddAndSearchAnnotations.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/AddAndSearchAnnotations.java Wed Mar 14 16:21:45 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,683 +0,0 @@
-//TODO: handle XML-Post des Annoteaprotocolls http://www.w3.org/2001/Annotea/User/Protocol.html
-
-package de.mpiwg.itgroup.annotationManager.restlet;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.log4j.Logger;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.restlet.Context;
-import org.restlet.data.ClientInfo;
-import org.restlet.data.Form;
-import org.restlet.data.MediaType;
-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.Get;
-import org.restlet.resource.Options;
-import org.restlet.resource.Post;
-import org.restlet.resource.ServerResource;
-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.Convert;
-import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert.Annotation;
-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;
-
-
-public class AddAndSearchAnnotations extends ServerResource {
-
- private Logger logger = Logger.getRootLogger();
-
-
-
- @Options
- public void doOptions(Representation entity) {
- Form responseHeaders = (Form) getResponse().getAttributes().get(
- "org.restlet.http.headers");
- if (responseHeaders == null) {
- responseHeaders = new Form();
- getResponse().getAttributes().put("org.restlet.http.headers",
- responseHeaders);
- }
- responseHeaders.add("Access-Control-Allow-Origin", "*");
- responseHeaders.add("Access-Control-Allow-Methods", "POST,OPTIONS,GET");
- responseHeaders.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Annotator-Account-Id, X-Annotator-User-Id, X-Annotator-Auth-Token-Valid-Until, X-Annotator-Auth-Token");
- responseHeaders.add("Access-Control-Allow-Credentials", "false");
- responseHeaders.add("Access-Control-Max-Age", "60");
- }
-
- @Get("html")
- public Representation doGetHTML(Representation entity){
-
- doOptions(entity);
- 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");
-
- try {
- if (uri!=null){
- uri = URLDecoder.decode(uri, "utf-8");
- }
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- setStatus(Status.CLIENT_ERROR_NOT_ACCEPTABLE);
- return null;
- }
-
-//
- RDFSearcher searcher = new RDFSearcher("file:///annotations"); //TODO should ge into config file
-
- String retString="";
- String lineFormat="%s | " +
- "%s | %s | %s | %s | %s | ";
- try {
-
- List annots=searcher.search(uri,user,limit,offset);
-
- for (Convert.Annotation annot:annots){
-
-
- RestServer restServer = (RestServer) getApplication();
- String userName=restServer.getUserNameFromLdap(annot.creator);
- List xpointer = new ArrayList();
-
- if (annot.xpointers==null || annot.xpointers.size()==0)
- retString+=String.format(lineFormat, userName,userName,annot.url,annot.url,annot.time,annot.text,annot.xpointer,annot.xpointer,annot.annotationUri,annot.annotationUri);
- else {
- for(String xpointerString:annot.xpointers){
- retString+=String.format(lineFormat, userName,userName,annot.url,annot.url,annot.time,annot.text,xpointerString,xpointerString,annot.annotationUri,annot.annotationUri);
- }
- }
-
- }
- } catch (TripleStoreHandlerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreHandler Error");
- return null;
- } catch (TripleStoreSearchError e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreSearch Error");
- return null;
- }
-
- retString+="
";
-
- logger.debug("sending:");
- logger.debug(retString);
- return new StringRepresentation(retString,MediaType.TEXT_HTML);
- }
-
- /**
- * Erzeugt aus einer Annotation, das fŸr den Annotator notwendige JSON-Format
- * @param annot
- * @return
- */
- public JSONObject annot2AnnotatorJSON(Convert.Annotation annot){
- JSONObject jo = new JSONObject();
- try {
- jo.put("text", annot.text);
- jo.put("uri",annot.url);
-
- JSONObject userObject= new JSONObject();
- userObject.put("id",annot.creator);
-
- RestServer restServer = (RestServer) getApplication();
-
- String userID= annot.creator;
- if (userID.startsWith(NS.MPIWG_PERSONS)){
- userID=userID.replace(NS.MPIWG_PERSONS, ""); //entferne NAMESPACE
- }
- String userName=restServer.getUserNameFromLdap(userID);
- userObject.put("name",userName);
-
- jo.put("user",userObject);
-
- List xpointer = new ArrayList();
-
- if (annot.xpointers==null || annot.xpointers.size()==0)
- xpointer.add(annot.xpointer);
- else {
- for(String xpointerString:annot.xpointers){
- xpointer.add(xpointerString);
- }
- }
- jo.put("ranges", transformToRanges(xpointer));
- jo.put("id", annot.annotationUri);
- return jo;
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return null;
- }
- }
-
- @Get("json")
- public Representation doGetJSON(Representation entity){
-
- doOptions(entity);
- 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");
-
-
-//
- RDFSearcher searcher = new RDFSearcher("file:///annotations"); //TODO should ge into config file
-
- JSONArray ja;
- try {
-
- List annots=searcher.search(uri,user,limit,offset);
-
- ja = new JSONArray();
- for (Convert.Annotation annot:annots){
-// JSONObject jo = new JSONObject();
-// jo.put("text", annot.text);
-// jo.put("uri",annot.url);
-//
-// JSONObject userObject= new JSONObject();
-// userObject.put("id",annot.creator);
-//
-// RestServer restServer = (RestServer) getApplication();
-//
-// String userID= annot.creator;
-// if (userID.startsWith(NS.MPIWG_PERSONS)){
-// userID=userID.replace(NS.MPIWG_PERSONS, ""); //entferne NAMESPACE
-// }
-// String userName=restServer.getUserNameFromLdap(userID);
-// userObject.put("name",userName);
-//
-// jo.put("user",userObject);
-//
-// List xpointer = new ArrayList();
-//
-// if (annot.xpointers==null || annot.xpointers.size()==0)
-// xpointer.add(annot.xpointer);
-// else {
-// for(String xpointerString:annot.xpointers){
-// xpointer.add(xpointerString);
-// }
-// }
-// jo.put("ranges", transformToRanges(xpointer));
- JSONObject jo = annot2AnnotatorJSON(annot);
- if (jo!=null){
- ja.put(annot2AnnotatorJSON(annot));
- } else {
- setStatus(Status.SERVER_ERROR_INTERNAL,"JSon Error");
- return null;
- }
- }
- } catch (TripleStoreHandlerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreHandler Error");
- return null;
- } catch (TripleStoreSearchError e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreSearch Error");
- return null;
- }
-
- JSONObject retObject = new JSONObject();
- try {
- retObject.put("rows",ja);
- retObject.put("total",ja.length());
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL,"JSon Error");
- return null;
- }
-
- logger.debug("sending:");
- logger.debug(retObject);
- return new JsonRepresentation(retObject);
- }
-
- 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\\)\\)\\)");
-
-
-
- try {
- for(String xpointer:xpointers){
- String decoded =URLDecoder.decode(xpointer,"utf-8");
- Matcher m=rg.matcher(decoded);
-
- if (m.find()){
- {
- JSONObject jo = new JSONObject();
- jo.put("start", m.group(1));
- jo.put("startOffset", m.group(2));
- jo.put("end", m.group(3));
- jo.put("endOffset", m.group(4));
- ja.put(jo);
- }
- }
- m=rg1.matcher(xpointer);
- if (m.find()){
- JSONObject jo = new JSONObject();
- jo.put("start", m.group(1));
- jo.put("startOffset", m.group(2));
-
- ja.put(jo);
- }
-
-
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
-
- return ja;
-
-
-
-
-
- }
-
-
- /**
- *
- * 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) {
-
- Annotation retVal = doPost(entity);
-
-
-// JSONObject jo;
-// try {
-// jo = new JSONObject("{\"annotUrl\":\"" + retVal + "\"}");
-// } catch (JSONException e) {
-// setStatus(Status.SERVER_ERROR_INTERNAL);
-// return null;
-// }
-
- if (retVal==null)
- return null;
- JSONObject jo = annot2AnnotatorJSON(retVal);
- JsonRepresentation retRep = new JsonRepresentation(jo);
- return retRep;
- }
-
- @Post("html")
- public Representation doPostHtml(Representation entity) {
- Annotation retValAnnot = doPost(entity);
- if (retValAnnot == null) {
- return null;
- }
-
-
- String retVal=retValAnnot.annotationUri;
- 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;
- }
-
- public Convert.Annotation doPost(Representation entity) {
-
- doOptions(entity);
- Convert.Annotation annot;
- // versuche basic authentifizierung und hole den Benutzer von dort.
-
- // User authUser;= handleBasicAuthentification(entity);
-
- if (entity.getMediaType().equals(MediaType.APPLICATION_JSON)) {
-
- JsonRepresentation jrep;
- try {
- jrep = new JsonRepresentation(entity);
- } catch (IOException e1) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
-
- // try {
- // logger.debug(jrep.getText());
- // } catch (IOException e1) {
- // // TODO Auto-generated catch block
- // e1.printStackTrace();
- // }
- //
-
- try {
- JSONObject jo = jrep.getJsonObject();
- if(jo==null){
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
-
- String mode=null;
- if(jo.has("mode")){
- mode = jo.getString("mode"); // hole modus
- }
- if (mode==null || mode.equals(""))
- mode="annotea"; // default mode (annotea) TODO make this configurable
-
- if (mode.equals("annotator") ) { // annotator format
- annot = handleAnnotatorSchema(jo, entity);
- logger.debug("storing annotator object");
- logger.debug(jo);
- } else if (mode.equals("annotea")){
- annot = handleAnnotea(jo, entity);
- } else {
- setStatus(Status.CLIENT_ERROR_BAD_REQUEST,"mode "+mode+"not supported!");
- return null;
- }
-
- } catch (JSONException e) {
- setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
- return null;
- }
-
- } else if (entity.getMediaType().equals(MediaType.APPLICATION_WWW_FORM)) {
- annot = handleForm(entity);
-
- } else {
- setStatus(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE);
-
- return null;
- }
-
- if (annot==null){
- return null;
- }
- if (annot.xpointer == null || annot.creator == null) {
- setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
-
- return null;
- }
-
-
-
- try {
- return new Convert("file:///annotations").storeAnnotation(annot);
- } catch (TripleStoreStoreError e) {
- e.printStackTrace();
- setStatus(Status.SERVER_ERROR_INTERNAL, "TripleStore Error");
- return null;
- }
- }
-
-
- /**
- *
- * @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 Convert.Annotation handleForm(Representation entity) {
- Convert.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 = handleBasicAuthentification(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+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 Convert.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 Convert.Annotation(xpointer, username, null, text,
- type, url);
- return annot;
- }
-
- @Post
- public Representation doPostHtml2(Representation entity) {
- return doPostHtml(entity);
- }
-
- private User handleBasicAuthentification(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();
-
- }
-
- /**
- * using a minimal annotation format based on the annotea specification
- *
- * @param jo
- * must contain xpointer, text,url,type and can contain a
- * username, if not the username form the authentification will
- * be used.
- * @param authUser
- * user object
- * 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
-
- * @return
- * @throws JSONException
- */
- public Annotation handleAnnotea(JSONObject jo, Representation entity)
- throws JSONException {
-
- User authUser = handleBasicAuthentification(entity);
- String username = jo.getString("username"); // not required, if no
- // username given authuser
- // will be used.
- String xpointer = jo.getString("xpointer");
- String text = null;
- if (jo.has("text"))
- text = jo.getString("text");
-
- String url = null;
- if (jo.has("url"))
- url = jo.getString("url");
-
- String type = null;
- if (jo.has("type"))
- type = jo.getString("type");
-
- if (username == null)
- 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
- if (!username.startsWith("http"))
- username=NS.MPIWG_PERSONS+username;
-
- return new Convert.Annotation(xpointer, username, null, text, type, url);
- }
-
- /**
- * uses the specification from the annotator project.
- *
- * @see{https://github.com/okfn/annotator/wiki/Annotation-format} The user
- * object must
- * contain an
- * id and
- * password or
- * basic
- * authentification
- * is used.
- * 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
- * @param authUser
- * @return
- * @throws JSONException
- */
- public Convert.Annotation handleAnnotatorSchema(JSONObject jo,
- Representation entity) throws JSONException {
- Convert.Annotation annot;
- String url = jo.getString("uri");
- String text = jo.getString("text");
-
- String username = null;
- if (jo.has("user")) { // not required, if no username given authuser
- // will be used otherwise username and password
- // has to be submitted
- JSONObject user = jo.getJSONObject("user");
- if (user.has("id")) {
- username = user.getString("id");
- if(!user.has("password")){
- User authUser = handleBasicAuthentification(entity);
- if (authUser==null){
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return null;
- }
- username = authUser.getIdentifier();
- } else {
- String password = user.getString("password");
- if (!((RestServer) getApplication()).authenticate(username,
- password, getRequest())) {
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return null;
- }
- }
- }
-
- } else {
- User authUser = handleBasicAuthentification(entity);
- if (authUser == null) {
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return null;
- }
- username = authUser.getIdentifier();
- }
-
- String 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;
- }
- } else {
- xpointer = url;
- }
-
- //username should be a URI, if not it will set to the MPIWG namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
- if (!username.startsWith("http"))
- username=NS.MPIWG_PERSONS+username;
-
- return new Convert.Annotation(xpointer, username, null, text, null);
- }
-
-}
diff -r 5bb7cc86069c -r 97f68ab3430f src/de/mpiwg/itgroup/annotationManager/restlet/ExtendedAnnotationInput.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/ExtendedAnnotationInput.java Wed Mar 14 16:21:45 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/ExtendedAnnotationInput.java Mon Mar 19 12:01:39 2012 +0100
@@ -32,10 +32,11 @@
responseHeaders = new Form();
getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
}
+ // TODO: better to answer Allow-Origin with the requested Origin
responseHeaders.add("Access-Control-Allow-Origin", "*");
responseHeaders.add("Access-Control-Allow-Methods", "POST,OPTIONS,GET");
responseHeaders.add("Access-Control-Allow-Headers", "Content-Type");
- responseHeaders.add("Access-Control-Allow-Credentials", "false");
+ responseHeaders.add("Access-Control-Allow-Credentials", "true");
responseHeaders.add("Access-Control-Max-Age", "60");
}
diff -r 5bb7cc86069c -r 97f68ab3430f src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java Wed Mar 14 16:21:45 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java Mon Mar 19 12:01:39 2012 +0100
@@ -89,7 +89,7 @@
}
/**
- * Konfiguration fŸr den Authentificator in Jaas. Pfad zum JAAS-Konfigurationsfile liegt im Context-Parameter
+ * Konfiguration f�r den Authentificator in Jaas. Pfad zum JAAS-Konfigurationsfile liegt im Context-Parameter
* "de.mpiwg.itgroup.annotationManager.jaas.configFilePath".
* @return
*/
@@ -133,8 +133,8 @@
Router router = new Router(getContext());
- router.attach("/annotations",AddAndSearchAnnotations.class);
- router.attach("/search",AddAndSearchAnnotations.class); // annotator api askes for different uris for search and adding
+ router.attach("/annotations",AddAndReadAnnotations.class);
+ router.attach("/search",SearchAnnotations.class); // annotator api askes for different uris for search and adding
router.attach("/dummy",Dummy.class);
//router.attach("",redirector);
diff -r 5bb7cc86069c -r 97f68ab3430f src/de/mpiwg/itgroup/annotationManager/restlet/SearchAnnotations.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/SearchAnnotations.java Mon Mar 19 12:01:39 2012 +0100
@@ -0,0 +1,542 @@
+//TODO: handle XML-Post des Annoteaprotocolls http://www.w3.org/2001/Annotea/User/Protocol.html
+
+package de.mpiwg.itgroup.annotationManager.restlet;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.restlet.Context;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+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.Get;
+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.Errors.TripleStoreSearchError;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert.Annotation;
+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;
+
+
+public class SearchAnnotations extends ServerResource {
+
+ private Logger logger = Logger.getRootLogger();
+
+
+
+ @Options
+ public void doOptions(Representation entity) {
+ Form responseHeaders = (Form) getResponse().getAttributes().get(
+ "org.restlet.http.headers");
+ if (responseHeaders == null) {
+ responseHeaders = new Form();
+ getResponse().getAttributes().put("org.restlet.http.headers",
+ responseHeaders);
+ }
+ Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers");
+ String origin = requestHeaders.getFirstValue("Origin", true);
+ if (origin == null) {
+ responseHeaders.add("Access-Control-Allow-Origin", "*");
+ } else {
+ responseHeaders.add("Access-Control-Allow-Origin", origin);
+ }
+ responseHeaders.add("Access-Control-Allow-Methods", "OPTIONS,GET");
+ String allowHeaders = requestHeaders.getFirstValue("Access-Control-Request-Headers", true);
+ if (allowHeaders != null) {
+ responseHeaders.add("Access-Control-Allow-Headers", allowHeaders);
+ }
+ //responseHeaders.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Annotator-Account-Id, X-Annotator-User-Id, X-Annotator-Auth-Token-Valid-Until, X-Annotator-Auth-Token");
+ responseHeaders.add("Access-Control-Allow-Credentials", "true");
+ responseHeaders.add("Access-Control-Max-Age", "60");
+ }
+
+ @Get("html")
+ public Representation doGetHTML(Representation entity){
+
+ doOptions(entity);
+ 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");
+
+ try {
+ if (uri!=null){
+ uri = URLDecoder.decode(uri, "utf-8");
+ }
+ } catch (UnsupportedEncodingException e1) {
+ e1.printStackTrace();
+ setStatus(Status.CLIENT_ERROR_NOT_ACCEPTABLE);
+ return null;
+ }
+
+ RDFSearcher searcher = new RDFSearcher("file:///annotations"); //TODO should ge into config file
+
+ String retString="";
+ String lineFormat="%s | " +
+ "%s | %s | %s | %s | %s | ";
+ try {
+
+ List annots=searcher.search(uri,user,limit,offset);
+
+ for (Convert.Annotation annot:annots){
+
+
+ RestServer restServer = (RestServer) getApplication();
+ String userName=restServer.getUserNameFromLdap(annot.creator);
+ List xpointer = new ArrayList();
+
+ if (annot.xpointers==null || annot.xpointers.size()==0)
+ retString+=String.format(lineFormat, userName,userName,annot.url,annot.url,annot.time,annot.text,annot.xpointer,annot.xpointer,annot.annotationUri,annot.annotationUri);
+ else {
+ for(String xpointerString:annot.xpointers){
+ retString+=String.format(lineFormat, userName,userName,annot.url,annot.url,annot.time,annot.text,xpointerString,xpointerString,annot.annotationUri,annot.annotationUri);
+ }
+ }
+
+ }
+ } catch (TripleStoreHandlerException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreHandler Error");
+ return null;
+ } catch (TripleStoreSearchError e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreSearch Error");
+ return null;
+ }
+
+ retString+="
";
+
+ logger.debug("sending:");
+ logger.debug(retString);
+ return new StringRepresentation(retString,MediaType.TEXT_HTML);
+ }
+
+ /**
+ * Erzeugt aus einer Annotation, das f�r den Annotator notwendige JSON-Format
+ * @param annot
+ * @return
+ */
+ public JSONObject annot2AnnotatorJSON(Convert.Annotation annot){
+ JSONObject jo = new JSONObject();
+ try {
+ jo.put("text", annot.text);
+ jo.put("uri",annot.url);
+
+ JSONObject userObject= new JSONObject();
+ userObject.put("id",annot.creator);
+
+ RestServer restServer = (RestServer) getApplication();
+
+ String userID= annot.creator;
+ if (userID.startsWith(NS.MPIWG_PERSONS)){
+ userID=userID.replace(NS.MPIWG_PERSONS, ""); //entferne NAMESPACE
+ }
+ String userName=restServer.getUserNameFromLdap(userID);
+ userObject.put("name",userName);
+
+ jo.put("user",userObject);
+
+ List xpointer = new ArrayList();
+
+ if (annot.xpointers==null || annot.xpointers.size()==0)
+ xpointer.add(annot.xpointer);
+ else {
+ for(String xpointerString:annot.xpointers){
+ xpointer.add(xpointerString);
+ }
+ }
+ jo.put("ranges", transformToRanges(xpointer));
+ jo.put("id", annot.annotationUri);
+ return jo;
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Get("json")
+ public Representation doGetJSON(Representation entity){
+
+ doOptions(entity);
+ 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");
+
+
+//
+ RDFSearcher searcher = new RDFSearcher("file:///annotations"); //TODO should ge into config file
+
+ JSONArray ja;
+ try {
+
+ List annots=searcher.search(uri,user,limit,offset);
+
+ ja = new JSONArray();
+ for (Convert.Annotation annot:annots){
+// JSONObject jo = new JSONObject();
+// jo.put("text", annot.text);
+// jo.put("uri",annot.url);
+//
+// JSONObject userObject= new JSONObject();
+// userObject.put("id",annot.creator);
+//
+// RestServer restServer = (RestServer) getApplication();
+//
+// String userID= annot.creator;
+// if (userID.startsWith(NS.MPIWG_PERSONS)){
+// userID=userID.replace(NS.MPIWG_PERSONS, ""); //entferne NAMESPACE
+// }
+// String userName=restServer.getUserNameFromLdap(userID);
+// userObject.put("name",userName);
+//
+// jo.put("user",userObject);
+//
+// List xpointer = new ArrayList();
+//
+// if (annot.xpointers==null || annot.xpointers.size()==0)
+// xpointer.add(annot.xpointer);
+// else {
+// for(String xpointerString:annot.xpointers){
+// xpointer.add(xpointerString);
+// }
+// }
+// jo.put("ranges", transformToRanges(xpointer));
+ JSONObject jo = annot2AnnotatorJSON(annot);
+ if (jo!=null){
+ ja.put(annot2AnnotatorJSON(annot));
+ } else {
+ setStatus(Status.SERVER_ERROR_INTERNAL,"JSon Error");
+ return null;
+ }
+ }
+ } catch (TripleStoreHandlerException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreHandler Error");
+ return null;
+ } catch (TripleStoreSearchError e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"TripleStoreSearch Error");
+ return null;
+ }
+
+ JSONObject result = new JSONObject();
+ try {
+ result.put("rows",ja);
+ result.put("total",ja.length());
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ setStatus(Status.SERVER_ERROR_INTERNAL,"JSon Error");
+ return null;
+ }
+
+ logger.debug("sending:");
+ logger.debug(result);
+ return new JsonRepresentation(result);
+ }
+
+ 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\\)\\)\\)");
+
+
+
+ try {
+ for(String xpointer:xpointers){
+ String decoded =URLDecoder.decode(xpointer,"utf-8");
+ Matcher m=rg.matcher(decoded);
+
+ if (m.find()){
+ {
+ JSONObject jo = new JSONObject();
+ jo.put("start", m.group(1));
+ jo.put("startOffset", m.group(2));
+ jo.put("end", m.group(3));
+ jo.put("endOffset", m.group(4));
+ ja.put(jo);
+ }
+ }
+ m=rg1.matcher(xpointer);
+ if (m.find()){
+ JSONObject jo = new JSONObject();
+ jo.put("start", m.group(1));
+ jo.put("startOffset", m.group(2));
+
+ ja.put(jo);
+ }
+
+
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+
+ return ja;
+ }
+
+
+
+ /**
+ *
+ * @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 Convert.Annotation handleForm(Representation entity) {
+ Convert.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 = handleBasicAuthentification(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+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 Convert.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 Convert.Annotation(xpointer, username, null, text,
+ type, url);
+ return annot;
+ }
+
+ private User handleBasicAuthentification(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();
+
+ }
+
+ /**
+ * using a minimal annotation format based on the annotea specification
+ *
+ * @param jo
+ * must contain xpointer, text,url,type and can contain a
+ * username, if not the username form the authentification will
+ * be used.
+ * @param authUser
+ * user object
+ * 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
+
+ * @return
+ * @throws JSONException
+ */
+ public Annotation handleAnnotea(JSONObject jo, Representation entity)
+ throws JSONException {
+
+ User authUser = handleBasicAuthentification(entity);
+ String username = jo.getString("username"); // not required, if no
+ // username given authuser
+ // will be used.
+ String xpointer = jo.getString("xpointer");
+ String text = null;
+ if (jo.has("text"))
+ text = jo.getString("text");
+
+ String url = null;
+ if (jo.has("url"))
+ url = jo.getString("url");
+
+ String type = null;
+ if (jo.has("type"))
+ type = jo.getString("type");
+
+ if (username == null)
+ 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
+ if (!username.startsWith("http"))
+ username=NS.MPIWG_PERSONS+username;
+
+ return new Convert.Annotation(xpointer, username, null, text, type, url);
+ }
+
+ /**
+ * uses the specification from the annotator project.
+ *
+ * @see{https://github.com/okfn/annotator/wiki/Annotation-format} The user
+ * object must
+ * contain an
+ * id and
+ * password or
+ * basic
+ * authentification
+ * is used.
+ * 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
+ * @param authUser
+ * @return
+ * @throws JSONException
+ */
+ public Convert.Annotation handleAnnotatorSchema(JSONObject jo,
+ Representation entity) throws JSONException {
+ Convert.Annotation annot;
+ String url = jo.getString("uri");
+ String text = jo.getString("text");
+
+ String username = null;
+ if (jo.has("user")) { // not required, if no username given authuser
+ // will be used otherwise username and password
+ // has to be submitted
+ JSONObject user = jo.getJSONObject("user");
+ if (user.has("id")) {
+ username = user.getString("id");
+ if(!user.has("password")){
+ User authUser = handleBasicAuthentification(entity);
+ if (authUser==null){
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ }
+ username = authUser.getIdentifier();
+ } else {
+ String password = user.getString("password");
+ if (!((RestServer) getApplication()).authenticate(username,
+ password, getRequest())) {
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ }
+ }
+ }
+
+ } else {
+ User authUser = handleBasicAuthentification(entity);
+ if (authUser == null) {
+ setStatus(Status.CLIENT_ERROR_FORBIDDEN);
+ return null;
+ }
+ username = authUser.getIdentifier();
+ }
+
+ String 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;
+ }
+ } else {
+ xpointer = url;
+ }
+
+ //username should be a URI, if not it will set to the MPIWG namespace defined in de.mpiwg.itgroup.annotationManager.Constants.NS
+ if (!username.startsWith("http"))
+ username=NS.MPIWG_PERSONS+username;
+
+ return new Convert.Annotation(xpointer, username, null, text, null);
+ }
+
+}