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

Last change on this file since 6009 was 6009, checked in by olhsha@mpi.nl, 9 years ago

Javadoc are updated for AnnotationResource?.java

File size: 38.1 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.ForbiddenException;
22import eu.dasish.annotation.backend.MatchMode;
23import eu.dasish.annotation.backend.NotInDataBaseException;
24import eu.dasish.annotation.backend.Resource;
25import eu.dasish.annotation.backend.dao.ILambda;
26import eu.dasish.annotation.schema.Annotation;
27import eu.dasish.annotation.schema.AnnotationBody;
28import eu.dasish.annotation.schema.AnnotationInfoList;
29import eu.dasish.annotation.schema.ObjectFactory;
30import eu.dasish.annotation.schema.Access;
31import eu.dasish.annotation.schema.PermissionList;
32import eu.dasish.annotation.schema.ReferenceList;
33import eu.dasish.annotation.schema.ResponseBody;
34import java.io.IOException;
35import java.util.ArrayList;
36import java.util.Arrays;
37import java.util.HashMap;
38import java.util.List;
39import java.util.Map;
40import java.util.Random;
41import java.util.UUID;
42import javax.servlet.http.HttpServletRequest;
43import javax.servlet.http.HttpServletResponse;
44import javax.ws.rs.Consumes;
45import javax.ws.rs.DELETE;
46import javax.ws.rs.FormParam;
47import javax.ws.rs.GET;
48import javax.ws.rs.POST;
49import javax.ws.rs.PUT;
50import javax.ws.rs.Path;
51import javax.ws.rs.PathParam;
52import javax.ws.rs.Produces;
53import javax.ws.rs.QueryParam;
54import javax.ws.rs.core.MediaType;
55import javax.ws.rs.ext.Providers;
56import javax.xml.bind.JAXBElement;
57import org.springframework.stereotype.Component;
58import org.springframework.transaction.annotation.Transactional;
59
60/**
61 *
62 * @author olhsha
63 */
64@Component
65@Path("/annotations")
66@Transactional(rollbackFor = {Exception.class})
67public class AnnotationResource extends ResourceResource {
68   
69    final private String defaultMatchMode = "exact";
70    final private String[] admissibleMatchModes = {"exact", "starts_with", "ends_with", "contains"};
71
72   /**
73    *
74    * @param httpServletResponse a {@link HttpServletResponse} object, to be set to "this" object and to be used to send error messages.
75    */
76    public void setHttpServletResponse(HttpServletResponse httpServletResponse) {
77        this.httpServletResponse = httpServletResponse;
78    }
79   
80    /**
81     *
82     * @param httpServletRequest a {@link HttpServletRequest} object, to be set to "this" object and to be used in the unit tests.
83     */
84    public void setHttpServletRequest(HttpServletRequest httpServletRequest) {
85        this.httpServletRequest = httpServletRequest;
86    }
87
88    /**
89     *
90     * @param providers a {@link Providers} object, to be set to "this" object and to be used to force
91     * validation of the input/output xml files w.r.t. the dasish schema.
92     */
93    public void setProviders(Providers providers) {
94        this.providers = providers;
95    }
96
97    public AnnotationResource() {
98    }
99   
100
101    /**
102     *
103     * @param externalIdentifier the string representing the UUID of an annotation.
104     * @return the xml-element representing the annotation with "externalIdentifier" built up
105     * from the "annotation" table and the corresponding junction tables.
106     * @throws IOException if sending the error fails.
107     */
108    @GET
109    @Produces(MediaType.TEXT_XML)
110    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}")
111    @Transactional(readOnly = true)
112    public JAXBElement<Annotation> getAnnotation(@PathParam("annotationid") String externalIdentifier) throws IOException {
113        Map params = new HashMap();
114        try {
115            Annotation result = (Annotation) (new RequestWrappers(this)).wrapRequestResource(params, new GetAnnotation(), Resource.ANNOTATION, Access.READ, externalIdentifier);
116            if (result != null) {
117                return (new ObjectFactory()).createAnnotation(result);
118            } else {
119                return (new ObjectFactory()).createAnnotation(new Annotation());
120            }
121        } catch (NotInDataBaseException e1) {
122            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
123            return (new ObjectFactory()).createAnnotation(new Annotation());
124        } catch (ForbiddenException e2) {
125            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
126            return (new ObjectFactory()).createAnnotation(new Annotation());
127        }
128    }
129
130    private class GetAnnotation implements ILambda<Map, Annotation> {
131
132        @Override
133        public Annotation apply(Map params) throws NotInDataBaseException {
134            return dbDispatcher.getAnnotation((Number) params.get("internalID"));
135        }
136    }
137
138    /**
139     *
140     * @param externalIdentifier the string representing the UUID of an annotation.
141     * @return the xml element representing the list of h-references of the annotation with "externalIdentifier".
142     * @throws IOException if sending the error fails.
143     */
144    @GET
145    @Produces(MediaType.TEXT_XML)
146    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/targets")
147    @Transactional(readOnly = true)
148    public JAXBElement<ReferenceList> getAnnotationTargets(@PathParam("annotationid") String externalIdentifier) throws IOException {
149        Map params = new HashMap();
150        try {
151            ReferenceList result = (ReferenceList) (new RequestWrappers(this)).wrapRequestResource(params, new GetTargetList(), Resource.ANNOTATION, Access.READ, externalIdentifier);
152            if (result != null) {
153                return (new ObjectFactory()).createTargetList(result);
154            } else {
155                return (new ObjectFactory()).createTargetList(new ReferenceList());
156            }
157        } catch (NotInDataBaseException e1) {
158            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
159            return (new ObjectFactory()).createReferenceList(new ReferenceList());
160        } catch (ForbiddenException e2) {
161            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
162            return (new ObjectFactory()).createReferenceList(new ReferenceList());
163        }
164    }
165
166    private class GetTargetList implements ILambda<Map, ReferenceList> {
167
168        @Override
169        public ReferenceList apply(Map params) throws NotInDataBaseException {
170            return dbDispatcher.getAnnotationTargets((Number) params.get("internalID"));
171        }
172    }
173
174    /**
175     *
176     * @param link the link representing one of the target sources of the annotation.
177     * @param matchMode the relation of the actual target-source link to "link" parameter: "exact", "starts_with", "ends_with", "contains"
178     * @param text the text fragment that must be present in the annotation body.
179     * @param access the access mode of the logged in user to the requested annotations.
180     * @param namespace not implemented.
181     * @param ownerExternalId the external UUID of the owner of requested annotations.
182     * @param after the minimal creation/update date of the annotation.
183     * @param before the maximal creation/update date of the annotation.
184     * @return the xml-element representing the list of {@link AnnotationInfo} objects representing
185     * the annotations satisfying the requirements defined by the parameters.
186     * @throws IOException if sending the error fails.
187     */
188    @GET
189    @Produces(MediaType.TEXT_XML)
190    @Path("")
191    @Transactional(readOnly = true)
192    public JAXBElement<AnnotationInfoList> getFilteredAnnotations(@QueryParam("link") String link,
193            @QueryParam("matchMode") String matchMode,
194            @QueryParam("text") String text,
195            @QueryParam("access") String access,
196            @QueryParam("namespace") String namespace,
197            @QueryParam("owner") String ownerExternalId,
198            @QueryParam("after") String after,
199            @QueryParam("before") String before) throws IOException {
200
201        Number principalID = this.getPrincipalID();
202        if (principalID == null) {
203            return new ObjectFactory().createAnnotationInfoList(new AnnotationInfoList());
204        }
205       
206         if (matchMode == null) {
207            matchMode = defaultMatchMode;
208        }
209        if (!Arrays.asList(admissibleMatchModes).contains(matchMode)) {
210            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "ivalide match mode " + matchMode);
211            return new ObjectFactory().createAnnotationInfoList(new AnnotationInfoList());
212        }
213
214        UUID ownerExternalUUID = (ownerExternalId != null) ? UUID.fromString(ownerExternalId) : null;
215       
216       
217        if (access == null) {
218            access = defaultAccess;
219        }
220        if (!Arrays.asList(admissibleAccess).contains(access)) {
221            this.INVALID_ACCESS_MODE(access);
222            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "ivalide mode acess " + access);
223            return new ObjectFactory().createAnnotationInfoList(new AnnotationInfoList());
224        }
225       
226       
227        try {
228            final AnnotationInfoList annotationInfoList = dbDispatcher.getFilteredAnnotationInfos(ownerExternalUUID, link, MatchMode.valueOf(matchMode.toUpperCase()), text, principalID, access, namespace, after, before);
229            return new ObjectFactory().createAnnotationInfoList(annotationInfoList);
230        } catch (NotInDataBaseException e) {
231            loggerServer.debug(e.toString());
232            httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
233            return new ObjectFactory().createAnnotationInfoList(new AnnotationInfoList());
234        }
235    }
236   
237    /**
238     *
239     * @param n # of requested annotations (to which logged in principal has "read" access.
240     * @return the external UUIDs of some n annotations to which the logged in principal has "read" access,
241     * if the principal has "admin" or "developer" type of account.
242     * @throws IOException if sending the error fails.
243     * @throws NotInDataBaseException if getting annotation fails.
244     */
245    @GET
246    @Produces(MediaType.TEXT_PLAIN)
247    @Path("stressTest")
248    @Transactional(readOnly = true)
249    public String getAnnotationsMultithread(@QueryParam("n") int n) throws IOException, NotInDataBaseException {
250        Number remotePrincipalID = this.getPrincipalID();
251        if (remotePrincipalID == null) {
252            return "You are not logged in";
253        }
254        String typeOfAccount = dbDispatcher.getTypeOfPrincipalAccount(remotePrincipalID);
255        if (typeOfAccount.equals(admin) || typeOfAccount.equals(DebugResource.developer)) {
256           
257            System.out.print("Preparing the data: getting the list of all annotations, picking up "+n+" of them randomly, and initializing threads");           
258            final List<Number> annotationIDs = dbDispatcher.getFilteredAnnotationIDs(null, null, null, null, remotePrincipalID, "read", null, null, null);
259            final int size = annotationIDs.size();
260            List<GetThread> threads = new ArrayList<GetThread>(n);
261            Random rand = new Random();
262            for (int i=0; i<n; i++) {
263               int r = rand.nextInt(size);
264               String annotationExternalId = dbDispatcher.getResourceExternalIdentifier(annotationIDs.get(r), Resource.ANNOTATION).toString();
265               GetThread thread = new GetThread(this, annotationExternalId);
266               threads.add(thread);           
267            }
268                       
269            System.out.print("Running on getAnnotation(id) (no serialized output is shown to save time) on randomly selected annotation ids."); 
270            for (int i=0; i<n; i++) {
271               threads.get(i).run();           
272            }
273           
274            return "Stress-tested annotationrResource's getAnnotation(xxx): ok";
275        } else {
276            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
277            return "You cannot enjoy this priviledged service because youe are neither admin nor developer. Ask the admin for more priviledges";
278        }
279    }
280   
281   
282
283   /**
284    *
285    * @param externalIdentifier the external UUID of an annotation.
286    * @return the xml-element representing the list of permissions, i.e. pairs (principalId, accessMode),
287    * built upon the table "annotations_principals_accesses".
288    * @throws IOException if sending the error fails.
289    */
290    @GET
291    @Produces(MediaType.TEXT_XML)
292    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/permissions")
293    @Transactional(readOnly = true)
294    public JAXBElement<PermissionList> getAnnotationPermissions(@PathParam("annotationid") String externalIdentifier) throws IOException {
295        Map params = new HashMap();
296        try {
297            PermissionList result = (PermissionList) (new RequestWrappers(this)).wrapRequestResource(params, new GetPermissionList(), Resource.ANNOTATION, Access.READ, externalIdentifier);
298            if (result != null) {
299                return (new ObjectFactory()).createPermissionList(result);
300            } else {
301                return (new ObjectFactory()).createPermissionList(new PermissionList());
302            }
303        } catch (NotInDataBaseException e1) {
304            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
305            return (new ObjectFactory()).createPermissionList(new PermissionList());
306        } catch (ForbiddenException e2) {
307            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
308            return (new ObjectFactory()).createPermissionList(new PermissionList());
309        }
310    }
311
312    private class GetPermissionList implements ILambda<Map, PermissionList> {
313
314        @Override
315        public PermissionList apply(Map params) throws NotInDataBaseException {
316            return dbDispatcher.getPermissions((Number) params.get("internalID"), (Resource) params.get("resourceType"));
317        }
318    }
319
320    /**
321     *
322     * @param externalIdentifier the external UUID of the annotation to be deleted.
323     * @return the message if the annotation is deleted or not.
324     * @throws IOException if sending the error fails.
325     */
326    @DELETE
327    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}")
328    public String deleteAnnotation(@PathParam("annotationid") String externalIdentifier) throws IOException {
329        Map params = new HashMap();
330        try {
331            int[] result = (int[]) (new RequestWrappers(this)).wrapRequestResource(params, new DeleteAnnotation(), Resource.ANNOTATION, Access.ALL, externalIdentifier);
332            if (result != null) {
333                return result[0] + " annotation(s) is(are) deleted.";
334            } else {
335                return "Nothing is deleted.";
336            }
337        } catch (NotInDataBaseException e1) {
338            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
339            return e1.getMessage();
340        } catch (ForbiddenException e2) {
341            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
342            return e2.getMessage();
343        }
344    }
345
346    private class DeleteAnnotation implements ILambda<Map, int[]> {
347
348        @Override
349        public int[] apply(Map params) throws NotInDataBaseException {
350            return dbDispatcher.deleteAnnotation((Number) params.get("internalID"));
351        }
352    }
353
354    /**
355     *
356     * @param annotation an {@link Annotation} object,
357     * @return the {@link ResponseBody} element that contains the xml element representing
358     * the fresh annotation (with its generated by the method external UUID), and the list
359     * of action-elements representing the actions the client should care for,
360     * e.g. add a cached representation for a certain target.
361     * @throws IOException if sending the error fails.
362     */
363    @POST
364    @Consumes(MediaType.APPLICATION_XML)
365    @Produces(MediaType.APPLICATION_XML)
366    @Path("")
367    public JAXBElement<ResponseBody> createAnnotation(Annotation annotation) throws IOException {
368
369        Map params = new HashMap();
370        params.put("annotation", annotation);
371        try {
372            ResponseBody result = (ResponseBody) (new RequestWrappers(this)).wrapRequestResource(params, new AddAnnotation());
373            if (result != null) {
374                return (new ObjectFactory()).createResponseBody(result);
375            } else {
376                return (new ObjectFactory()).createResponseBody(new ResponseBody());
377            }
378        } catch (NotInDataBaseException e) {
379            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
380            return (new ObjectFactory()).createResponseBody(new ResponseBody());
381        } catch (ForbiddenException e2) {
382            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
383            return (new ObjectFactory()).createResponseBody(new ResponseBody());
384        }
385    }
386
387    private class AddAnnotation implements ILambda<Map, ResponseBody> {
388
389        @Override
390        public ResponseBody apply(Map params) throws NotInDataBaseException {
391            Number principalID = (Number) params.get("principalID");
392            Annotation annotation = (Annotation) params.get("annotation");
393            Number annotationID = dbDispatcher.addPrincipalsAnnotation(principalID, annotation);
394            return dbDispatcher.makeAnnotationResponseEnvelope(annotationID);
395        }
396    }
397
398   /**
399    *
400    * @param externalId the external UUID of the annotation to be updated.
401    * @param annotation the {@link Annotation} object that represent the new annotation that should replace the annotation with "externalId".
402    * @return the {@link ResponseBody} element that contains the xml element representing
403     * the updated annotation, and the list of action-elements representing the actions the client should care for,
404     * e.g. add a cached representation for a certain target.
405     * @throws IOException if sending the error fails.
406    */
407    @PUT
408    @Consumes(MediaType.APPLICATION_XML)
409    @Produces(MediaType.APPLICATION_XML)
410    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}")
411    public JAXBElement<ResponseBody> updateAnnotation(@PathParam("annotationid") String externalId, Annotation annotation) throws IOException {
412
413        String annotationExtId = annotation.getId();
414        if (!(externalId).equals(annotationExtId)) {
415            loggerServer.debug("Wrong request: the annotation identifier   " + externalId + " and the annotation (notebook) ID from the request body do not match.");
416            httpServletResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
417            return null;
418        }
419        try {
420            Map params = new HashMap();           
421            params.put("annotation", annotation);
422            params.put("remoteUser",httpServletRequest.getRemoteUser()); 
423            ResponseBody result = (ResponseBody) (new RequestWrappers(this)).wrapRequestResource(params, new UpdateAnnotation(), Resource.ANNOTATION, Access.WRITE, externalId);
424            if (result != null) {
425                return (new ObjectFactory()).createResponseBody(result);
426            }
427            else {
428                return (new ObjectFactory()).createResponseBody(new ResponseBody());
429            }
430        } catch (NotInDataBaseException e1) {
431            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
432            return (new ObjectFactory()).createResponseBody(new ResponseBody());
433        } catch (ForbiddenException e2) {
434            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
435            return (new ObjectFactory()).createResponseBody(new ResponseBody());
436        }
437    }
438
439   
440    private class UpdateAnnotation implements ILambda<Map, ResponseBody> {
441
442        @Override 
443        public ResponseBody apply(Map params) throws NotInDataBaseException, ForbiddenException {
444            Annotation annotation = (Annotation) params.get("annotation");
445            Number annotationID = (Number) params.get("internalID");
446            String remoteUser = (String) params.get("remoteUser");
447            int updatedRows = dbDispatcher.updateAnnotation(annotation, remoteUser);
448            return dbDispatcher.makeAnnotationResponseEnvelope(annotationID);
449        }
450    }
451   
452   /**
453    *
454    * @param externalIdentifier the external UUID of the annotation whose body must be updated.
455    * @param annotationBody an {@link AnnotationBody} object representation the new body of the annotation,
456    * which should replace the old body.
457    * @return the {@link ResponseBody} element that contains the xml element representing
458    * the updated annotation, and the list of action-elements representing the actions the client should care for.
459    * @throws IOException if sending the error fails. 
460    */
461    @PUT
462    @Consumes(MediaType.APPLICATION_XML)
463    @Produces(MediaType.APPLICATION_XML)
464    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/body")
465    public JAXBElement<ResponseBody> updateAnnotationBody(@PathParam("annotationid") String externalIdentifier, AnnotationBody annotationBody) throws IOException {
466        Map params = new HashMap();
467        params.put("annotationBody", annotationBody);
468        try {
469            ResponseBody result = (ResponseBody) (new RequestWrappers(this)).wrapRequestResource(params, new UpdateAnnotationBody(), Resource.ANNOTATION, Access.WRITE, externalIdentifier);
470            if (result != null) {
471                return (new ObjectFactory()).createResponseBody(result);
472            } else {
473                return (new ObjectFactory()).createResponseBody(new ResponseBody());
474            }
475        } catch (NotInDataBaseException e1) {
476            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
477            return (new ObjectFactory()).createResponseBody(new ResponseBody());
478        } catch (ForbiddenException e2) {
479            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
480            return (new ObjectFactory()).createResponseBody(new ResponseBody());
481        }
482
483    }
484
485    ///////////////////////////////////////////////////////////
486    private class UpdateAnnotationBody implements ILambda<Map, ResponseBody> {
487
488        @Override
489        public ResponseBody apply(Map params) throws NotInDataBaseException {
490            Number resourceID = (Number) params.get("internalID");
491            AnnotationBody annotationBody = (AnnotationBody) params.get("annotationBody");
492            int updatedRows = dbDispatcher.updateAnnotationBody(resourceID, annotationBody);
493            return dbDispatcher.makeAnnotationResponseEnvelope(resourceID);
494        }
495    }
496
497    /**
498     *
499     * @param externalIdentifier the external UUID of the annotation whose headline is to be updated.
500     * @param newHeadline the string representing the new headline.
501     * @return the {@link ResponseBody} element that contains the xml element representing
502     * the updated annotation, and the list of action-elements representing the actions the client should care for.
503     * @throws IOException if sending the error fails. 
504     */
505    @PUT
506    @Consumes(MediaType.TEXT_PLAIN)
507    @Produces(MediaType.APPLICATION_XML)
508    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/headline")
509    public JAXBElement<ResponseBody> updateAnnotationHeadline(@PathParam("annotationid") String externalIdentifier, String newHeadline) throws IOException {
510        Map params = new HashMap();
511        params.put("headline", newHeadline);
512        try {
513            ResponseBody result = (ResponseBody) (new RequestWrappers(this)).wrapRequestResource(params, new UpdateAnnotationHeadline(), Resource.ANNOTATION, Access.WRITE, externalIdentifier);
514            if (result != null) {
515                return (new ObjectFactory()).createResponseBody(result);
516            } else {
517                return (new ObjectFactory()).createResponseBody(new ResponseBody());
518            }
519        } catch (NotInDataBaseException e1) {
520            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
521            return (new ObjectFactory()).createResponseBody(new ResponseBody());
522        } catch (ForbiddenException e2) {
523            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
524            return (new ObjectFactory()).createResponseBody(new ResponseBody());
525        }
526
527    }
528
529    ///////////////////////////////////////////////////////////
530    private class UpdateAnnotationHeadline implements ILambda<Map, ResponseBody> {
531
532        @Override
533        public ResponseBody apply(Map params) throws NotInDataBaseException {
534            Number resourceID = (Number) params.get("internalID");
535            String newHeadline = (String) params.get("headline");
536            int updatedRows = dbDispatcher.updateAnnotationHeadline(resourceID, newHeadline);
537            return dbDispatcher.makeAnnotationResponseEnvelope(resourceID);
538        }
539    }
540
541   /**
542    *
543    * @param annotationDatabaseId the internal database Id of the annotation to be updated.
544    * @param annotationHeadline the annotation's headline.
545    * @param access the new value for the public attribute of the annotation.
546    * @return the message if the database has been updated and how many rows have been updated;
547    * if "annotationDatabaseId" == null or empty then all the annotations with "annotationHeadline"
548    * must be updated,
549    * @throws IOException if sending the error fails.
550    */
551    @POST
552    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
553    @Produces(MediaType.TEXT_PLAIN)
554    @Path("publicaccessform")
555    public String updatePubliAccessFromForm(
556            @FormParam("annotationId") String annotationDatabaseId,
557            @FormParam("annotationHeadline") String annotationHeadline,
558            @FormParam("access") String access)
559            throws IOException {
560
561        if (access.trim().equals("")) {
562            access = "none";
563        }
564
565        try {
566
567            Access accessTyped = Access.fromValue(access);
568            if (annotationDatabaseId == null || annotationDatabaseId.trim().equals("")) {
569                List<UUID> annotationIds = dbDispatcher.getAnnotationExternalIdsFromHeadline(annotationHeadline);
570                if (annotationIds == null || annotationIds.isEmpty()) {
571                    httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "No annotations with this headline have been found");
572                    return "No annotations with this headline have been found";
573                };
574                int updatedAnnotations = 0;           
575                for (UUID annotationId : annotationIds) {
576                    Map params = new HashMap();
577                    params.put("access", accessTyped);
578                    Integer result = (Integer) (new RequestWrappers(this)).wrapRequestResource(params, new UpdatePublicAccess(), Resource.ANNOTATION, Access.ALL, annotationId.toString());
579                    updatedAnnotations = (result != null) ? updatedAnnotations + result.intValue() : updatedAnnotations;
580                }
581                return (updatedAnnotations + " row(s) are updated");
582            } else {
583                Map params = new HashMap();
584                params.put("access", accessTyped);
585                Integer result = (Integer) (new RequestWrappers(this)).wrapRequestResource(params, new UpdatePublicAccess(), Resource.ANNOTATION, Access.ALL, annotationDatabaseId);
586                if (result != null) {
587                    return result + " row(s) is(are) updated.";
588                } else {
589                    return "0 rows are updated.";
590                }
591            }
592        } catch (NotInDataBaseException e1) {
593            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.toString());
594            return "0 rows are updated.";
595        } catch (ForbiddenException e2) {
596            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.toString());
597            return "0 rows are updated.";
598        }
599    }
600
601    private class UpdatePublicAccess implements ILambda<Map, Integer> {
602
603        @Override
604        public Integer apply(Map params) throws NotInDataBaseException {
605            Number annotationID = (Number) params.get("internalID");
606            Access access = (Access) params.get("access");
607            return dbDispatcher.updatePublicAttribute(annotationID, access);
608        }
609    }
610
611    /**
612     *
613     * @param annotationExternalId the external UUID of an annotation.
614     * @param principalExternalId the external UUID of a principal whose access mode to the annotation must be updated.
615     * @param access the access mode that should assigned to the principal.
616     * @return the message about the amount of updated rows.
617     * @throws IOException if sending the error fails.
618     */
619    @PUT
620    @Consumes(MediaType.APPLICATION_XML)
621    @Produces(MediaType.APPLICATION_XML)
622    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/permissions/{principalid: " + BackendConstants.regExpIdentifier + "}")
623    public String updatePermission(@PathParam("annotationid") String annotationExternalId,
624            @PathParam("principalid") String principalExternalId, Access access) throws IOException {
625        try {
626            return this.genericUpdateDeletePermission(annotationExternalId, principalExternalId, access);
627        } catch (NotInDataBaseException e1) {
628            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
629            return e1.getMessage();
630        } catch (ForbiddenException e2) {
631            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
632            return e2.getMessage();
633        }
634    }
635
636    /**
637     * One of 3 principal-related parameters must be non-null and non-empty; one of 2 annotation related parameters must be non-null and non-empty.
638     * @param remoteID the remote ID of the principal whose access mode to the annotation (see below) must be updated.
639     * @param fullName the full name of the principal whose access mode to the annotation must be updated.
640     * @param principalDatabaseId the internal database identifier of the principal whose access mode to the annotation must be updated.
641     * @param annotationDatabaseId the internal database id of the annotation for which the access mode must be updated.
642     * @param annotationHeadline the headline of the annotation for which the access mode must be updated.
643     * @param access the new access mode.
644     * @return the message explaining how many rows have been updated.
645     * @throws IOException  if sending error message fails.
646     */
647    @POST
648    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
649    @Produces(MediaType.TEXT_PLAIN)
650    @Path("permissionform")
651    public String updatePermissionFromForm(@FormParam("login") String remoteID,
652            @FormParam("fullName") String fullName,
653            @FormParam("userId") String principalDatabaseId,
654            @FormParam("annotationId") String annotationDatabaseId,
655            @FormParam("annotationHeadline") String annotationHeadline,
656            @FormParam("access") String access)
657            throws IOException {
658
659        try {
660
661            if (access.trim().equals("")) {
662                access = null;
663            }
664
665            if (principalDatabaseId == null || principalDatabaseId.trim().equals("")) {
666                if (remoteID != null && !remoteID.trim().equals("")) {
667                    principalDatabaseId = dbDispatcher.getPrincipalExternalIDFromRemoteID(remoteID).toString();
668                } else {
669                    if (fullName != null) {
670                        principalDatabaseId = dbDispatcher.getPrincipalExternalIdFromName(fullName).toString();
671                    } else {
672                        httpServletResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "No user information is given");
673                    }
674                }
675            }
676
677            if (annotationDatabaseId == null || annotationDatabaseId.trim().equals("")) {
678                List<UUID> annotationIds = dbDispatcher.getAnnotationExternalIdsFromHeadline(annotationHeadline);
679                if (annotationIds == null || annotationIds.isEmpty()) {
680                    return "No annotations with this headline found";
681                };
682                int count = 0;
683                String tmp = null;
684                for (UUID annotationId : annotationIds) {
685                    tmp = this.genericUpdateDeletePermission(annotationId.toString(), principalDatabaseId, Access.fromValue(access));
686                    if (!tmp.startsWith("0")) {
687                        count++;
688                    }
689                }
690                return (count + " row(s) are updated");
691            } else {
692                return this.genericUpdateDeletePermission(annotationDatabaseId, principalDatabaseId, Access.fromValue(access));
693            }
694
695        } catch (NotInDataBaseException e1) {
696            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
697            return e1.getMessage();
698        } catch (ForbiddenException e2) {
699            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
700            return e2.getMessage();
701        }
702    }
703
704    ////////////////////////////////////////////
705    private String genericUpdateDeletePermission(String annotationId, String principalId, Access access) throws IOException, NotInDataBaseException, ForbiddenException {
706        Map params = new HashMap();
707        params.put("access", access);
708        final Number inputPrincipalID = dbDispatcher.getResourceInternalIdentifier(UUID.fromString(principalId), Resource.PRINCIPAL);
709        params.put("inputPrincipalID", inputPrincipalID);
710        Integer result = (Integer) (new RequestWrappers(this)).wrapRequestResource(params, new UpdatePermissionHelper(), Resource.ANNOTATION, Access.ALL, annotationId);
711        if (result != null) {
712            return result + " row(s) is(are) updated.";
713        } else {
714            return "0 rows are updated.";
715        }
716    }
717
718    private class UpdatePermissionHelper implements ILambda<Map, Integer> {
719
720        @Override
721        public Integer apply(Map params) throws NotInDataBaseException {
722            Number annotationID = (Number) params.get("internalID");
723            Number principalID = (Number) params.get("inputPrincipalID");
724            Access access = (Access) params.get("access");
725            return dbDispatcher.updatePermission(annotationID, principalID, access);
726        }
727    }
728   
729   
730    /**
731     *
732     * @param annotationExternalId the external UUID of an annotation.
733     * @param permissions a {@link PermissionList} object representing a list of pairs (principal UUID, access mode) of the
734     * new list of permissions for the annotation.
735     * @return the {@link ResponseBody} element that contains the xml element representing
736     * the updated annotation, and the list of action-elements representing the actions the client should care for,
737     * e.g. add the e-mail of a certain principal.
738     * @throws IOException if sending the error fails.
739     */
740    @PUT
741    @Consumes(MediaType.APPLICATION_XML)
742    @Produces(MediaType.APPLICATION_XML)
743    @Path("{annotationid: " + BackendConstants.regExpIdentifier + "}/permissions/")
744    public JAXBElement<ResponseBody> updatePermissions(@PathParam("annotationid") String annotationExternalId, PermissionList permissions) throws IOException {
745
746        Map params = new HashMap();
747        params.put("permissions", permissions);
748        try {
749            ResponseBody result = (ResponseBody) (new RequestWrappers(this)).wrapRequestResource(params, new UpdatePermissions(), Resource.ANNOTATION, Access.ALL, annotationExternalId);
750            if (result != null) {
751                return new ObjectFactory().createResponseBody(result);
752            } else {
753                return new ObjectFactory().createResponseBody(new ResponseBody());
754            }
755        } catch (NotInDataBaseException e1) {
756            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
757            return new ObjectFactory().createResponseBody(new ResponseBody());
758        } catch (ForbiddenException e2) {
759            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
760            return new ObjectFactory().createResponseBody(new ResponseBody());
761        }
762
763    }
764
765    ////////////////////////////////////////////
766    private class UpdatePermissions implements ILambda<Map, ResponseBody> {
767
768        @Override
769        public ResponseBody apply(Map params) throws NotInDataBaseException {
770            Number annotationID = (Number) params.get("internalID");
771            PermissionList permissions = (PermissionList) params.get("permissions");
772            int updatedRows = dbDispatcher.updateOrAddPermissions(annotationID, permissions);
773            return dbDispatcher.makeAccessResponseEnvelope(annotationID, Resource.ANNOTATION);
774        }
775    }
776
777    /**
778     *
779     * @param annotationId the external UUID of the annotation.
780     * @param principalId the external UUID of a principal whose access mode must be deleted.
781     * @return the amount of updated/removed rows in the database.
782     * @throws IOException if sending the error fails.
783     */
784    @DELETE
785    @Produces(MediaType.TEXT_PLAIN)
786    @Path("{annotationId: " + BackendConstants.regExpIdentifier + "}/principal/{principalId}/delete")
787    public String deletePermission(@PathParam("annotationId") String annotationId,
788            @PathParam("principalId") String principalId) throws IOException {
789        try {
790            return this.genericUpdateDeletePermission(annotationId, principalId, null);
791        } catch (NotInDataBaseException e1) {
792            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, e1.getMessage());
793            return e1.getMessage();
794        } catch (ForbiddenException e2) {
795            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e2.getMessage());
796            return e2.getMessage();
797        }
798    }
799   
800   
801}
Note: See TracBrowser for help on using the repository browser.