source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java @ 88:b406507a953d

Last change on this file since 88:b406507a953d was 88:b406507a953d, checked in by casties, 9 years ago

upped version to 0.5.
can use display name and groups from auth token.

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