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

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

Fixed issued arising after testing on localhost tomcat (completed)

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