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

Last change on this file since 4681 was 4681, checked in by Twan Goosen, 10 years ago

Fixed errors occurring while expanding due to wrapping of root component in an immutable singleton list

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