source: ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/rest/ComponentRegistryRestService.java @ 3449

Last change on this file since 3449 was 3449, checked in by George.Georgovassilis@mpi.nl, 11 years ago

#360 Refactoring of transaction handling, tests and application context

File size: 52.3 KB
Line 
1package clarin.cmdi.componentregistry.rest;
2
3import clarin.cmdi.componentregistry.AllowedAttributetypesXML;
4import clarin.cmdi.componentregistry.ComponentRegistry;
5import clarin.cmdi.componentregistry.ComponentRegistryException;
6import clarin.cmdi.componentregistry.ComponentRegistryFactory;
7import clarin.cmdi.componentregistry.ComponentStatus;
8import clarin.cmdi.componentregistry.DeleteFailedException;
9import clarin.cmdi.componentregistry.MDMarshaller;
10import clarin.cmdi.componentregistry.Owner;
11import clarin.cmdi.componentregistry.UserCredentials;
12import clarin.cmdi.componentregistry.UserUnauthorizedException;
13import clarin.cmdi.componentregistry.components.CMDComponentSpec;
14import clarin.cmdi.componentregistry.components.CMDComponentType;
15import clarin.cmdi.componentregistry.model.AbstractDescription;
16import clarin.cmdi.componentregistry.model.Comment;
17import clarin.cmdi.componentregistry.model.CommentResponse;
18import clarin.cmdi.componentregistry.model.ComponentDescription;
19import clarin.cmdi.componentregistry.model.ProfileDescription;
20import clarin.cmdi.componentregistry.model.RegisterResponse;
21import clarin.cmdi.componentregistry.rss.Rss;
22import clarin.cmdi.componentregistry.rss.RssCreatorComments;
23import clarin.cmdi.componentregistry.rss.RssCreatorDescriptions;
24
25import com.sun.jersey.api.core.InjectParam;
26import com.sun.jersey.multipart.FormDataParam;
27
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
31import java.net.URI;
32import java.security.Principal;
33import java.text.ParseException;
34import java.util.ArrayList;
35import java.util.Arrays;
36import java.util.List;
37
38import javax.servlet.ServletContext;
39import javax.servlet.http.HttpServletRequest;
40import javax.ws.rs.Consumes;
41import javax.ws.rs.DELETE;
42import javax.ws.rs.DefaultValue;
43import javax.ws.rs.FormParam;
44import javax.ws.rs.GET;
45import javax.ws.rs.POST;
46import javax.ws.rs.Path;
47import javax.ws.rs.PathParam;
48import javax.ws.rs.Produces;
49import javax.ws.rs.QueryParam;
50import javax.ws.rs.WebApplicationException;
51import javax.ws.rs.core.Context;
52import javax.ws.rs.core.MediaType;
53import javax.ws.rs.core.Response;
54import javax.ws.rs.core.Response.Status;
55import javax.ws.rs.core.SecurityContext;
56import javax.ws.rs.core.StreamingOutput;
57import javax.ws.rs.core.UriInfo;
58import javax.xml.bind.JAXBException;
59
60import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62import org.springframework.stereotype.Component;
63import org.springframework.stereotype.Service;
64import org.springframework.transaction.annotation.Transactional;
65
66/**
67 * Handles CRUD operations on {@link ComponentDescription}, {@link ProfileDescription} and {@link Comment}s
68 * @author george.georgovassilis@mpi.nl
69 *
70 */
71@Path("/registry")
72@Service
73public class ComponentRegistryRestService implements
74                IComponentRegistryRestService {
75
76        private final static Logger LOG = LoggerFactory
77                        .getLogger(IComponentRegistryRestService.class);
78        @Context
79        private UriInfo uriInfo;
80        @Context
81        private SecurityContext security;
82        @Context
83        private HttpServletRequest request;
84        @Context
85        private ServletContext servletContext;
86        @InjectParam(value = "componentRegistryFactory")
87        private ComponentRegistryFactory componentRegistryFactory;
88        @InjectParam(value = "mdMarshaller")
89        private MDMarshaller marshaller;
90
91        /**
92         * Converts userspace boolean to component status. Temporary solution!!!
93         *
94         * TODO: Replace all calls to getRegistry that use this by calls using
95         * ComponentStatus
96         *
97         *
98         *
99         * @param userSpace
100         * @return
101         * @deprecated All calls should go directly to
102         *             {@link #getRegistry(clarin.cmdi.componentregistry.ComponentStatus)}
103         */
104        @Deprecated
105        private static ComponentStatus getStatus(boolean userSpace) {
106                if (userSpace) {
107                        return ComponentStatus.PRIVATE;
108                } else {
109                        return ComponentStatus.PUBLISHED;
110                }
111        }
112
113        private ComponentRegistry getRegistry(ComponentStatus status) {
114                Principal userPrincipal = security.getUserPrincipal();
115                UserCredentials userCredentials = getUserCredentials(userPrincipal);
116                return getRegistry(status, null, userCredentials);
117        }
118
119        private ComponentRegistry getRegistry(ComponentStatus status, Owner owner,
120                        UserCredentials userCredentials) {
121                try {
122                        return componentRegistryFactory.getComponentRegistry(status, owner,
123                                        userCredentials);
124                } catch (UserUnauthorizedException uuEx) {
125                        LOG.warn("Unauthorized access to {} registry by user {}", status,
126                                        userCredentials);
127                        LOG.debug("Details for unauthorized access", uuEx);
128                        throw new WebApplicationException(uuEx, Status.UNAUTHORIZED);
129                }
130        }
131
132        /**
133         *
134         * @return Principal of current request
135         * @throws IllegalArgumentException
136         *             If no user principal found
137         */
138        private Principal checkAndGetUserPrincipal()
139                        throws UserUnauthorizedException {
140                Principal principal = security.getUserPrincipal();
141                if (principal == null) {
142                        throw new UserUnauthorizedException("no user principal found.");
143                }
144                return principal;
145        }
146
147        private UserCredentials getUserCredentials(Principal userPrincipal) {
148                UserCredentials userCredentials = null;
149                if (userPrincipal != null) {
150                        userCredentials = new UserCredentials(userPrincipal);
151                }
152                return userCredentials;
153        }
154       
155        @Override
156        @GET
157        @Path("/components")
158        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
159                        MediaType.APPLICATION_JSON })
160        public List<ComponentDescription> getRegisteredComponents(
161                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
162                        throws ComponentRegistryException {
163                long start = System.currentTimeMillis();
164                List<ComponentDescription> components = getRegistry(
165                                getStatus(userspace)).getComponentDescriptions();
166                LOG.debug(
167                                "Releasing {} registered components into the world ({} millisecs)",
168                                components.size(), (System.currentTimeMillis() - start));
169                return components;
170        }
171
172        @Override
173        @GET
174        @Path("/profiles")
175        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
176                        MediaType.APPLICATION_JSON })
177        public List<ProfileDescription> getRegisteredProfiles(
178                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
179                        @QueryParam(METADATA_EDITOR_PARAM) @DefaultValue("false") boolean metadataEditor)
180                        throws ComponentRegistryException {
181                long start = System.currentTimeMillis();
182
183                List<ProfileDescription> profiles;
184                if (metadataEditor) {
185                        profiles = getRegistry(getStatus(userspace))
186                                        .getProfileDescriptionsForMetadaEditor();
187                } else {
188                        profiles = getRegistry(getStatus(userspace))
189                                        .getProfileDescriptions();
190                }
191
192                LOG.debug(
193                                "Releasing {} registered profiles into the world ({} millisecs)",
194                                profiles.size(), (System.currentTimeMillis() - start));
195                return profiles;
196        }
197
198        @Override
199        @GET
200        @Path("/components/{componentId}")
201        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
202                        MediaType.APPLICATION_JSON })
203        public Response getRegisteredComponent(
204                        @PathParam("componentId") String componentId,
205                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
206                        throws ComponentRegistryException {
207                LOG.debug("Component with id: {} is requested.", componentId);
208                CMDComponentSpec mdComponent = getRegistry(getStatus(userspace))
209                                .getMDComponent(componentId);
210                if (mdComponent == null) {
211                        return Response.status(Status.NOT_FOUND).build();
212                } else {
213                        return Response.ok(mdComponent).build();
214                }
215        }
216
217        @Override
218        @GET
219        @Path("/components/{componentId}/{rawType}")
220        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML })
221        public Response getRegisteredComponentRawType(
222                        @PathParam("componentId") final String componentId,
223                        @PathParam("rawType") String rawType) {
224                LOG.debug("Component with id: {} and rawType: {} is requested.",
225                                componentId, rawType);
226                StreamingOutput result = null;
227                try {
228                        final ComponentRegistry registry = findRegistry(componentId,
229                                        new ComponentClosure());
230                        if (registry == null) {
231                                return Response
232                                                .status(Status.NOT_FOUND)
233                                                .entity("Id: " + componentId
234                                                                + " is not registered, cannot create data.")
235                                                .build();
236                        }
237                        ComponentDescription desc = registry
238                                        .getComponentDescription(componentId);
239                        checkAndThrowDescription(desc, componentId);
240                        String fileName = desc.getName() + "." + rawType;
241                        if ("xml".equalsIgnoreCase(rawType)) {
242                                result = new StreamingOutput() {
243                                        @Override
244                                        public void write(OutputStream output) throws IOException,
245                                                        WebApplicationException {
246                                                try {
247                                                        registry.getMDComponentAsXml(componentId, output);
248                                                } catch (ComponentRegistryException e) {
249                                                        LOG.warn("Could not retrieve component {}",
250                                                                        componentId);
251                                                        LOG.debug("Details", e);
252                                                        throw new WebApplicationException(e, Response
253                                                                        .serverError()
254                                                                        .status(Status.INTERNAL_SERVER_ERROR)
255                                                                        .build());
256                                                }
257                                        }
258                                };
259                        } else if ("xsd".equalsIgnoreCase(rawType)) {
260                                result = new StreamingOutput() {
261                                        @Override
262                                        public void write(OutputStream output) throws IOException,
263                                                        WebApplicationException {
264                                                try {
265                                                        registry.getMDComponentAsXsd(componentId, output);
266                                                } catch (ComponentRegistryException e) {
267                                                        LOG.warn("Could not retrieve component {}",
268                                                                        componentId);
269                                                        LOG.debug("Details", e);
270                                                        throw new WebApplicationException(e, Response
271                                                                        .serverError()
272                                                                        .status(Status.INTERNAL_SERVER_ERROR)
273                                                                        .build());
274                                                }
275
276                                        }
277                                };
278                        } else {
279                                throw new WebApplicationException(Response
280                                                .serverError()
281                                                .entity("unsupported rawType: " + rawType
282                                                                + " (only xml or xsd are supported)").build());
283                        }
284                        return createDownloadResponse(result, fileName);
285                } catch (ComponentRegistryException e) {
286                        LOG.warn("Could not retrieve component {}", componentId);
287                        LOG.debug("Details", e);
288                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
289                                        .build();
290                }
291        }
292
293        @Override
294        public ComponentRegistry findRegistry(String id,
295                        RegistryClosure<? extends AbstractDescription> clos)
296                        throws ComponentRegistryException {
297                AbstractDescription desc = null;
298                ComponentRegistry result = getRegistry(getStatus(false));
299                desc = clos.getDescription(result, id);
300                if (desc == null) {
301                        List<ComponentRegistry> userRegs = componentRegistryFactory
302                                        .getAllUserRegistries();
303                        for (ComponentRegistry reg : userRegs) {
304                                desc = clos.getDescription(reg, id);
305                                if (desc != null) {
306                                        result = reg;
307                                        break;
308                                }
309                        }
310                }
311                return result;
312        }
313
314        @Override
315        @GET
316        @Path("/profiles/{profileId}")
317        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
318                        MediaType.APPLICATION_JSON })
319        public Response getRegisteredProfile(
320                        @PathParam("profileId") String profileId,
321                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
322                        throws ComponentRegistryException {
323                LOG.debug("Profile with id {} is requested.", profileId);
324                CMDComponentSpec mdProfile = getRegistry(getStatus(userspace))
325                                .getMDProfile(profileId);
326                if (mdProfile == null) {
327                        return Response.status(Status.NOT_FOUND).build();
328                } else {
329                        return Response.ok(mdProfile).build();
330                }
331        }
332
333        @Override
334        @GET
335        @Path("/components/usage/{componentId}")
336        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
337                        MediaType.APPLICATION_JSON })
338        public List<AbstractDescription> getComponentUsage(
339                        @PathParam("componentId") String componentId,
340                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
341                        throws ComponentRegistryException {
342                try {
343                        final long start = System.currentTimeMillis();
344                        ComponentRegistry registry = getRegistry(getStatus(userspace));
345                        List<ComponentDescription> components = registry
346                                        .getUsageInComponents(componentId);
347                        List<ProfileDescription> profiles = registry
348                                        .getUsageInProfiles(componentId);
349
350                        LOG.debug(
351                                        "Found {} components and {} profiles that use component {} ({} millisecs)",
352                                        components.size(), profiles.size(), componentId,
353                                        (System.currentTimeMillis() - start));
354
355                        List<AbstractDescription> usages = new ArrayList<AbstractDescription>(
356                                        components.size() + profiles.size());
357                        usages.addAll(components);
358                        usages.addAll(profiles);
359
360                        return usages;
361                } catch (ComponentRegistryException e) {
362                        LOG.warn("Could not retrieve profile usage {}", componentId);
363                        LOG.debug("Details", e);
364                        throw e;
365                }
366        }
367
368        @Override
369        @GET
370        @Path("/profiles/{profileId}/comments")
371        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
372                        MediaType.APPLICATION_JSON })
373        public List<Comment> getCommentsFromProfile(
374                        @PathParam("profileId") String profileId,
375                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
376                        throws ComponentRegistryException {
377                long start = System.currentTimeMillis();
378                final Principal principal = security.getUserPrincipal();
379                List<Comment> comments = getRegistry(getStatus(userspace))
380                                .getCommentsInProfile(profileId, principal);
381                LOG.debug(
382                                "Releasing {} registered comments in profile into the world ({} millisecs)",
383                                comments.size(), (System.currentTimeMillis() - start));
384                return comments;
385        }
386
387        @Override
388        @GET
389        @Path("/components/{componentId}/comments")
390        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
391                        MediaType.APPLICATION_JSON })
392        public List<Comment> getCommentsFromComponent(
393                        @PathParam("componentId") String componentId,
394                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
395                        throws ComponentRegistryException {
396                long start = System.currentTimeMillis();
397                final Principal principal = security.getUserPrincipal();
398                List<Comment> comments = getRegistry(getStatus(userspace))
399                                .getCommentsInComponent(componentId, principal);
400                LOG.debug(
401                                "Releasing {} registered comments in Component into the world ({} millisecs)",
402                                comments.size(), (System.currentTimeMillis() - start));
403                return comments;
404        }
405
406        @Override
407        @GET
408        @Path("/profiles/{profileId}/comments/{commentId}")
409        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
410                        MediaType.APPLICATION_JSON })
411        public Comment getSpecifiedCommentFromProfile(
412                        @PathParam("profileId") String profileId,
413                        @PathParam("commentId") String commentId,
414                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
415                        throws ComponentRegistryException {
416                LOG.debug("Comments of profile with id {} are requested.", commentId);
417                final Principal principal = security.getUserPrincipal();
418                return getRegistry(getStatus(userspace)).getSpecifiedCommentInProfile(
419                                profileId, commentId, principal);
420        }
421
422        @Override
423        @GET
424        @Path("/components/{componentId}/comments/{commentId}")
425        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
426                        MediaType.APPLICATION_JSON })
427        public Comment getSpecifiedCommentFromComponent(
428                        @PathParam("componentId") String componentId,
429                        @PathParam("commentId") String commentId,
430                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
431                        throws ComponentRegistryException {
432                LOG.debug("Comments of component with id {} are requested.", commentId);
433                final Principal principal = security.getUserPrincipal();
434                return getRegistry(getStatus(userspace))
435                                .getSpecifiedCommentInComponent(componentId, commentId,
436                                                principal);
437        }
438
439        /**
440         *
441         * Purely helper method for my front-end (FLEX) which only does post/get
442         * requests. The query param is checked and the "proper" method is called.
443         *
444         * @param profileId
445         * @param method
446         * @return
447         */
448        @Override
449        @POST
450        @Path("/profiles/{profileId}")
451        public Response manipulateRegisteredProfile(
452                        @PathParam("profileId") String profileId,
453                        @FormParam("method") String method,
454                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
455                if ("delete".equalsIgnoreCase(method)) {
456                        return deleteRegisteredProfile(profileId, userspace);
457                } else {
458                        return Response.ok().build();
459                }
460        }
461
462        @Override
463        @POST
464        @Path("/profiles/{profileId}/comments/{commentId}")
465        public Response manipulateCommentFromProfile(
466                        @PathParam("profileId") String profileId,
467                        @PathParam("commentId") String commentId,
468                        @FormParam("method") String method,
469                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
470                if ("delete".equalsIgnoreCase(method)) {
471                        return deleteCommentFromProfile(profileId, commentId, userspace);
472                } else {
473                        return Response.ok().build();
474                }
475        }
476
477        @Override
478        @POST
479        @Path("/components/{componentId}/comments/{commentId}")
480        public Response manipulateCommentFromComponent(
481                        @PathParam("componentId") String componentId,
482                        @PathParam("commentId") String commentId,
483                        @FormParam("method") String method,
484                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
485                if ("delete".equalsIgnoreCase(method)) {
486                        return deleteCommentFromComponent(componentId, commentId, userspace);
487                } else {
488                        return Response.ok().build();
489                }
490        }
491
492        @Override
493        @POST
494        @Path("/profiles/{profileId}/publish")
495        @Consumes("multipart/form-data")
496        public Response publishRegisteredProfile(
497                        @PathParam("profileId") String profileId,
498                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
499                        @FormDataParam(NAME_FORM_FIELD) String name,
500                        @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
501                        @FormDataParam(GROUP_FORM_FIELD) String group,
502                        @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
503                try {
504                        Principal principal = checkAndGetUserPrincipal();
505                        ProfileDescription desc = getRegistry(getStatus(true))
506                                        .getProfileDescription(profileId);
507                        if (desc != null) {
508                                updateDescription(desc, name, description, domainName, group);
509                                return register(input, desc, getUserCredentials(principal),
510                                                true, new PublishAction(principal));
511                        } else {
512                                LOG.error("Update of nonexistent profile {} failed.", profileId);
513                                return Response
514                                                .serverError()
515                                                .entity("Invalid id, cannot update nonexistent profile")
516                                                .build();
517                        }
518                } catch (ComponentRegistryException e) {
519                        LOG.warn("Could not retrieve profile {}", profileId);
520                        LOG.debug("Details", e);
521                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
522                                        .build();
523                } catch (UserUnauthorizedException ex) {
524                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
525                                        .build();
526                }
527        }
528
529        @Override
530        @POST
531        @Path("/profiles/{profileId}/update")
532        @Consumes("multipart/form-data")
533        public Response updateRegisteredProfile(
534                        @PathParam("profileId") String profileId,
535                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
536                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
537                        @FormDataParam(NAME_FORM_FIELD) String name,
538                        @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
539                        @FormDataParam(GROUP_FORM_FIELD) String group,
540                        @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
541                try {
542                        Principal principal = checkAndGetUserPrincipal();
543                        UserCredentials userCredentials = getUserCredentials(principal);
544                        ProfileDescription desc = getRegistry(getStatus(userspace))
545                                        .getProfileDescription(profileId);
546                        if (desc != null) {
547                                updateDescription(desc, name, description, domainName, group);
548                                return register(input, desc, userCredentials, userspace,
549                                                new UpdateAction(principal));
550                        } else {
551                                LOG.error("Update of nonexistent id (" + profileId
552                                                + ") failed.");
553                                return Response
554                                                .serverError()
555                                                .entity("Invalid id, cannot update nonexistent profile")
556                                                .build();
557                        }
558                } catch (ComponentRegistryException e) {
559                        LOG.warn("Could not retrieve profile {}", profileId);
560                        LOG.debug("Details", e);
561                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
562                                        .build();
563                } catch (UserUnauthorizedException ex) {
564                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
565                                        .build();
566                }
567
568        }
569
570        /**
571         *
572         * Purely helper method for my front-end (FLEX) which van only do post/get
573         * requests. The query param is checked and the "proper" method is called.
574         *
575         * @param componentId
576         * @param method
577         * @return
578         */
579        @Override
580        @POST
581        @Path("/components/{componentId}")
582        public Response manipulateRegisteredComponent(
583                        @PathParam("componentId") String componentId,
584                        @FormParam("method") String method,
585                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
586                if ("delete".equalsIgnoreCase(method)) {
587                        return deleteRegisteredComponent(componentId, userspace);
588                } else {
589                        return Response.ok().build();
590                }
591        }
592
593        @Override
594        @POST
595        @Path("/components/{componentId}/publish")
596        @Consumes("multipart/form-data")
597        public Response publishRegisteredComponent(
598                        @PathParam("componentId") String componentId,
599                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
600                        @FormDataParam(NAME_FORM_FIELD) String name,
601                        @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
602                        @FormDataParam(GROUP_FORM_FIELD) String group,
603                        @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
604                try {
605                        Principal principal = checkAndGetUserPrincipal();
606                        // TODO: Get status from parameter
607                        ComponentDescription desc = getRegistry(getStatus(true))
608                                        .getComponentDescription(componentId);
609                        if (desc != null) {
610                                updateDescription(desc, name, description, domainName, group);
611                                return register(input, desc, getUserCredentials(principal),
612                                                true, new PublishAction(principal));
613                        } else {
614                                LOG.error("Update of nonexistent id (" + componentId
615                                                + ") failed.");
616                                return Response
617                                                .serverError()
618                                                .entity("Invalid id, cannot update nonexistent profile")
619                                                .build();
620                        }
621                } catch (ComponentRegistryException e) {
622                        LOG.warn("Could not retrieve component {}", componentId);
623                        LOG.debug("Details", e);
624                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
625                                        .build();
626                } catch (UserUnauthorizedException ex) {
627                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
628                                        .build();
629                }
630        }
631
632        @Override
633        @POST
634        @Path("/components/{componentId}/update")
635        @Consumes("multipart/form-data")
636        public Response updateRegisteredComponent(
637                        @PathParam("componentId") String componentId,
638                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
639                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
640                        @FormDataParam(NAME_FORM_FIELD) String name,
641                        @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
642                        @FormDataParam(GROUP_FORM_FIELD) String group,
643                        @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
644                try {
645                        Principal principal = checkAndGetUserPrincipal();
646                        ComponentDescription desc = getRegistry(getStatus(userspace))
647                                        .getComponentDescription(componentId);
648                        if (desc != null) {
649                                updateDescription(desc, name, description, domainName, group);
650                                return register(input, desc, getUserCredentials(principal),
651                                                userspace, new UpdateAction(principal));
652                        } else {
653                                LOG.error("Update of nonexistent id (" + componentId
654                                                + ") failed.");
655                                return Response
656                                                .serverError()
657                                                .entity("Invalid id, cannot update nonexistent component")
658                                                .build();
659                        }
660                } catch (ComponentRegistryException e) {
661                        LOG.warn("Could not retrieve component {}", componentId);
662                        LOG.debug("Details", e);
663                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
664                                        .build();
665                } catch (UserUnauthorizedException ex) {
666                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
667                                        .build();
668                }
669        }
670
671        private void updateDescription(AbstractDescription desc, String name,
672                        String description, String domainName, String group) {
673                desc.setName(name);
674                desc.setDescription(description);
675                desc.setDomainName(domainName);
676                desc.setGroupName(group);
677                desc.setRegistrationDate(AbstractDescription.createNewDate());
678        }
679
680        @Override
681        @DELETE
682        @Path("/components/{componentId}")
683        public Response deleteRegisteredComponent(
684                        @PathParam("componentId") String componentId,
685                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
686                try {
687                        Principal principal = checkAndGetUserPrincipal();
688                        ComponentRegistry registry = getRegistry(getStatus(userspace));
689                        LOG.debug("Component with id {} set for deletion.", componentId);
690                        registry.deleteMDComponent(componentId, principal, false);
691                } catch (DeleteFailedException e) {
692                        LOG.info("Component with id {} deletion failed. Reason: {}",
693                                        componentId, e.getMessage());
694                        LOG.debug("Deletion failure details:", e);
695                        return Response.status(Status.FORBIDDEN)
696                                        .entity("" + e.getMessage()).build();
697                } catch (ComponentRegistryException e) {
698                        LOG.warn("Component with id " + componentId + " deletion failed.",
699                                        e);
700                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
701                                        .build();
702                } catch (IOException e) {
703                        LOG.error("Component with id " + componentId + " deletion failed.",
704                                        e);
705                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
706                                        .build();
707                } catch (UserUnauthorizedException e) {
708                        LOG.info("Component with id {} deletion failed: {}", componentId,
709                                        e.getMessage());
710                        LOG.debug("Deletion failure details:", e);
711                        return Response.serverError().status(Status.UNAUTHORIZED)
712                                        .entity("" + e.getMessage()).build();
713                }
714                LOG.info("Component with id: {} deleted.", componentId);
715                return Response.ok().build();
716        }
717
718        @Override
719        @DELETE
720        @Path("/profiles/{profileId}")
721        public Response deleteRegisteredProfile(
722                        @PathParam("profileId") String profileId,
723                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
724                try {
725                        Principal principal = checkAndGetUserPrincipal();
726                        LOG.debug("Profile with id: {} set for deletion.", profileId);
727                        getRegistry(getStatus(userspace)).deleteMDProfile(profileId,
728                                        principal);
729                } catch (DeleteFailedException e) {
730                        LOG.info("Profile with id: {} deletion failed: {}", profileId,
731                                        e.getMessage());
732                        LOG.debug("Deletion failure details:", e);
733                        return Response.serverError().status(Status.FORBIDDEN)
734                                        .entity("" + e.getMessage()).build();
735                } catch (ComponentRegistryException e) {
736                        LOG.warn("Could not retrieve component", e);
737                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
738                                        .build();
739                } catch (IOException e) {
740                        LOG.error("Profile with id: " + profileId + " deletion failed.", e);
741                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
742                                        .build();
743                } catch (UserUnauthorizedException e) {
744                        LOG.info("Profile with id: {} deletion failed: {}", profileId,
745                                        e.getMessage());
746                        LOG.debug("Deletion failure details:", e);
747                        return Response.serverError().status(Status.UNAUTHORIZED)
748                                        .entity("" + e.getMessage()).build();
749                }
750                LOG.info("Profile with id: {} deleted.", profileId);
751                return Response.ok().build();
752        }
753
754        @Override
755        @DELETE
756        @Path("/profiles/{profileId}/comments/{commentId}")
757        public Response deleteCommentFromProfile(
758                        @PathParam("profileId") String profileId,
759                        @PathParam("commentId") String commentId,
760                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
761                try {
762                        final Principal principal = checkAndGetUserPrincipal();
763                        final ComponentRegistry registry = getRegistry(getStatus(userspace));
764                        final Comment comment = registry.getSpecifiedCommentInProfile(
765                                        profileId, commentId, principal);
766                        if (comment != null
767                                        && profileId.equals(comment.getProfileDescriptionId())) {
768                                LOG.debug("Comment with id: {} set for deletion.", commentId);
769                                registry.deleteComment(commentId, principal);
770                        } else {
771                                throw new ComponentRegistryException(
772                                                "Comment not found for specified profile");
773                        }
774                } catch (DeleteFailedException e) {
775                        LOG.info("Comment with id: {} deletion failed: {}", commentId,
776                                        e.getMessage());
777                        LOG.debug("Deletion failure details:", e);
778                        return Response.serverError().status(Status.FORBIDDEN)
779                                        .entity("" + e.getMessage()).build();
780                } catch (ComponentRegistryException e) {
781                        LOG.info("Could not retrieve component", e);
782                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
783                                        .build();
784                } catch (IOException e) {
785                        LOG.error("Comment with id: " + commentId + " deletion failed.", e);
786                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
787                                        .build();
788                } catch (UserUnauthorizedException e) {
789                        LOG.info("Comment with id: {} deletion failed: {}", commentId,
790                                        e.getMessage());
791                        LOG.debug("Deletion failure details:", e);
792                        return Response.serverError().status(Status.UNAUTHORIZED)
793                                        .entity("" + e.getMessage()).build();
794                }
795                LOG.info("Comment with id: {} deleted.", commentId);
796                return Response.ok().build();
797        }
798
799        @Override
800        @DELETE
801        @Path("/components/{componentId}/comments/{commentId}")
802        public Response deleteCommentFromComponent(
803                        @PathParam("componentId") String componentId,
804                        @PathParam("commentId") String commentId,
805                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
806                try {
807                        final Principal principal = checkAndGetUserPrincipal();
808                        final ComponentRegistry registry = getRegistry(getStatus(userspace));
809                        final Comment comment = registry.getSpecifiedCommentInComponent(
810                                        componentId, commentId, principal);
811                        if (comment != null
812                                        && componentId.equals(comment.getComponentDescriptionId())) {
813                                LOG.debug("Comment with id: {} set for deletion.", commentId);
814                                registry.deleteComment(commentId, principal);
815                        } else {
816                                throw new ComponentRegistryException(
817                                                "Comment not found for specified component");
818                        }
819                } catch (DeleteFailedException e) {
820                        LOG.info("Comment with id: {} deletion failed: {}", commentId,
821                                        e.getMessage());
822                        LOG.debug("Deletion failure details:", e);
823                        return Response.serverError().status(Status.FORBIDDEN)
824                                        .entity("" + e.getMessage()).build();
825                } catch (ComponentRegistryException e) {
826                        LOG.info("Could not retrieve component", e);
827                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
828                                        .build();
829                } catch (IOException e) {
830                        LOG.error("Comment with id: " + commentId + " deletion failed.", e);
831                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
832                                        .build();
833                } catch (UserUnauthorizedException e) {
834                        LOG.info("Comment with id: {} deletion failed: {}", commentId,
835                                        e.getMessage());
836                        LOG.debug("Deletion failure details:", e);
837                        return Response.serverError().status(Status.UNAUTHORIZED)
838                                        .entity("" + e.getMessage()).build();
839                }
840                LOG.info("Comment with id: {} deleted.", commentId);
841                return Response.ok().build();
842        }
843
844        @Override
845        @GET
846        @Path("/profiles/{profileId}/{rawType}")
847        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML })
848        public Response getRegisteredProfileRawType(
849                        @PathParam("profileId") final String profileId,
850                        @PathParam("rawType") String rawType) {
851                LOG.debug("Profile with id {} and rawType {} is requested.", profileId,
852                                rawType);
853                StreamingOutput result = null;
854                try {
855                        final ComponentRegistry registry = findRegistry(profileId,
856                                        new ProfileClosure());
857                        if (registry == null) {
858                                return Response
859                                                .status(Status.NOT_FOUND)
860                                                .entity("Id: " + profileId
861                                                                + " is not registered, cannot create data.")
862                                                .build();
863                        }
864                        ProfileDescription desc = registry.getProfileDescription(profileId);
865                        checkAndThrowDescription(desc, profileId);
866                        String fileName = desc.getName() + "." + rawType;
867
868                        if ("xml".equalsIgnoreCase(rawType)) {
869                                result = new StreamingOutput() {
870                                        @Override
871                                        public void write(OutputStream output) throws IOException,
872                                                        WebApplicationException {
873                                                try {
874                                                        registry.getMDProfileAsXml(profileId, output);
875                                                } catch (ComponentRegistryException e) {
876                                                        LOG.warn("Could not retrieve component {}",
877                                                                        profileId);
878                                                        LOG.debug("Details", e);
879                                                        throw new WebApplicationException(e, Response
880                                                                        .serverError()
881                                                                        .status(Status.INTERNAL_SERVER_ERROR)
882                                                                        .build());
883                                                }
884                                        }
885                                };
886                        } else if ("xsd".equalsIgnoreCase(rawType)) {
887                                result = new StreamingOutput() {
888                                        @Override
889                                        public void write(OutputStream output) throws IOException,
890                                                        WebApplicationException {
891                                                try {
892                                                        registry.getMDProfileAsXsd(profileId, output);
893                                                } catch (ComponentRegistryException e) {
894                                                        LOG.warn("Could not retrieve component {}",
895                                                                        profileId);
896                                                        LOG.debug("Details", e);
897                                                        throw new WebApplicationException(e, Response
898                                                                        .serverError()
899                                                                        .status(Status.INTERNAL_SERVER_ERROR)
900                                                                        .build());
901                                                }
902                                        }
903                                };
904                        } else {
905                                throw new WebApplicationException(Response
906                                                .serverError()
907                                                .entity("unsupported rawType: " + rawType
908                                                                + " (only xml or xsd are supported)").build());
909                        }
910                        return createDownloadResponse(result, fileName);
911                } catch (ComponentRegistryException e) {
912                        LOG.warn("Could not retrieve component {}", profileId);
913                        LOG.debug("Details", e);
914                        return Response.serverError().status(Status.INTERNAL_SERVER_ERROR)
915                                        .build();
916                }
917        }
918
919        private void checkAndThrowDescription(AbstractDescription desc, String id) {
920                if (desc == null) {
921                        throw new WebApplicationException(Response.serverError()
922                                        .entity("Incorrect id:" + id + "cannot handle request")
923                                        .build());
924                }
925        }
926
927        private Response createDownloadResponse(StreamingOutput result,
928                        String fileName) {
929                // Making response so it triggers browsers native save as dialog.
930                Response response = Response
931                                .ok()
932                                .type("application/x-download")
933                                .header("Content-Disposition",
934                                                "attachment; filename=\"" + fileName + "\"")
935                                .entity(result).build();
936                return response;
937
938        }
939
940        @Override
941        @POST
942        @Path("/profiles")
943        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
944                        MediaType.APPLICATION_JSON })
945        @Consumes("multipart/form-data")
946        public Response registerProfile(
947                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
948                        @FormDataParam(NAME_FORM_FIELD) String name,
949                        @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
950                        @FormDataParam(GROUP_FORM_FIELD) String group,
951                        @FormDataParam(DOMAIN_FORM_FIELD) String domainName,
952                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
953                try {
954                        Principal principal = checkAndGetUserPrincipal();
955                        UserCredentials userCredentials = getUserCredentials(principal);
956                        ProfileDescription desc = createNewProfileDescription();
957                        desc.setCreatorName(userCredentials.getDisplayName());
958                        desc.setUserId(userCredentials.getPrincipalName()); // Hash used to
959                                                                                                                                // be created
960                                                                                                                                // here, now Id
961                                                                                                                                // is
962                                                                                                                                // constructed
963                                                                                                                                // by impl
964                        desc.setName(name);
965                        desc.setDescription(description);
966                        desc.setGroupName(group);
967                        desc.setDomainName(domainName);
968                        LOG.debug("Trying to register Profile: {}", desc);
969                        return register(input, desc, userCredentials, userspace,
970                                        new NewAction());
971                } catch (UserUnauthorizedException ex) {
972                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
973                                        .build();
974                }
975        }
976
977        @Override
978        @POST
979        @Path("/components")
980        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
981                        MediaType.APPLICATION_JSON })
982        @Consumes("multipart/form-data")
983        public Response registerComponent(
984                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
985                        @FormDataParam(NAME_FORM_FIELD) String name,
986                        @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
987                        @FormDataParam(GROUP_FORM_FIELD) String group,
988                        @FormDataParam(DOMAIN_FORM_FIELD) String domainName,
989                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
990                try {
991                        Principal principal = checkAndGetUserPrincipal();
992                        UserCredentials userCredentials = getUserCredentials(principal);
993                        ComponentDescription desc = createNewComponentDescription();
994                        desc.setCreatorName(userCredentials.getDisplayName());
995                        desc.setUserId(userCredentials.getPrincipalName()); // Hash used to
996                                                                                                                                // be created
997                                                                                                                                // here, now Id
998                                                                                                                                // is
999                                                                                                                                // constructed
1000                                                                                                                                // by impl
1001                        desc.setName(name);
1002                        desc.setDescription(description);
1003                        desc.setGroupName(group);
1004                        desc.setDomainName(domainName);
1005                        LOG.debug("Trying to register Component: {}", desc);
1006                        return register(input, desc, userCredentials, userspace,
1007                                        new NewAction());
1008                } catch (UserUnauthorizedException ex) {
1009                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
1010                                        .build();
1011                }
1012        }
1013
1014        @Override
1015        @POST
1016        @Path("/components/{componentId}/comments")
1017        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1018                        MediaType.APPLICATION_JSON })
1019        @Consumes("multipart/form-data")
1020        public Response registerCommentInComponent(
1021                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
1022                        @PathParam("componentId") String componentId,
1023                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
1024                        throws ComponentRegistryException {
1025                try {
1026                        Principal principal = checkAndGetUserPrincipal();
1027                        UserCredentials userCredentials = getUserCredentials(principal);
1028                        if (null == componentRegistryFactory
1029                                        .getOrCreateUser(userCredentials)) {
1030                                throw new UserUnauthorizedException(
1031                                                "Cannot materialize authenticated user");
1032                        }
1033                        // TODO: Add user/group param
1034                        ComponentRegistry registry = getRegistry(getStatus(userspace),
1035                                        null, userCredentials);
1036                        ComponentDescription description = registry
1037                                        .getComponentDescription(componentId);
1038                        if (description != null) {
1039                                LOG.debug("Trying to register comment to {}", componentId);
1040                                return registerComment(input, registry, userspace, description,
1041                                                principal, userCredentials);
1042                        } else {
1043                                LOG.warn(
1044                                                "Attempt to post comment on nonexistent component id {} failed.",
1045                                                componentId);
1046                                return Response
1047                                                .serverError()
1048                                                .entity("Invalid id, cannot comment on nonexistent component")
1049                                                .build();
1050                        }
1051                } catch (UserUnauthorizedException ex) {
1052                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
1053                                        .build();
1054                }
1055        }
1056
1057        @Override
1058        @POST
1059        @Path("/profiles/{profileId}/comments")
1060        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1061                        MediaType.APPLICATION_JSON })
1062        @Consumes("multipart/form-data")
1063        public Response registerCommentInProfile(
1064                        @FormDataParam(DATA_FORM_FIELD) InputStream input,
1065                        @PathParam("profileId") String profileId,
1066                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace)
1067                        throws ComponentRegistryException {
1068                try {
1069                        Principal principal = checkAndGetUserPrincipal();
1070                        UserCredentials userCredentials = getUserCredentials(principal);
1071                        if (null == componentRegistryFactory
1072                                        .getOrCreateUser(userCredentials)) {
1073                                throw new UserUnauthorizedException(
1074                                                "Cannot materialize authenticated user");
1075                        }
1076                        // TODO: Add user/group param
1077                        ComponentRegistry registry = getRegistry(getStatus(userspace),
1078                                        null, userCredentials);
1079                        ProfileDescription description = registry
1080                                        .getProfileDescription(profileId);
1081                        if (description != null) {
1082                                LOG.debug("Trying to register comment to {}", profileId);
1083                                return registerComment(input, registry, userspace, description,
1084                                                principal, userCredentials);
1085                        } else {
1086                                LOG.warn(
1087                                                "Attempt to post comment on nonexistent profile id {} failed.",
1088                                                profileId);
1089                                return Response
1090                                                .serverError()
1091                                                .entity("Invalid id, cannot comment on nonexistent profile")
1092                                                .build();
1093                        }
1094                } catch (UserUnauthorizedException ex) {
1095                        return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage())
1096                                        .build();
1097                }
1098        }
1099
1100        @Override
1101        @GET
1102        @Path("/pingSession")
1103        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1104                        MediaType.APPLICATION_JSON })
1105        public Response pingSession() {
1106                boolean stillActive = false;
1107                Principal userPrincipal = security.getUserPrincipal();
1108                if (LOG.isInfoEnabled()) {
1109                        LOG.debug("ping by <{}>",
1110                                        (userPrincipal == null ? "unauthorized user"
1111                                                        : userPrincipal.getName()));
1112                }
1113                if (request != null) {
1114                        if (userPrincipal != null
1115                                        && !ComponentRegistryFactory.ANONYMOUS_USER
1116                                                        .equals(userPrincipal.getName())) {
1117                                stillActive = !((HttpServletRequest) request).getSession()
1118                                                .isNew();
1119                        }
1120                }
1121                return Response
1122                                .ok()
1123                                .entity(String.format("<session stillActive=\"%s\"/>",
1124                                                stillActive)).build();
1125        }
1126
1127        private Response register(InputStream input, AbstractDescription desc,
1128                        UserCredentials userCredentials, boolean userspace,
1129                        RegisterAction action) {
1130                try {
1131                        // TODO: Add user/group param
1132                        ComponentRegistry registry = getRegistry(getStatus(userspace),
1133                                        null, userCredentials);
1134                        DescriptionValidator descriptionValidator = new DescriptionValidator(
1135                                        desc);
1136                        MDValidator validator = new MDValidator(input, desc, registry,
1137                                        getRegistry(getStatus(true)),
1138                                        componentRegistryFactory.getPublicRegistry(), marshaller);
1139                        RegisterResponse response = new RegisterResponse();
1140                        response.setIsInUserSpace(userspace);
1141                        validate(response, descriptionValidator, validator);
1142                        if (response.getErrors().isEmpty()) {
1143
1144                                CMDComponentSpec spec = validator.getCMDComponentSpec();
1145
1146                                // removing filename from spec before it gets extended.
1147                                // recursion over all the components
1148                                setFileNamesFromListToNull(spec.getCMDComponent());
1149
1150                                try {
1151                                        checkForRecursion(validator, registry, desc);
1152
1153                                        // Add profile
1154                                        int returnCode = action.execute(desc, spec, response,
1155                                                        registry);
1156                                        if (returnCode == 0) {
1157                                                response.setRegistered(true);
1158                                                response.setDescription(desc);
1159                                        } else {
1160                                                response.setRegistered(false);
1161                                                response.addError("Unable to register at this moment. Internal server error.");
1162                                        }
1163                                } catch (ComponentRegistryException ex) {
1164                                        // Recursion detected
1165                                        response.setRegistered(false);
1166                                        response.addError("Error while expanding specification. "
1167                                                        + ex.getMessage());
1168                                }
1169                        } else {
1170                                LOG.warn("Registration failed with validation errors: {}",
1171                                                Arrays.toString(response.getErrors().toArray()));
1172                                response.setRegistered(false);
1173                        }
1174                        LOG.info("Registered new {} {}", desc.isProfile() ? "profile"
1175                                        : "component", desc);
1176                        response.setIsProfile(desc.isProfile());
1177                        return Response.ok(response).build();
1178                } finally {
1179                        try {
1180                                input.close();// either we read the input or there was an
1181                                                                // exception, we need to close it.
1182                        } catch (IOException e) {
1183                                LOG.error("Error when closing inputstream: ", e);
1184                        }
1185                }
1186        }
1187
1188        /**
1189         *
1190         * @param validator
1191         * @param registry
1192         * @param desc
1193         * @throws ComponentRegistryException
1194         *             if recursion is detected or something goes wrong while trying
1195         *             to detect recursion
1196         */
1197        private void checkForRecursion(MDValidator validator,
1198                        ComponentRegistry registry, AbstractDescription desc)
1199                        throws ComponentRegistryException {
1200                try {
1201                        // Expand to check for recursion. Operate on copy so that original
1202                        // does not get expanded.
1203                        final CMDComponentSpec specCopy = validator
1204                                        .getCopyOfCMDComponentSpec();
1205                        // In case of recursion, the following will throw a
1206                        // ComponentRegistryException
1207                        registry.getExpander().expandNestedComponent(
1208                                        specCopy.getCMDComponent(), desc.getId());
1209                } catch (JAXBException ex) {
1210                        throw new ComponentRegistryException(
1211                                        "Unmarshalling failed while preparing recursion detection",
1212                                        ex);
1213                }
1214        }
1215
1216        private Response registerComment(InputStream input,
1217                        ComponentRegistry registry, boolean userspace,
1218                        AbstractDescription description, Principal principal,
1219                        UserCredentials userCredentials) {
1220                try {
1221                        CommentValidator validator = new CommentValidator(input,
1222                                        description, marshaller);
1223                        CommentResponse response = new CommentResponse();
1224                        response.setIsInUserSpace(userspace);
1225                        validateComment(response, validator);
1226                        if (response.getErrors().isEmpty()) {
1227                                Comment com = validator.getCommentSpec();
1228                                // int returnCode = action.executeComment(com, response,
1229                                // registry, principal.getName());
1230
1231                                // If user name is left empty, fill it using the user's display
1232                                // name
1233                                if (null == com.getUserName() || "".equals(com.getUserName())) {
1234                                        if (userCredentials != null) {
1235                                                com.setUserName(userCredentials.getDisplayName());
1236                                        } else {
1237                                                com.setUserName(principal.getName());
1238                                        }
1239                                }
1240
1241                                int returnCode = registry.registerComment(com,
1242                                                principal.getName());
1243                                if (returnCode == 0) {
1244                                        response.setRegistered(true);
1245                                        response.setComment(com);
1246                                } else {
1247                                        response.setRegistered(false);
1248                                        response.addError("Unable to post at this moment. Internal server error.");
1249                                }
1250                                if (com.getComponentDescriptionId() != null) {
1251                                        LOG.info("Posted new comment on component {}",
1252                                                        com.getComponentDescriptionId());
1253                                } else {
1254                                        LOG.info("Posted new comment on profile {}",
1255                                                        com.getProfileDescriptionId());
1256                                }
1257                        } else {
1258                                LOG.warn(
1259                                                "Posting of comment failed with validation errors: {}",
1260                                                Arrays.toString(response.getErrors().toArray()));
1261                                response.setRegistered(false);
1262                        }
1263                        return Response.ok(response).build();
1264                } catch (ComponentRegistryException ex) {
1265                        LOG.error("Error while inserting comment: ", ex);
1266                        return Response.serverError().entity(ex.getMessage()).build();
1267                } finally {
1268                        try {
1269                                input.close();// either we read the input or there was an
1270                                                                // exception, we need to close it.
1271                        } catch (IOException e) {
1272                                LOG.error("Error when closing inputstream: ", e);
1273                                return Response.serverError().build();
1274                        }
1275                }
1276        }
1277
1278        private ComponentDescription createNewComponentDescription() {
1279                ComponentDescription desc = ComponentDescription.createNewDescription();
1280                desc.setHref(createXlink(desc.getId()));
1281                return desc;
1282        }
1283
1284        private ProfileDescription createNewProfileDescription() {
1285                ProfileDescription desc = ProfileDescription.createNewDescription();
1286                desc.setHref(createXlink(desc.getId()));
1287                return desc;
1288        }
1289
1290        private String createXlink(String id) {
1291                URI uri = uriInfo.getRequestUriBuilder().path(id).build();
1292                return uri.toString();
1293        }
1294
1295        /**
1296         *
1297         * @return The application's base URI as configured in the
1298         *         {@link #APPLICATION_BASE_URL_PARAM} context parameter. If
1299         *         correctly configured, it should look something like
1300         *         "http://catalog.clarin.eu/ds/ComponentRegistry".
1301         *         <em>Be aware that this
1302         * can also be null if configured incorrectly!</em>
1303         *
1304         * @see #APPLICATION_BASE_URL_PARAM
1305         */
1306        private String getApplicationBaseURI() {
1307                return servletContext.getInitParameter(APPLICATION_BASE_URL_PARAM);
1308        }
1309
1310        private void validate(RegisterResponse response, Validator... validators) {
1311                for (Validator validator : validators) {
1312                        if (!validator.validate()) {
1313                                for (String error : validator.getErrorMessages()) {
1314                                        response.addError(error);
1315                                }
1316                        }
1317                }
1318        }
1319
1320        private void validateComment(CommentResponse response,
1321                        Validator... validators) {
1322                for (Validator validator : validators) {
1323                        if (!validator.validate()) {
1324                                for (String error : validator.getErrorMessages()) {
1325                                        response.addError(error);
1326                                }
1327                        }
1328                }
1329        }
1330
1331        /**
1332         * @param componentRegistryFactory
1333         *            the componentRegistryFactory to set
1334         */
1335        @Override
1336        public void setComponentRegistryFactory(
1337                        ComponentRegistryFactory componentRegistryFactory) {
1338                this.componentRegistryFactory = componentRegistryFactory;
1339        }
1340
1341        /**
1342         *
1343         * @param listofcomponents
1344         *            a list of components whose file-names and whose childrens'
1345         *            filenames are to be set to null
1346         */
1347        @Override
1348        public void setFileNamesFromListToNull(
1349                        List<CMDComponentType> listofcomponents) {
1350
1351                for (CMDComponentType currentcomponent : listofcomponents) {
1352                        setFileNamesToNullCurrent(currentcomponent);
1353                }
1354
1355        }
1356
1357        /**
1358         *
1359         * @param currentcomponent
1360         *            a component whose file-name and whose children filenames are
1361         *            to be set to null
1362         */
1363        protected void setFileNamesToNullCurrent(CMDComponentType currentcomponent) {
1364                currentcomponent.setFilename(null);
1365                setFileNamesFromListToNull(currentcomponent.getCMDComponent());
1366        }
1367
1368        /**
1369         *
1370         * @param userspace
1371         *            if "true" then profiles and components from the user's
1372         *            workspace, otherwise -- public
1373         * @param limit
1374         *            the number of items to be displayed
1375         * @return rss for the components in the database to which we are currently
1376         *         connected
1377         * @throws ComponentRegistryException
1378         * @throws ParseException
1379         */
1380        @Override
1381        @GET
1382        @Path("/components/rss")
1383        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1384                        MediaType.APPLICATION_JSON })
1385        public Rss getRssComponent(
1386                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
1387                        @QueryParam(NUMBER_OF_RSSITEMS) @DefaultValue("20") String limit)
1388                        throws ComponentRegistryException, ParseException {
1389                final List<ComponentDescription> components = getRegistry(
1390                                getStatus(userspace)).getComponentDescriptions();
1391                final RssCreatorDescriptions instance = new RssCreatorDescriptions(
1392                                userspace, getApplicationBaseURI(), "components",
1393                                Integer.parseInt(limit), components,
1394                                AbstractDescription.COMPARE_ON_DATE);
1395                final Rss rss = instance.getRss();
1396                LOG.debug("Releasing RSS of {} most recently registered components",
1397                                limit);
1398                return rss;
1399        }
1400
1401        /**
1402         *
1403         * @param userspace
1404         *            if "true" then profiles and components from the user's
1405         *            workspace, otherwise -- public
1406         * @param limit
1407         *            the number of items to be displayed
1408         * @return rss for the profiles in the database to which we are currently
1409         *         connected
1410         * @throws ComponentRegistryException
1411         * @throws ParseException
1412         */
1413        @Override
1414        @GET
1415        @Path("/profiles/rss")
1416        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1417                        MediaType.APPLICATION_JSON })
1418        public Rss getRssProfile(
1419                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
1420                        @QueryParam(NUMBER_OF_RSSITEMS) @DefaultValue("20") String limit)
1421                        throws ComponentRegistryException, ParseException {
1422                final List<ProfileDescription> profiles = getRegistry(
1423                                getStatus(userspace)).getProfileDescriptions();
1424                final RssCreatorDescriptions instance = new RssCreatorDescriptions(
1425                                userspace, getApplicationBaseURI(), "profiles",
1426                                Integer.parseInt(limit), profiles,
1427                                AbstractDescription.COMPARE_ON_DATE);
1428                final Rss rss = instance.getRss();
1429                LOG.debug("Releasing RSS of {} most recently registered profiles",
1430                                limit);
1431                return rss;
1432        }
1433
1434        /**
1435         *
1436         * @param profileId
1437         *            the Id of a profile whose comments are to be rss-ed
1438         * @param userspace
1439         *            if "true" then profiles and components from the user's
1440         *            workspace, otherwise -- public
1441         * @param limit
1442         *            the number of items to be displayed
1443         * @return rss of the comments for a chosen profile
1444         * @throws ComponentRegistryException
1445         * @throws IOException
1446         * @throws JAXBException
1447         * @throws ParseException
1448         */
1449        @Override
1450        @GET
1451        @Path("/profiles/{profileId}/comments/rss")
1452        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1453                        MediaType.APPLICATION_JSON })
1454        public Rss getRssOfCommentsFromProfile(
1455                        @PathParam("profileId") String profileId,
1456                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
1457                        @QueryParam(NUMBER_OF_RSSITEMS) @DefaultValue("20") String limit)
1458                        throws ComponentRegistryException, IOException, JAXBException,
1459                        ParseException {
1460                final Principal principal = security.getUserPrincipal();
1461                final List<Comment> comments = getRegistry(getStatus(userspace))
1462                                .getCommentsInProfile(profileId, principal);
1463                final String profileName = getRegistry(getStatus(userspace))
1464                                .getProfileDescription(profileId).getName();
1465                final RssCreatorComments instance = new RssCreatorComments(userspace,
1466                                getApplicationBaseURI(), Integer.parseInt(limit), profileId,
1467                                profileName, "profile", comments, Comment.COMPARE_ON_DATE);
1468                final Rss rss = instance.getRss();
1469                LOG.debug("Releasing RSS of {} most recent post on profile {}", limit,
1470                                profileId);
1471                return rss;
1472        }
1473
1474        /**
1475         *
1476         * @param componentId
1477         *            the Id of a component whose comments are to be rss-ed
1478         * @param userspace
1479         *            if "true" then profiles and components from the user's
1480         *            workspace, otherwise -- public
1481         * @param limit
1482         *            the number of items to be displayed
1483         * @return rss of the comments for a chosen component
1484         * @throws ComponentRegistryException
1485         * @throws IOException
1486         * @throws JAXBException
1487         * @throws ParseException
1488         */
1489        @Override
1490        @GET
1491        @Path("/components/{componentId}/comments/rss")
1492        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1493                        MediaType.APPLICATION_JSON })
1494        public Rss getRssOfCommentsFromComponent(
1495                        @PathParam("componentId") String componentId,
1496                        @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
1497                        @QueryParam(NUMBER_OF_RSSITEMS) @DefaultValue("20") String limit)
1498                        throws ComponentRegistryException, IOException, JAXBException,
1499                        ParseException {
1500                final Principal principal = security.getUserPrincipal();
1501                final List<Comment> comments = getRegistry(getStatus(userspace))
1502                                .getCommentsInComponent(componentId, principal);
1503                final String componentName = getRegistry(getStatus(userspace))
1504                                .getComponentDescription(componentId).getName();
1505                final RssCreatorComments instance = new RssCreatorComments(userspace,
1506                                getApplicationBaseURI(), Integer.parseInt(limit), componentId,
1507                                componentName, "component", comments, Comment.COMPARE_ON_DATE);
1508                final Rss rss = instance.getRss();
1509                LOG.debug("Releasing RSS of {} most recent post on component {}",
1510                                limit, componentId);
1511                return rss;
1512        }
1513
1514        @Override
1515        @GET
1516        @Path("/AllowedTypes")
1517        @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML,
1518                        MediaType.APPLICATION_JSON })
1519        public AllowedAttributetypesXML getAllowedAttributeTypes()
1520                        throws ComponentRegistryException, IOException, JAXBException,
1521                        ParseException {
1522                return (new AllowedAttributetypesXML());
1523        }
1524}
Note: See TracBrowser for help on using the repository browser.