source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java @ 65:c0dd5314bada

Last change on this file since 65:c0dd5314bada was 65:c0dd5314bada, checked in by casties, 11 years ago

deal with special characters in urls.

File size: 10.1 KB
Line 
1/**
2 * Implements the "annotations" uri of the Annotator API. see
3 * <https://github.com/okfn/annotator/wiki/Storage>
4 */
5package de.mpiwg.itgroup.annotations.restlet;
6
7import java.io.IOException;
8import java.io.UnsupportedEncodingException;
9import java.net.URLDecoder;
10import java.util.ArrayList;
11import java.util.List;
12
13import org.json.JSONArray;
14import org.json.JSONException;
15import org.json.JSONObject;
16import org.restlet.data.Form;
17import org.restlet.data.Status;
18import org.restlet.ext.json.JsonRepresentation;
19import org.restlet.representation.Representation;
20import org.restlet.resource.Delete;
21import org.restlet.resource.Get;
22import org.restlet.resource.Post;
23import org.restlet.resource.Put;
24
25import de.mpiwg.itgroup.annotations.Annotation;
26import de.mpiwg.itgroup.annotations.Person;
27import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
28import de.mpiwg.itgroup.annotations.restlet.utils.JSONObjectComparator;
29
30/**
31 * Implements the "annotations" uri of the Annotator API. see
32 * <https://github.com/okfn/annotator/wiki/Storage>
33 *
34 * @author dwinter, casties
35 *
36 */
37public class AnnotatorAnnotations extends AnnotatorResourceImpl {
38
39    protected String getAllowedMethodsForHeader() {
40        return "OPTIONS,GET,POST,PUT,DELETE";
41    }
42
43    /**
44     * GET with JSON content-type.
45     *
46     * @param entity
47     * @return
48     */
49    @Get("json")
50    public Representation doGetJSON(Representation entity) {
51        logger.debug("AnnotatorAnnotations doGetJSON!");
52        setCorsHeaders();
53        // id from URI /annotations/{id}
54        String id = null;
55        String jsonId = (String) getRequest().getAttributes().get("id");
56        if (jsonId != null) {
57            // URL decode
58            try {
59                jsonId = URLDecoder.decode(jsonId, "UTF-8");
60            } catch (UnsupportedEncodingException e) {
61                // this shouldn't happen
62            }
63            id = decodeJsonId(jsonId);
64            logger.debug("annotation-id=" + id);
65        }
66
67        // do authentication
68        Person authUser = Person.createPersonWithId(this.checkAuthToken(entity));
69        logger.debug("request authenticated=" + authUser);
70
71        if (id == null) {
72            // no id -- send all annotations
73            Form form = getRequest().getResourceRef().getQueryAsForm();
74            int limit = getInt(form.getFirstValue("limit"));
75            int offset = getInt(form.getFirstValue("offset"));
76            String sortBy = form.getFirstValue("sortBy");
77            return getAllAnnotations(authUser, limit, offset, sortBy);
78        }
79
80        // send annotation with id
81        AnnotationStore store = getAnnotationStore();
82        Annotation annot = store.getAnnotationById(id);
83        if (annot != null) {
84            if (!annot.isActionAllowed("read", authUser, store)) {
85                setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
86                return null;
87            }
88            JSONObject result = createAnnotatorJson(annot, (authUser == null));
89            return new JsonRepresentation(result);
90        } else {
91            // not found
92            setStatus(Status.CLIENT_ERROR_NOT_FOUND);
93            return null;
94        }
95    }
96
97    private Representation getAllAnnotations(Person authUser, int limit, int offset, String sortBy) {
98        AnnotationStore store = getAnnotationStore();
99        ArrayList<JSONObject> results = new ArrayList<JSONObject>();
100
101        // read all annotations
102        List<Annotation> annotations = store.getAnnotations(null, null);
103        for (Annotation annotation : annotations) {
104            // check permission
105            if (!annotation.isActionAllowed("read", authUser, store))
106                continue;
107            // add annotation to list
108            JSONObject jo = createAnnotatorJson(annotation, false);
109            results.add(jo);
110        }
111
112        // sort if necessary
113        if (sortBy != null) {
114            JSONObjectComparator.sortAnnotations(results, sortBy);
115        }
116
117        // put in JSON list
118        JSONArray rows = new JSONArray();
119        int cnt = 0;
120        for (JSONObject result : results) {
121            cnt += 1;
122            if (offset > 0 && cnt < offset)
123                continue;
124            rows.put(result);
125            if (limit > 0 && cnt >= limit)
126                break;
127        }
128
129        // assemble result object
130        JSONObject result = new JSONObject();
131        try {
132            result.put("rows", rows);
133            result.put("total", rows.length());
134        } catch (JSONException e) {
135            setStatus(Status.SERVER_ERROR_INTERNAL, "JSON Error");
136            return null;
137        }
138        return new JsonRepresentation(result);
139    }
140
141    /**
142     * POST with JSON content-type. Creates a new Annotation.
143     *
144     * @return
145     */
146    @Post("json")
147    public Representation doPostJson(Representation entity) {
148        logger.debug("AnnotatorAnnotations doPostJSON!");
149        // set headers
150        setCorsHeaders();
151
152        // do authentication TODO: who's allowed to create?
153        Person authUser = Person.createPersonWithId(this.checkAuthToken(entity));
154        logger.debug("request authenticated=" + authUser);
155        if (authUser == null) {
156            setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
157            return null;
158        }
159
160        Annotation annot = null;
161        try {
162            JsonRepresentation jrep = new JsonRepresentation(entity);
163            JSONObject jo = jrep.getJsonObject();
164            if (jo == null) {
165                setStatus(Status.SERVER_ERROR_INTERNAL);
166                return null;
167            }
168            // make sure id is not set for POST
169            jo.remove("id");
170            // get Annotation object from posted JSON
171            annot = createAnnotation(jo, entity);
172        } catch (IOException e1) {
173            setStatus(Status.SERVER_ERROR_INTERNAL);
174            return null;
175        } catch (JSONException e) {
176            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
177            return null;
178        }
179        if (annot == null) {
180            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
181            return null;
182        }
183        Annotation storedAnnot;
184        // store Annotation
185        storedAnnot = getAnnotationStore().storeAnnotation(annot);
186        /*
187         * according to https://github.com/okfn/annotator/wiki/Storage we should
188         * return 303: see other. For now we return the annotation.
189         */
190        JSONObject jo = createAnnotatorJson(storedAnnot, (authUser == null));
191        JsonRepresentation retRep = new JsonRepresentation(jo);
192        return retRep;
193    }
194
195    /**
196     * PUT with JSON content-type. Modifies an Annotation.
197     *
198     * @param entity
199     * @return
200     */
201    @Put("json")
202    public Representation doPutJSON(Representation entity) {
203        logger.debug("AnnotatorAnnotations doPutJSON!");
204        setCorsHeaders();
205        // id from URI /annotations/{id}
206        String jsonId = (String) getRequest().getAttributes().get("id");
207        String id = decodeJsonId(jsonId);
208        logger.debug("annotation-id=" + id);
209
210        // do authentication
211        Person authUser = Person.createPersonWithId(this.checkAuthToken(entity));
212        logger.debug("request authenticated=" + authUser);
213
214        Annotation annot = null;
215        AnnotationStore store = getAnnotationStore();
216        try {
217            JsonRepresentation jrep = new JsonRepresentation(entity);
218            JSONObject jo = jrep.getJsonObject();
219            if (jo == null) {
220                setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
221                return null;
222            }
223            // get stored Annotation
224            Annotation storedAnnot = store.getAnnotationById(id);
225            if (storedAnnot == null) {
226                setStatus(Status.CLIENT_ERROR_NOT_FOUND);
227                return null;
228            }
229            if (!storedAnnot.isActionAllowed("update", authUser, store)) {
230                setStatus(Status.CLIENT_ERROR_FORBIDDEN);
231                return null;
232            }
233            // update from posted JSON
234            annot = updateAnnotation(storedAnnot, jo, entity);
235            // store Annotation
236            storedAnnot = store.storeAnnotation(annot);
237            /*
238             * according to https://github.com/okfn/annotator/wiki/Storage we
239             * should return 303: see other. but the client doesn't like it
240             * setStatus(Status.REDIRECTION_SEE_OTHER); // go to same URL as
241             * this one Reference thisUrl = this.getReference();
242             * this.getResponse().setLocationRef(thisUrl);
243             */
244            // return new annotation
245            jo = createAnnotatorJson(storedAnnot, (authUser == null));
246            JsonRepresentation retRep = new JsonRepresentation(jo);
247            return retRep;
248        } catch (JSONException e) {
249            logger.error("Error in doPutJSON", e);
250            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
251        } catch (IOException e) {
252            logger.error("Error in doPutJSON", e);
253            setStatus(Status.SERVER_ERROR_INTERNAL, "Other Error");
254        }
255        return null;
256    }
257
258    /**
259     * DELETE with JSON content-type. Deletes an Annotation.
260     *
261     * @param entity
262     * @return
263     */
264    @Delete("json")
265    public Representation doDeleteJSON(Representation entity) {
266        logger.debug("AnnotatorAnnotations doDeleteJSON!");
267        setCorsHeaders();
268        // id from URI /annotations/{id}
269        String jsonId = (String) getRequest().getAttributes().get("id");
270        String id = decodeJsonId(jsonId);
271        logger.debug("annotation-id=" + id);
272
273        // do authentication
274        Person authUser = Person.createPersonWithId(this.checkAuthToken(entity));
275        logger.debug("request authenticated=" + authUser);
276        AnnotationStore store = getAnnotationStore();
277        Annotation annot = store.getAnnotationById(id);
278        if (annot != null) {
279            if (!annot.isActionAllowed("delete", authUser, store)) {
280                setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Not Authorized!");
281                return null;
282            }
283        }
284        // delete annotation
285        store.deleteAnnotationById(id);
286        setStatus(Status.SUCCESS_NO_CONTENT);
287        return null;
288    }
289
290}
Note: See TracBrowser for help on using the repository browser.