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

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

Javadoc annotations are completed.

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