source: DASISH/t5.6/backend/annotator-backend/trunk/annotator-backend/src/main/java/eu/dasish/annotation/backend/rest/AnnotationResource.java @ 4217

Last change on this file since 4217 was 4217, checked in by olhsha, 10 years ago

files INSTALL, UPDATED, CHANGES and README are corrected. The bug with the wrong server diagnostic (403 instead of 404), when a resource's give id is not found, is fixed.

File size: 21.6 KB
Line 
1/*
2 * Copyright (C) 2013 DASISH
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 */
18package eu.dasish.annotation.backend.rest;
19
20import eu.dasish.annotation.backend.BackendConstants;
21import eu.dasish.annotation.backend.dao.DBIntegrityService;
22import eu.dasish.annotation.schema.Annotation;
23import eu.dasish.annotation.schema.AnnotationActionName;
24import eu.dasish.annotation.schema.AnnotationInfoList;
25import eu.dasish.annotation.schema.Action;
26import eu.dasish.annotation.schema.ActionList;
27import eu.dasish.annotation.schema.AnnotationBody;
28import eu.dasish.annotation.schema.ObjectFactory;
29import eu.dasish.annotation.schema.Permission;
30import eu.dasish.annotation.schema.PermissionActionName;
31import eu.dasish.annotation.schema.UserWithPermissionList;
32import eu.dasish.annotation.schema.ReferenceList;
33import eu.dasish.annotation.schema.ResponseBody;
34import java.io.IOException;
35import java.net.URI;
36import java.sql.Timestamp;
37import java.util.ArrayList;
38import java.util.List;
39import java.util.UUID;
40import javax.servlet.http.HttpServletRequest;
41import javax.servlet.http.HttpServletResponse;
42import javax.ws.rs.Consumes;
43import javax.ws.rs.DELETE;
44import javax.ws.rs.GET;
45import javax.ws.rs.POST;
46import javax.ws.rs.PUT;
47import javax.ws.rs.Path;
48import javax.ws.rs.PathParam;
49import javax.ws.rs.Produces;
50import javax.ws.rs.QueryParam;
51import javax.ws.rs.core.Context;
52import javax.ws.rs.core.MediaType;
53import javax.ws.rs.core.UriInfo;
54import javax.ws.rs.ext.Providers;
55import javax.xml.bind.JAXBElement;
56import org.springframework.beans.factory.annotation.Autowired;
57import org.springframework.security.access.annotation.Secured;
58import org.springframework.stereotype.Component;
59import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61import org.springframework.transaction.annotation.Transactional;
62
63/**
64 *
65 * @author olhsha
66 */
67@Component
68@Path("/annotations")
69@Transactional(rollbackFor = {Exception.class})
70public class AnnotationResource {
71
72    @Autowired
73    private DBIntegrityService dbIntegrityService;
74    @Context
75    private HttpServletRequest httpServletRequest;
76    @Context
77    private HttpServletResponse httpServletResponse;
78    @Context
79    private UriInfo uriInfo;
80    @Context
81    private Providers providers;
82    final String default_permission = "reader";
83    private static final Logger logger = LoggerFactory.getLogger(AnnotationResource.class);
84
85    public void setUriInfo(UriInfo uriInfo) {
86        this.uriInfo = uriInfo;
87    }
88
89    public void setHttpServletResponse(HttpServletResponse httpServletResponse) {
90        this.httpServletResponse = httpServletResponse;
91    }
92
93    public void setHttpServletRequest(HttpServletRequest httpServletRequest) {
94        this.httpServletRequest = httpServletRequest;
95    }
96
97    public void setProviders(Providers providers) {
98        this.providers = providers;
99    }
100
101    public AnnotationResource() {
102    }
103
104    @GET
105    @Produces(MediaType.TEXT_XML)
106    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}")
107    @Secured("ROLE_USER")
108    @Transactional(readOnly = true)
109    public JAXBElement<Annotation> getAnnotation(@PathParam("annotationid") String ExternalIdentifier) throws IOException {
110        URI baseURI = uriInfo.getBaseUri();
111        String baseURIstr = baseURI.toString();
112        dbIntegrityService.setServiceURI(baseURIstr);
113        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(ExternalIdentifier));
114        if (annotationID != null) {
115            String remoteUser = httpServletRequest.getRemoteUser();
116            final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(remoteUser);
117            if (canRead(userID, annotationID)) {
118                final Annotation annotation = dbIntegrityService.getAnnotation(annotationID);
119                JAXBElement<Annotation> rootElement = new ObjectFactory().createAnnotation(annotation);
120                logger.info("getAnnotation method: OK");
121                return rootElement;
122            } else {
123                httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "The logged-in user cannot read the annotation.");
124                return null;
125            }
126        } else {
127            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
128            return null;
129        }
130
131    }
132
133    //TODO: unit test
134    @GET
135    @Produces(MediaType.TEXT_XML)
136    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/targets")
137    @Secured("ROLE_USER")
138    @Transactional(readOnly = true)
139    public JAXBElement<ReferenceList> getAnnotationTargets(@PathParam("annotationid") String ExternalIdentifier) throws IOException {
140        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
141        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(ExternalIdentifier));
142        if (annotationID != null) {
143            final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
144            if (canRead(userID, annotationID)) {
145                final ReferenceList TargetList = dbIntegrityService.getAnnotationTargets(annotationID);
146                logger.info("getAnnotationTargets method: OK");
147                return new ObjectFactory().createTargetList(TargetList);
148            } else {
149                httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "The logged-in user cannot read the annotation.");
150                return null;
151            }
152        } else {
153            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
154            return null;
155        }
156    }
157
158    // TODO Unit test
159    @GET
160    @Produces(MediaType.TEXT_XML)
161    @Path("")
162    @Secured("ROLE_USER")
163    @Transactional(readOnly = true)
164    public JAXBElement<AnnotationInfoList> getFilteredAnnotations(@QueryParam("link") String link,
165            @QueryParam("text") String text,
166            @QueryParam("access") String permission,
167            @QueryParam("namespace") String namespace,
168            @QueryParam("owner") String ownerExternalId,
169            @QueryParam("after") Timestamp after,
170            @QueryParam("before") Timestamp before) {
171
172        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
173        Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
174        UUID ownerExternalUUID = (ownerExternalId != null) ? UUID.fromString(ownerExternalId) : null;
175        String access = (permission != null) ? permission : default_permission;
176        final AnnotationInfoList annotationInfoList = dbIntegrityService.getFilteredAnnotationInfos(link, text, userID, makeAccessModeChain(access), namespace, ownerExternalUUID, after, before);
177        logger.info("getFilteredAnnotations method: OK");
178        return new ObjectFactory().createAnnotationInfoList(annotationInfoList);
179    }
180
181    // TODO Unit test   
182    @GET
183    @Produces(MediaType.TEXT_XML)
184    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/permissions")
185    @Secured("ROLE_USER")
186    @Transactional(readOnly = true)
187    public JAXBElement<UserWithPermissionList> getAnnotationPermissions(@PathParam("annotationid") String ExternalIdentifier) throws IOException {
188        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
189        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(ExternalIdentifier));
190        final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
191        if (annotationID != null) {
192            if (canRead(userID, annotationID)) {
193                final UserWithPermissionList permissionList = dbIntegrityService.getPermissionsForAnnotation(annotationID);
194                logger.info("getAnnotationPermissions method: OK");
195                return new ObjectFactory().createPermissionList(permissionList);
196            } else {
197                httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "The logged-in user cannot read the annotation.");
198                return null;
199            }
200        } else {
201            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
202            return null;
203        }
204    }
205
206    ///////////////////////////////////////////////////////
207    // TODO: how to return the status code?
208    @DELETE
209    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}")
210    @Secured("ROLE_USER")
211    public String deleteAnnotation(@PathParam("annotationid") String externalIdentifier) throws IOException {
212        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
213        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(externalIdentifier));
214        final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
215        if (annotationID != null) {
216            if (isOwner(userID, annotationID)) {
217                int[] resultDelete = dbIntegrityService.deleteAnnotation(annotationID);
218                String result = Integer.toString(resultDelete[0]);
219                logger.info("deleteAnnotation method: OK");
220                return result + " annotation(s) deleted.";
221            } else {
222                httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "The logged-in user cannot delete the annotation. Only the owner can delete the annotation.");
223                return null;
224            }
225        } else {
226            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
227            return null;
228        }
229    }
230
231    ///////////////////////////////////////////////////////
232    @POST
233    @Consumes(MediaType.APPLICATION_XML)
234    @Produces(MediaType.APPLICATION_XML)
235    @Path("")
236    @Secured("ROLE_USER")
237    public JAXBElement<ResponseBody> createAnnotation(Annotation annotation) throws IOException {
238        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
239        final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
240        Number annotationID = dbIntegrityService.addUsersAnnotation(userID, annotation);
241        logger.info("createAnnotation method: OK");
242        return new ObjectFactory().createResponseBody(makeAnnotationResponseEnvelope(annotationID));
243    }
244
245    ///////////////////////////////////////////////////////
246    // TODO: unit test
247    @PUT
248    @Consumes(MediaType.APPLICATION_XML)
249    @Produces(MediaType.APPLICATION_XML)
250    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}")
251    @Secured("ROLE_USER")
252    public JAXBElement<ResponseBody> updateAnnotation(@PathParam("annotationid") String externalIdentifier, Annotation annotation) throws IOException {
253        String path = uriInfo.getBaseUri().toString();
254        dbIntegrityService.setServiceURI(path);
255        String annotationURI = annotation.getURI();
256        if (!(path + "annotations/" + externalIdentifier).equals(annotationURI)) {
257            logger.error("Wrong request: the external annotation ID and the annotation ID from the request body do not match.");
258            logger.error("Will do nothing.");
259            return null;
260        }
261        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(externalIdentifier));
262        if (annotationID != null) {
263            final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
264            if (canWrite(userID, annotationID)) {
265                int updatedRows = dbIntegrityService.updateUsersAnnotation(userID, annotation);
266                logger.info("updateAnnotation method: OK");
267                return new ObjectFactory().createResponseBody(makeAnnotationResponseEnvelope(annotationID));
268
269            } else {
270                httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
271                return null;
272            }
273        } else {
274            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
275            return null;
276        }
277    }
278
279    @PUT
280    @Consumes(MediaType.APPLICATION_XML)
281    @Produces(MediaType.APPLICATION_XML)
282    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/body")
283    @Secured("ROLE_USER")
284    public JAXBElement<ResponseBody> updateAnnotationBody(@PathParam("annotationid") String externalIdentifier, AnnotationBody annotationBody) throws IOException {
285        String path = uriInfo.getBaseUri().toString();
286        dbIntegrityService.setServiceURI(path);
287
288        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(externalIdentifier));
289        final Number userID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
290        if (annotationID != null) {
291            if (canWrite(userID, annotationID)) {
292                int updatedRows = dbIntegrityService.updateAnnotationBody(annotationID, annotationBody);
293                logger.info("updateAnnotationBody method: OK");
294                return new ObjectFactory().createResponseBody(makeAnnotationResponseEnvelope(annotationID));
295            } else {
296                httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
297                return null;
298            }
299        } else {
300            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
301            return null;
302        }
303    }
304
305    @PUT
306    @Consumes(MediaType.APPLICATION_XML)
307    @Produces(MediaType.APPLICATION_XML)
308    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/permissions/{userid: " + BackendConstants.regExpIdentifier + "}")
309    @Secured("ROLE_USER")
310    public String updatePermission(@PathParam("annotationid") String annotationExternalId, @PathParam("userid") String userExternalId, Permission permission) throws IOException {
311        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
312        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(annotationExternalId));
313        final Number remoteUserID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
314        final Number userID = dbIntegrityService.getUserInternalIdentifier(UUID.fromString(userExternalId));
315        if (annotationID != null) {
316            if (isOwner(remoteUserID, annotationID)) {
317                int result = (dbIntegrityService.getPermission(annotationID, userID) != null)
318                        ? dbIntegrityService.updateAnnotationPrincipalPermission(annotationID, userID, permission)
319                        : dbIntegrityService.addAnnotationPrincipalPermission(annotationID, userID, permission);
320                logger.info("updatePermission method: OK");
321                return result + " rows are updated/added";
322
323            } else {
324                httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
325                return null;
326            }
327        } else {
328            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
329            return null;
330        }
331    }
332
333    @PUT
334    @Consumes(MediaType.APPLICATION_XML)
335    @Produces(MediaType.APPLICATION_XML)
336    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/permissions/")
337    @Secured("ROLE_USER")
338    public JAXBElement<ResponseBody> updatePermissions(@PathParam("annotationid") String annotationExternalId, UserWithPermissionList permissions) throws IOException {
339        dbIntegrityService.setServiceURI(uriInfo.getBaseUri().toString());
340        final Number annotationID = dbIntegrityService.getAnnotationInternalIdentifier(UUID.fromString(annotationExternalId));
341        final Number remoteUserID = dbIntegrityService.getUserInternalIDFromRemoteID(httpServletRequest.getRemoteUser());
342        if (annotationID != null) {
343            if (isOwner(remoteUserID, annotationID)) {
344                int updatedRows = dbIntegrityService.updatePermissions(annotationID, permissions);
345                logger.info("updatePermissions method: OK");
346                return new ObjectFactory().createResponseBody(makePermissionResponseEnvelope(annotationID));
347            } else {
348                httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
349                return null;
350            }
351        } else {
352            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "The annotation with the given id is not found in the database");
353            return null;
354        }
355    }
356
357    /////////////////////////////////////////
358    private ResponseBody makeAnnotationResponseEnvelope(Number annotationID) {
359        ResponseBody result = new ResponseBody();
360        result.setPermissions(null);
361        Annotation annotation = dbIntegrityService.getAnnotation(annotationID);
362        result.setAnnotation(annotation);
363        List<String> targetsNoCached = dbIntegrityService.getTargetsWithNoCachedRepresentation(annotationID);
364        ActionList actionList = new ActionList();
365        result.setActionList(actionList);
366        actionList.getAction().addAll(makeActionList(targetsNoCached, AnnotationActionName.CREATE_CACHED_REPRESENTATION.value()));
367        return result;
368    }
369
370    /////////////////////////////////////////
371    private ResponseBody makePermissionResponseEnvelope(Number annotationID) {
372        ResponseBody result = new ResponseBody();
373        result.setAnnotation(null);
374        UserWithPermissionList permissions = dbIntegrityService.getPermissionsForAnnotation(annotationID);
375        result.setPermissions(permissions);
376        List<String> usersWithNoInfo = dbIntegrityService.getUsersWithNoInfo(annotationID);
377        ActionList actionList = new ActionList();
378        result.setActionList(actionList);
379        actionList.getAction().addAll(makeActionList(usersWithNoInfo, PermissionActionName.PROVIDE_USER_INFO.value()));
380        return result;
381    }
382
383    // REFACTOR : move to the integrity service all te methods below 
384    private List<Action> makeActionList(List<String> resourceURIs, String message) {
385        if (resourceURIs != null) {
386            if (resourceURIs.isEmpty()) {
387                return (new ArrayList<Action>());
388            } else {
389                List<Action> result = new ArrayList<Action>();
390                for (String resourceURI : resourceURIs) {
391                    Action action = new Action();
392                    result.add(action);
393                    action.setMessage(message);
394                    action.setObject(resourceURI);
395                }
396                return result;
397            }
398        } else {
399            return null;
400        }
401    }
402
403    private boolean canRead(Number userID, Number annotationID) {
404        final Permission permission = dbIntegrityService.getPermission(annotationID, userID);
405        if (permission != null) {
406            return (permission.value() == Permission.OWNER.value() || permission.value() == Permission.WRITER.value() || permission.value() == Permission.READER.value());
407        } else {
408            return false;
409        }
410    }
411
412    private boolean canWrite(Number userID, Number annotationID) {
413        final Permission permission = dbIntegrityService.getPermission(annotationID, userID);
414        if (permission != null) {
415            return (permission.value() == Permission.OWNER.value() || permission.value() == Permission.WRITER.value());
416        } else {
417            return false;
418        }
419    }
420
421    private boolean isOwner(Number userID, Number annotationID) {
422        final Permission permission = dbIntegrityService.getPermission(annotationID, userID);
423        if (permission != null) {
424            return (permission.value() == Permission.OWNER.value());
425        } else {
426            return false;
427        }
428    }
429
430    private String[] makeAccessModeChain(String accessMode) {
431        if (accessMode != null) {
432            if (accessMode == Permission.OWNER.value()) {
433                String[] result = new String[1];
434                result[0] = accessMode;
435                return result;
436            } else {
437                if (accessMode == Permission.WRITER.value()) {
438                    String[] result = new String[2];
439                    result[0] = Permission.WRITER.value();
440                    result[1] = Permission.OWNER.value();
441                    return result;
442                } else {
443                    if (accessMode == Permission.READER.value()) {
444                        String[] result = new String[3];
445                        result[0] = Permission.READER.value();
446                        result[1] = Permission.WRITER.value();
447                        result[2] = Permission.OWNER.value();
448                        return result;
449                    } else {
450                        logger.error("Invalide access " + accessMode);
451                        return null;
452                    }
453
454                }
455            }
456
457        } else {
458            return null;
459        }
460    }
461}
Note: See TracBrowser for help on using the repository browser.