changeset 8:11baadcdd2c8

start of new Annotator API implementation.
author casties
date Mon, 19 Mar 2012 14:50:28 +0100
parents 97f68ab3430f
children e9fd2e1e0979
files src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorResourceImpl.java src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorSearch.java src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java
diffstat 3 files changed, 340 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorResourceImpl.java	Mon Mar 19 14:50:28 2012 +0100
@@ -0,0 +1,161 @@
+/**
+ * Base class for Annotator resource classes.
+ */
+package de.mpiwg.itgroup.annotationManager.restlet;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.restlet.data.Form;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Options;
+import org.restlet.resource.ServerResource;
+
+import de.mpiwg.itgroup.annotationManager.Constants.NS;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert;
+
+/**
+ * Base class for Annotator resource classes.
+ * 
+ * @author dwinter, casties
+ * 
+ */
+public abstract class AnnotatorResourceImpl extends ServerResource {
+
+    protected String getAllowedMethodsForHeader() {
+        return "OPTIONS,GET,POST";
+    }
+
+    /**
+     * Handle options request to allow CORS for AJAX.
+     * 
+     * @param entity
+     */
+    @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-Methods",
+                getAllowedMethodsForHeader());
+        // echo back Origin and Request-Headers
+        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-Credentials", "true");
+        responseHeaders.add("Access-Control-Max-Age", "60");
+    }
+
+    /**
+     * Erzeugt aus einer Annotation, das fuer den Annotator notwendige
+     * JSON-Format
+     * 
+     * @param annot
+     * @return
+     */
+    protected 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<String> xpointer = new ArrayList<String>();
+
+            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;
+        }
+    }
+
+    private JSONArray transformToRanges(List<String> 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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/AnnotatorSearch.java	Mon Mar 19 14:50:28 2012 +0100
@@ -0,0 +1,177 @@
+/**
+ * Implements the "search" uri of the Annotator API.
+ */
+package de.mpiwg.itgroup.annotationManager.restlet;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+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 de.mpiwg.itgroup.annotationManager.Errors.TripleStoreSearchError;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.Convert;
+import de.mpiwg.itgroup.annotationManager.RDFHandling.RDFSearcher;
+import de.mpiwg.itgroup.triplestoremanager.exceptions.TripleStoreHandlerException;
+
+/**
+ * Implements the "search" uri of the Annotator API.
+ * see <https://github.com/okfn/annotator/wiki/Storage>
+ * 
+ * @author casties
+ *
+ */
+public class AnnotatorSearch extends AnnotatorResourceImpl {
+    
+    private Logger logger = Logger.getRootLogger();
+
+    protected String getAllowedMethodsForHeader() {
+        return "OPTIONS,GET";
+    }
+    
+    /**
+     * JSON content type result.
+     * 
+     * @param entity
+     * @return
+     */
+    @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<Convert.Annotation> annots=searcher.search(uri,user,limit,offset);
+
+            ja = new JSONArray();
+            for (Convert.Annotation annot:annots){
+                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);
+    }
+
+    /**
+     * HTML content type result.
+     * 
+     * @param entity
+     * @return
+     */
+    @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="<html><body><table>";
+        String lineFormat="<tr><td><a href=\"%s\">%s</a></td>" +
+                "<td><a href=\"%s\">%s</a></td><td>%s</td><td>%s</td><td><a href=\"%s\">%s</a></td><td><a href=\"%s\">%s</a></td></div>";
+        try {
+            
+            List<Convert.Annotation> annots=searcher.search(uri,user,limit,offset);
+
+            for (Convert.Annotation annot:annots){
+                
+                
+                RestServer restServer = (RestServer) getApplication();
+                String userName=restServer.getUserNameFromLdap(annot.creator);
+                List<String> xpointer = new ArrayList<String>();
+
+                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+="</table></body></html>";
+        
+        logger.debug("sending:");
+        logger.debug(retString);
+        return new StringRepresentation(retString,MediaType.TEXT_HTML);
+    }
+
+
+}
--- a/src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java	Mon Mar 19 12:01:39 2012 +0100
+++ b/src/de/mpiwg/itgroup/annotationManager/restlet/RestServer.java	Mon Mar 19 14:50:28 2012 +0100
@@ -12,11 +12,7 @@
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.login.AppConfigurationEntry;
 import javax.security.auth.login.Configuration;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
@@ -29,21 +25,13 @@
 import org.restlet.Request;
 import org.restlet.Response;
 import org.restlet.Restlet;
-
 import org.restlet.data.ChallengeScheme;
 import org.restlet.data.ClientInfo;
-import org.restlet.engine.component.ChildContext;
 import org.restlet.ext.jaas.JaasVerifier;
-import org.restlet.routing.Redirector;
 import org.restlet.routing.Router;
-import org.restlet.routing.Template;
-import org.restlet.routing.TemplateRoute;
 import org.restlet.security.ChallengeAuthenticator;
-import org.restlet.security.MapVerifier;
 import org.restlet.security.User;
-import org.restlet.security.Verifier;
 
-import com.sun.org.apache.xalan.internal.xsltc.runtime.Attributes;
 import com.sun.security.auth.login.ConfigFile;
 
 
@@ -134,7 +122,8 @@
 		
 		
 		router.attach("/annotations",AddAndReadAnnotations.class);
-		router.attach("/search",SearchAnnotations.class); // annotator api askes for different uris for search and adding
+        router.attach("/search",AnnotatorSearch.class); // annotator api askes for different uris for search and adding
+		//router.attach("/search",SearchAnnotations.class); // annotator api askes for different uris for search and adding
 		router.attach("/dummy",Dummy.class);
 		
 		//router.attach("",redirector);