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

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

Fixed exception that have appeared while unit-testing

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