# 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="" + + ""; + 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+="
%s%s%s%s%s%s
"; + + 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="" + - ""; - 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+="
%s%s%s%s%s%s
"; - - 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="" + + ""; + 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+="
%s%s%s%s%s%s
"; + + 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); + } + +}