source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorAnnotations.java @ 75:25eb2e1df106

Last change on this file since 75:25eb2e1df106 was 75:25eb2e1df106, checked in by casties, 10 years ago

change logging to java.util.logging.

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