source: ComponentRegistry/branches/ComponentRegistry-1.13.0-olha/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/rest/ComponentRegistryRestService.java @ 2152

Last change on this file since 2152 was 2152, checked in by olhsha, 12 years ago

key stuff for fixing tickets 50 and 180 is discussed and coded

File size: 42.4 KB
Line 
1package clarin.cmdi.componentregistry.rest;
2
3import clarin.cmdi.componentregistry.CMDComponentTypeWrapper;
4import clarin.cmdi.componentregistry.ComponentRegistry;
5import clarin.cmdi.componentregistry.ComponentRegistryException;
6import clarin.cmdi.componentregistry.ComponentRegistryFactory;
7import clarin.cmdi.componentregistry.ComponentStatus;
8import clarin.cmdi.componentregistry.DeleteFailedException;
9import clarin.cmdi.componentregistry.Owner;
10import clarin.cmdi.componentregistry.UserCredentials;
11import clarin.cmdi.componentregistry.UserUnauthorizedException;
12import clarin.cmdi.componentregistry.components.CMDComponentSpec;
13import clarin.cmdi.componentregistry.components.CMDComponentType;
14import clarin.cmdi.componentregistry.model.AbstractDescription;
15import clarin.cmdi.componentregistry.model.Comment;
16import clarin.cmdi.componentregistry.model.CommentResponse;
17import clarin.cmdi.componentregistry.model.ComponentDescription;
18import clarin.cmdi.componentregistry.model.ProfileDescription;
19import clarin.cmdi.componentregistry.model.RegisterResponse;
20import com.sun.jersey.multipart.FormDataParam;
21import com.sun.jersey.spi.inject.Inject;
22import java.io.IOException;
23import java.io.InputStream;
24import java.io.OutputStream;
25import java.net.URI;
26import java.security.Principal;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.List;
30import javax.servlet.http.HttpServletRequest;
31import javax.ws.rs.Consumes;
32import javax.ws.rs.DELETE;
33import javax.ws.rs.DefaultValue;
34import javax.ws.rs.FormParam;
35import javax.ws.rs.GET;
36import javax.ws.rs.POST;
37import javax.ws.rs.Path;
38import javax.ws.rs.PathParam;
39import javax.ws.rs.Produces;
40import javax.ws.rs.QueryParam;
41import javax.ws.rs.WebApplicationException;
42import javax.ws.rs.core.Context;
43import javax.ws.rs.core.MediaType;
44import javax.ws.rs.core.Response;
45import javax.ws.rs.core.Response.Status;
46import javax.ws.rs.core.SecurityContext;
47import javax.ws.rs.core.StreamingOutput;
48import javax.ws.rs.core.UriInfo;
49import org.slf4j.Logger;
50import org.slf4j.LoggerFactory;
51
52@Path("/registry")
53public class ComponentRegistryRestService {
54
55    @Context
56    private UriInfo uriInfo;
57    @Context
58    private SecurityContext security;
59    @Context
60    private HttpServletRequest request;
61    private final static Logger LOG = LoggerFactory.getLogger(ComponentRegistryRestService.class);
62    public static final String DATA_FORM_FIELD = "data";
63    public static final String NAME_FORM_FIELD = "name";
64    public static final String DESCRIPTION_FORM_FIELD = "description";
65    public static final String GROUP_FORM_FIELD = "group";
66    public static final String DOMAIN_FORM_FIELD = "domainName";
67    public static final String USERSPACE_PARAM = "userspace";
68    public static final String METADATA_EDITOR_PARAM = "mdEditor";
69    @Inject(value = "componentRegistryFactory")
70    private ComponentRegistryFactory componentRegistryFactory;
71
72    /**
73     * Converts userspace boolean to component status. Temporary solution!!!
74     *
75     * TODO: Replace all calls to getRegistry that use this by calls using ComponentStatus
76     * @param userSpace
77     * @return
78     * @deprecated All calls should go directly to {@link #getRegistry(clarin.cmdi.componentregistry.ComponentStatus)}
79     */
80    @Deprecated
81    private static ComponentStatus getStatus(boolean userSpace) {
82        if (userSpace) {
83            return ComponentStatus.DEVELOPMENT;
84        } else {
85            return ComponentStatus.PUBLIC;
86        }
87    }
88
89    private ComponentRegistry getRegistry(ComponentStatus status) {
90        Principal userPrincipal = security.getUserPrincipal();
91        UserCredentials userCredentials = getUserCredentials(userPrincipal);
92        return getRegistry(status, null, userCredentials);
93    }
94
95    private ComponentRegistry getRegistry(ComponentStatus status, Owner owner, UserCredentials userCredentials) {
96        try {
97            return componentRegistryFactory.getComponentRegistry(status, owner, userCredentials);
98        } catch (UserUnauthorizedException uuEx) {
99            //TODO: Throw actual exception and catch nicely
100            throw new RuntimeException("Cannot access requested registry", uuEx);
101        }
102    }
103
104    /**
105     *
106     * @return Principal of current request
107     * @throws IllegalArgumentException If no user principal found
108     */
109    private Principal checkAndGetUserPrincipal() throws UserUnauthorizedException {
110        Principal principal = security.getUserPrincipal();
111        if (principal == null) {
112            throw new UserUnauthorizedException("no user principal found.");
113        }
114        return principal;
115    }
116
117    private UserCredentials getUserCredentials(Principal userPrincipal) {
118        UserCredentials userCredentials = null;
119        if (userPrincipal != null) {
120            userCredentials = new UserCredentials(userPrincipal);
121        }
122        return userCredentials;
123    }
124
125    @GET
126    @Path("/components")
127    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
128    public List<ComponentDescription> getRegisteredComponents(@QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
129        long start = System.currentTimeMillis();
130        List<ComponentDescription> components = getRegistry(getStatus(userspace)).getComponentDescriptions();
131        LOG.info("Releasing " + components.size() + " registered components into the world (" + (System.currentTimeMillis() - start)
132                + " millisecs)");
133        return components;
134    }
135
136    @GET
137    @Path("/profiles")
138    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
139    public List<ProfileDescription> getRegisteredProfiles(@QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace,
140            @QueryParam(METADATA_EDITOR_PARAM) @DefaultValue("false") boolean metadataEditor) throws ComponentRegistryException {
141        long start = System.currentTimeMillis();
142
143        List<ProfileDescription> profiles;
144        if (metadataEditor) {
145            profiles = getRegistry(getStatus(userspace)).getProfileDescriptionsForMetadaEditor();
146        } else {
147            profiles = getRegistry(getStatus(userspace)).getProfileDescriptions();
148        }
149
150        LOG.info("Releasing " + profiles.size() + " registered profiles into the world (" + (System.currentTimeMillis() - start)
151                + " millisecs)");
152        return profiles;
153    }
154
155    @GET
156    @Path("/components/{componentId}")
157    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
158    public Response getRegisteredComponent(@PathParam("componentId") String componentId,
159            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
160        LOG.info("Component with id: " + componentId + " is requested.");
161        CMDComponentSpec mdComponent = getRegistry(getStatus(userspace)).getMDComponent(componentId);
162        if (mdComponent == null) {
163            return Response.status(Status.NOT_FOUND).build();
164        } else {
165            return Response.ok(mdComponent).build();
166        }
167    }
168
169    @GET
170    @Path("/components/{componentId}/{rawType}")
171    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
172    public Response getRegisteredComponentRawType(@PathParam("componentId") final String componentId, @PathParam("rawType") String rawType) {
173        LOG.info("Component with id: " + componentId + " and rawType:" + rawType + " is requested.");
174        StreamingOutput result = null;
175        try {
176            final ComponentRegistry registry = findRegistry(componentId, new ComponentClosure());
177            if (registry == null) {
178                return Response.status(Status.NOT_FOUND).entity("Id: " + componentId + " is not registered, cannot create data.").build();
179            }
180            ComponentDescription desc = registry.getComponentDescription(componentId);
181            checkAndThrowDescription(desc, componentId);
182            String fileName = desc.getName() + "." + rawType;
183            if ("xml".equalsIgnoreCase(rawType)) {
184                result = new StreamingOutput() {
185
186                    @Override
187                    public void write(OutputStream output) throws IOException, WebApplicationException {
188                        try {
189                            registry.getMDComponentAsXml(componentId, output);
190                        } catch (ComponentRegistryException e) {
191                            LOG.info("Could not retrieve component", e);
192                            throw new WebApplicationException(e, Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build());
193                        }
194                    }
195                };
196            } else if ("xsd".equalsIgnoreCase(rawType)) {
197                result = new StreamingOutput() {
198
199                    @Override
200                    public void write(OutputStream output) throws IOException, WebApplicationException {
201                        try {
202                            registry.getMDComponentAsXsd(componentId, output);
203                        } catch (ComponentRegistryException e) {
204                            LOG.info("Could not retrieve component", e);
205                            throw new WebApplicationException(e, Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build());
206                        }
207
208                    }
209                };
210            } else {
211                throw new WebApplicationException(Response.serverError().entity(
212                        "unsupported rawType: " + rawType + " (only xml or xsd are supported)").build());
213            }
214            return createDownloadResponse(result, fileName);
215        } catch (ComponentRegistryException e) {
216            LOG.info("Could not retrieve component", e);
217            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
218        }
219    }
220
221    public ComponentRegistry findRegistry(String id, RegistryClosure<? extends AbstractDescription> clos) throws ComponentRegistryException {
222        AbstractDescription desc = null;
223        ComponentRegistry result = getRegistry(getStatus(false));
224        desc = clos.getDescription(result, id);
225        if (desc == null) {
226            List<ComponentRegistry> userRegs = componentRegistryFactory.getAllUserRegistries();
227            for (ComponentRegistry reg : userRegs) {
228                desc = clos.getDescription(reg, id);
229                if (desc != null) {
230                    result = reg;
231                    break;
232                }
233            }
234        }
235        return result;
236    }
237
238    @GET
239    @Path("/profiles/{profileId}")
240    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
241    public Response getRegisteredProfile(@PathParam("profileId") String profileId,
242            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
243        LOG.info("Profile with id: " + profileId + " is requested.");
244        CMDComponentSpec mdProfile = getRegistry(getStatus(userspace)).getMDProfile(profileId);
245        if (mdProfile == null) {
246            return Response.status(Status.NOT_FOUND).build();
247        } else {
248            return Response.ok(mdProfile).build();
249        }
250    }
251
252    @GET
253    @Path("/components/usage/{componentId}")
254    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
255    public List<AbstractDescription> getComponentUsage(@PathParam("componentId") String componentId, @QueryParam(USERSPACE_PARAM) @DefaultValue("true") boolean userspace) throws ComponentRegistryException {
256        try {
257            final long start = System.currentTimeMillis();
258            ComponentRegistry registry = getRegistry(getStatus(userspace));
259            List<ComponentDescription> components = registry.getUsageInComponents(componentId);
260            List<ProfileDescription> profiles = registry.getUsageInProfiles(componentId);
261
262            LOG.info("Found " + components.size() + " components and " + profiles.size() + " profiles that use component " + componentId
263                    + " (" + (System.currentTimeMillis() - start) + " millisecs)");
264
265            List<AbstractDescription> usages = new ArrayList<AbstractDescription>(components.size() + profiles.size());
266            usages.addAll(components);
267            usages.addAll(profiles);
268
269            return usages;
270        } catch (ComponentRegistryException e) {
271            LOG.info("Could not retrieve profile usage", e);
272            throw e;
273        }
274    }
275
276    @GET
277    @Path("/profiles/{profileId}/comments")
278    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
279    public List<Comment> getCommentsFromProfile(@PathParam("profileId") String profileId, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
280        long start = System.currentTimeMillis();
281        final Principal principal = security.getUserPrincipal();
282        List<Comment> comments = getRegistry(getStatus(userspace)).getCommentsInProfile(profileId, principal);
283        LOG.info("Releasing " + comments.size() + " registered comments in Profile into the world (" + (System.currentTimeMillis() - start)
284                + " millisecs)");
285        return comments;
286    }
287
288    @GET
289    @Path("/components/{componentId}/comments")
290    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
291    public List<Comment> getCommentsFromComponent(@PathParam("componentId") String componentId, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
292        long start = System.currentTimeMillis();
293        final Principal principal = security.getUserPrincipal();
294        List<Comment> comments = getRegistry(getStatus(userspace)).getCommentsInComponent(componentId, principal);
295        LOG.info("Releasing " + comments.size() + " registered comments in Component into the world (" + (System.currentTimeMillis() - start)
296                + " millisecs)");
297        return comments;
298    }
299
300    @GET
301    @Path("/profiles/{profileId}/comments/{commentId}")
302    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
303    public Comment getSpecifiedCommentFromProfile(@PathParam("profileId") String profileId, @PathParam("commentId") String commentId, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
304        LOG.info(" Comments of component with id" + commentId + " are requested.");
305        final Principal principal = security.getUserPrincipal();
306        return getRegistry(getStatus(userspace)).getSpecifiedCommentInProfile(profileId, commentId, principal);
307    }
308
309    @GET
310    @Path("/components/{componentId}/comments/{commentId}")
311    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
312    public Comment getSpecifiedCommentFromComponent(@PathParam("componentId") String componentId, @PathParam("commentId") String commentId, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
313        LOG.info(" Comments of component with id" + commentId + " are requested.");
314        final Principal principal = security.getUserPrincipal();
315        return getRegistry(getStatus(userspace)).getSpecifiedCommentInComponent(componentId, commentId, principal);
316    }
317
318    /**
319     *
320     * Purely helper method for my front-end (FLEX) which only does post/get requests. The query param is checked and the "proper" method is
321     * called.
322     *
323     * @param profileId
324     * @param method
325     * @return
326     */
327    @POST
328    @Path("/profiles/{profileId}")
329    public Response manipulateRegisteredProfile(@PathParam("profileId") String profileId, @FormParam("method") String method,
330            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
331        if ("delete".equalsIgnoreCase(method)) {
332            return deleteRegisteredProfile(profileId, userspace);
333        } else {
334            return Response.ok().build();
335        }
336    }
337
338    @POST
339    @Path("/profiles/{profileId}/comments/{commentId}")
340    public Response manipulateCommentFromProfile(@PathParam("profileId") String profileId, @PathParam("commentId") String commentId, @FormParam("method") String method,
341            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
342        if ("delete".equalsIgnoreCase(method)) {
343            return deleteCommentFromProfile(profileId, commentId, userspace);
344        } else {
345            return Response.ok().build();
346        }
347    }
348
349    @POST
350    @Path("/components/{componentId}/comments/{commentId}")
351    public Response manipulateCommentFromComponent(@PathParam("componentId") String componentId, @PathParam("commentId") String commentId, @FormParam("method") String method,
352            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
353        if ("delete".equalsIgnoreCase(method)) {
354            return deleteCommentFromComponent(componentId, commentId, userspace);
355        } else {
356            return Response.ok().build();
357        }
358    }
359
360    @POST
361    @Path("/profiles/{profileId}/publish")
362    @Consumes("multipart/form-data")
363    public Response publishRegisteredProfile(@PathParam("profileId") String profileId, @FormDataParam(DATA_FORM_FIELD) InputStream input,
364            @FormDataParam(NAME_FORM_FIELD) String name, @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
365            @FormDataParam(GROUP_FORM_FIELD) String group, @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
366        try {
367            Principal principal = checkAndGetUserPrincipal();
368            ProfileDescription desc = getRegistry(getStatus(true)).getProfileDescription(profileId);
369            if (desc != null) {
370                updateDescription(desc, name, description, domainName, group);
371                return register(input, desc, getUserCredentials(principal), true, new PublishAction(principal));
372            } else {
373                LOG.error("Update of nonexistent id (" + profileId + ") failed.");
374                return Response.serverError().entity("Invalid id, cannot update nonexistent profile").build();
375            }
376        } catch (ComponentRegistryException e) {
377            LOG.info("Could not retrieve component", e);
378            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
379        } catch (UserUnauthorizedException ex) {
380            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
381        }
382    }
383
384    @POST
385    @Path("/profiles/{profileId}/update")
386    @Consumes("multipart/form-data")
387    public Response updateRegisteredProfile(@PathParam("profileId") String profileId,
388            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace, @FormDataParam(DATA_FORM_FIELD) InputStream input,
389            @FormDataParam(NAME_FORM_FIELD) String name, @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
390            @FormDataParam(GROUP_FORM_FIELD) String group, @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
391        try {
392            Principal principal = checkAndGetUserPrincipal();
393            UserCredentials userCredentials = getUserCredentials(principal);
394            ProfileDescription desc = getRegistry(getStatus(userspace)).getProfileDescription(profileId);
395            if (desc != null) {
396                updateDescription(desc, name, description, domainName, group);
397                return register(input, desc, userCredentials, userspace, new UpdateAction(principal));
398            } else {
399                LOG.error("Update of nonexistent id (" + profileId + ") failed.");
400                return Response.serverError().entity("Invalid id, cannot update nonexistent profile").build();
401            }
402        } catch (ComponentRegistryException e) {
403            LOG.info("Could not retrieve component", e);
404            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
405        } catch (UserUnauthorizedException ex) {
406            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
407        }
408
409    }
410
411    /**
412     *
413     * Purely helper method for my front-end (FLEX) which van only do post/get requests. The query param is checked and the "proper" method
414     * is called.
415     *
416     * @param componentId
417     * @param method
418     * @return
419     */
420    @POST
421    @Path("/components/{componentId}")
422    public Response manipulateRegisteredComponent(@PathParam("componentId") String componentId, @FormParam("method") String method,
423            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
424        if ("delete".equalsIgnoreCase(method)) {
425            return deleteRegisteredComponent(componentId, userspace);
426        } else {
427            return Response.ok().build();
428        }
429    }
430
431    @POST
432    @Path("/components/{componentId}/publish")
433    @Consumes("multipart/form-data")
434    public Response publishRegisteredComponent(@PathParam("componentId") String componentId,
435            @FormDataParam(DATA_FORM_FIELD) InputStream input, @FormDataParam(NAME_FORM_FIELD) String name,
436            @FormDataParam(DESCRIPTION_FORM_FIELD) String description, @FormDataParam(GROUP_FORM_FIELD) String group,
437            @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
438        try {
439            Principal principal = checkAndGetUserPrincipal();
440            // TODO: Get status from parameter
441            ComponentDescription desc = getRegistry(getStatus(true)).getComponentDescription(componentId);
442            if (desc != null) {
443                updateDescription(desc, name, description, domainName, group);
444                return register(input, desc, getUserCredentials(principal), true, new PublishAction(principal));
445            } else {
446                LOG.error("Update of nonexistent id (" + componentId + ") failed.");
447                return Response.serverError().entity("Invalid id, cannot update nonexistent profile").build();
448            }
449        } catch (ComponentRegistryException e) {
450            LOG.info("Could not retrieve component", e);
451            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
452        } catch (UserUnauthorizedException ex) {
453            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
454        }
455    }
456
457    @POST
458    @Path("/components/{componentId}/update")
459    @Consumes("multipart/form-data")
460    public Response updateRegisteredComponent(@PathParam("componentId") String componentId,
461            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace, @FormDataParam(DATA_FORM_FIELD) InputStream input,
462            @FormDataParam(NAME_FORM_FIELD) String name, @FormDataParam(DESCRIPTION_FORM_FIELD) String description,
463            @FormDataParam(GROUP_FORM_FIELD) String group, @FormDataParam(DOMAIN_FORM_FIELD) String domainName) {
464        try {
465            Principal principal = checkAndGetUserPrincipal();
466            ComponentDescription desc = getRegistry(getStatus(userspace)).getComponentDescription(componentId);
467            if (desc != null) {
468                updateDescription(desc, name, description, domainName, group);
469                return register(input, desc, getUserCredentials(principal), userspace, new UpdateAction(principal));
470            } else {
471                LOG.error("Update of nonexistent id (" + componentId + ") failed.");
472                return Response.serverError().entity("Invalid id, cannot update nonexistent component").build();
473            }
474        } catch (ComponentRegistryException e) {
475            LOG.info("Could not retrieve component", e);
476            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
477        } catch (UserUnauthorizedException ex) {
478            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
479        }
480    }
481
482    private void updateDescription(AbstractDescription desc, String name, String description, String domainName, String group) {
483        desc.setName(name);
484        desc.setDescription(description);
485        desc.setDomainName(domainName);
486        desc.setGroupName(group);
487        desc.setRegistrationDate(AbstractDescription.createNewDate());
488    }
489
490    @DELETE
491    @Path("/components/{componentId}")
492    public Response deleteRegisteredComponent(@PathParam("componentId") String componentId,
493            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
494        try {
495            Principal principal = checkAndGetUserPrincipal();
496            ComponentRegistry registry = getRegistry(getStatus(userspace));
497            LOG.info("Component with id: " + componentId + " set for deletion.");
498            registry.deleteMDComponent(componentId, principal, false);
499        } catch (DeleteFailedException e) {
500            LOG.info("Component with id: " + componentId + " deletion failed.", e);
501            return Response.status(Status.FORBIDDEN).entity("" + e.getMessage()).build();
502        } catch (ComponentRegistryException e) {
503            LOG.info("Component with id: " + componentId + " deletion failed.", e);
504            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
505        } catch (IOException e) {
506            LOG.info("Component with id: " + componentId + " deletion failed.", e);
507            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
508        } catch (UserUnauthorizedException e) {
509            LOG.info("Component with id: " + componentId + " deletion failed: " + e.getMessage());
510            return Response.serverError().status(Status.UNAUTHORIZED).entity("" + e.getMessage()).build();
511        }
512        LOG.info("Component with id: " + componentId + " deleted.");
513        return Response.ok().build();
514    }
515
516    @DELETE
517    @Path("/profiles/{profileId}")
518    public Response deleteRegisteredProfile(@PathParam("profileId") String profileId,
519            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
520        try {
521            Principal principal = checkAndGetUserPrincipal();
522            LOG.info("Profile with id: " + profileId + " set for deletion.");
523            getRegistry(getStatus(userspace)).deleteMDProfile(profileId, principal);
524        } catch (DeleteFailedException e) {
525            LOG.info("Profile with id: " + profileId + " deletion failed: " + e.getMessage());
526            return Response.serverError().status(Status.FORBIDDEN).entity("" + e.getMessage()).build();
527        } catch (ComponentRegistryException e) {
528            LOG.info("Could not retrieve component", e);
529            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
530        } catch (IOException e) {
531            LOG.info("Profile with id: " + profileId + " deletion failed.", e);
532            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
533        } catch (UserUnauthorizedException e) {
534            LOG.info("Profile with id: " + profileId + " deletion failed: " + e.getMessage());
535            return Response.serverError().status(Status.UNAUTHORIZED).entity("" + e.getMessage()).build();
536        }
537        LOG.info("Profile with id: " + profileId + " deleted.");
538        return Response.ok().build();
539    }
540
541    @DELETE
542    @Path("/profiles/{profileId}/comments/{commentId}")
543    public Response deleteCommentFromProfile(@PathParam("profileId") String profileId, @PathParam("commentId") String commentId,
544            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
545        try {
546            final Principal principal = checkAndGetUserPrincipal();
547            final ComponentRegistry registry = getRegistry(getStatus(userspace));
548            final Comment comment = registry.getSpecifiedCommentInProfile(profileId, commentId, principal);
549            if (comment != null && profileId.equals(comment.getProfileDescriptionId())) {
550                LOG.info("Comment with id: " + commentId + " set for deletion.");
551                registry.deleteComment(commentId, principal);
552            } else {
553                throw new ComponentRegistryException("Comment not found for specified profile");
554            }
555        } catch (DeleteFailedException e) {
556            LOG.info("Comment with id: " + commentId + " deletion failed: " + e.getMessage());
557            return Response.serverError().status(Status.FORBIDDEN).entity("" + e.getMessage()).build();
558        } catch (ComponentRegistryException e) {
559            LOG.info("Could not retrieve component", e);
560            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
561        } catch (IOException e) {
562            LOG.info("Comment with id: " + commentId + " deletion failed.", e);
563            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
564        } catch (UserUnauthorizedException e) {
565            LOG.info("Comment with id: " + commentId + " deletion failed: " + e.getMessage());
566            return Response.serverError().status(Status.UNAUTHORIZED).entity("" + e.getMessage()).build();
567        }
568        LOG.info("Comment with id: " + commentId + " deleted.");
569        return Response.ok().build();
570    }
571
572    @DELETE
573    @Path("/components/{componentId}/comments/{commentId}")
574    public Response deleteCommentFromComponent(@PathParam("componentId") String componentId, @PathParam("commentId") String commentId,
575            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
576        try {
577            final Principal principal = checkAndGetUserPrincipal();
578            final ComponentRegistry registry = getRegistry(getStatus(userspace));
579            final Comment comment = registry.getSpecifiedCommentInComponent(componentId, commentId, principal);
580            if (comment != null && componentId.equals(comment.getComponentDescriptionId())) {
581                LOG.info("Comment with id: " + commentId + " set for deletion.");
582                registry.deleteComment(commentId, principal);
583            } else {
584                throw new ComponentRegistryException("Comment not found for specified component");
585            }
586        } catch (DeleteFailedException e) {
587            LOG.info("Comment with id: " + commentId + " deletion failed: " + e.getMessage());
588            return Response.serverError().status(Status.FORBIDDEN).entity("" + e.getMessage()).build();
589        } catch (ComponentRegistryException e) {
590            LOG.info("Could not retrieve component", e);
591            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
592        } catch (IOException e) {
593            LOG.info("Comment with id: " + commentId + " deletion failed.", e);
594            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
595        } catch (UserUnauthorizedException e) {
596            LOG.info("Comment with id: " + commentId + " deletion failed: " + e.getMessage());
597            return Response.serverError().status(Status.UNAUTHORIZED).entity("" + e.getMessage()).build();
598        }
599        LOG.info("Comment with id: " + commentId + " deleted.");
600        return Response.ok().build();
601    }
602
603    @GET
604    @Path("/profiles/{profileId}/{rawType}")
605    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
606    public Response getRegisteredProfileRawType(@PathParam("profileId") final String profileId, @PathParam("rawType") String rawType) {
607        LOG.info("Profile with id: " + profileId + " and rawType:" + rawType + " is requested.");
608        StreamingOutput result = null;
609        try {
610            final ComponentRegistry registry = findRegistry(profileId, new ProfileClosure());
611            if (registry == null) {
612                return Response.status(Status.NOT_FOUND).entity("Id: " + profileId + " is not registered, cannot create data.").build();
613            }
614            ProfileDescription desc = registry.getProfileDescription(profileId);
615            checkAndThrowDescription(desc, profileId);
616            String fileName = desc.getName() + "." + rawType;
617
618            if ("xml".equalsIgnoreCase(rawType)) {
619                result = new StreamingOutput() {
620
621                    @Override
622                    public void write(OutputStream output) throws IOException, WebApplicationException {
623                        try {
624                            registry.getMDProfileAsXml(profileId, output);
625                        } catch (ComponentRegistryException e) {
626                            LOG.warn("Could not retrieve component", e);
627                            throw new WebApplicationException(e, Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build());
628                        }
629                    }
630                };
631            } else if ("xsd".equalsIgnoreCase(rawType)) {
632                result = new StreamingOutput() {
633
634                    @Override
635                    public void write(OutputStream output) throws IOException, WebApplicationException {
636                        try {
637                            registry.getMDProfileAsXsd(profileId, output);
638                        } catch (ComponentRegistryException e) {
639                            LOG.warn("Could not retrieve component", e);
640                            throw new WebApplicationException(e, Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build());
641                        }
642                    }
643                };
644            } else {
645                throw new WebApplicationException(Response.serverError().entity(
646                        "unsupported rawType: " + rawType + " (only xml or xsd are supported)").build());
647            }
648            return createDownloadResponse(result, fileName);
649        } catch (ComponentRegistryException e) {
650            LOG.info("Could not retrieve component", e);
651            return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
652        }
653    }
654
655    private void checkAndThrowDescription(AbstractDescription desc, String id) {
656        if (desc == null) {
657            throw new WebApplicationException(Response.serverError().entity("Incorrect id:" + id + "cannot handle request").build());
658        }
659    }
660
661    private Response createDownloadResponse(StreamingOutput result, String fileName) {
662        //Making response so it triggers browsers native save as dialog.
663        Response response = Response.ok().type("application/x-download").header("Content-Disposition",
664                "attachment; filename=\"" + fileName + "\"").entity(result).build();
665        return response;
666
667    }
668
669    @POST
670    @Path("/profiles")
671    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
672    @Consumes("multipart/form-data")
673    public Response registerProfile(@FormDataParam(DATA_FORM_FIELD) InputStream input, @FormDataParam(NAME_FORM_FIELD) String name,
674            @FormDataParam(DESCRIPTION_FORM_FIELD) String description, @FormDataParam(GROUP_FORM_FIELD) String group, @FormDataParam(DOMAIN_FORM_FIELD) String domainName,
675            @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
676        try {
677            Principal principal = checkAndGetUserPrincipal();
678            UserCredentials userCredentials = getUserCredentials(principal);
679            ProfileDescription desc = createNewProfileDescription();
680            desc.setCreatorName(userCredentials.getDisplayName());
681            desc.setUserId(userCredentials.getPrincipalName()); // Hash used to be created here, now Id is constructed by impl
682            desc.setName(name);
683            desc.setDescription(description);
684            desc.setGroupName(group);
685            desc.setDomainName(domainName);
686            LOG.info("Trying to register Profile: " + desc);
687            return register(input, desc, userCredentials, userspace, new NewAction());
688        } catch (UserUnauthorizedException ex) {
689            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
690        }
691    }
692
693    @POST
694    @Path("/components")
695    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
696    @Consumes("multipart/form-data")
697    public Response registerComponent(@FormDataParam(DATA_FORM_FIELD) InputStream input, @FormDataParam(NAME_FORM_FIELD) String name,
698            @FormDataParam(DESCRIPTION_FORM_FIELD) String description, @FormDataParam(GROUP_FORM_FIELD) String group,
699            @FormDataParam(DOMAIN_FORM_FIELD) String domainName, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) {
700        try {
701            Principal principal = checkAndGetUserPrincipal();
702            UserCredentials userCredentials = getUserCredentials(principal);
703            ComponentDescription desc = createNewComponentDescription();
704            desc.setCreatorName(userCredentials.getDisplayName());
705            desc.setUserId(userCredentials.getPrincipalName()); // Hash used to be created here, now Id is constructed by impl
706            desc.setName(name);
707            desc.setDescription(description);
708            desc.setGroupName(group);
709            desc.setDomainName(domainName);
710            LOG.info("Trying to register Component: " + desc);
711            return register(input, desc, userCredentials, userspace, new NewAction());
712        } catch (UserUnauthorizedException ex) {
713            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
714        }
715    }
716
717    @POST
718    @Path("/components/{componentId}/comments")
719    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
720    @Consumes("multipart/form-data")
721    public Response registerCommentInComponent(@FormDataParam(DATA_FORM_FIELD) InputStream input,
722            @PathParam("componentId") String componentId, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
723        try {
724            Principal principal = checkAndGetUserPrincipal();
725            UserCredentials userCredentials = getUserCredentials(principal);
726            if (null == componentRegistryFactory.getOrCreateUser(userCredentials)) {
727                throw new UserUnauthorizedException("Cannot materialize authenticated user");
728            }
729            // TODO: Add user/group param
730            ComponentRegistry registry = getRegistry(getStatus(userspace), null, userCredentials);
731            ComponentDescription description = registry.getComponentDescription(componentId);
732            if (description != null) {
733                LOG.info("Trying to register comment to " + componentId);
734                return registerComment(input, registry, userspace, description, principal, userCredentials);
735            } else {
736                LOG.error("Attempt to post comment on nonexistent component id (" + componentId + ") failed.");
737                return Response.serverError().entity("Invalid id, cannot comment on nonexistent component").build();
738            }
739        } catch (UserUnauthorizedException ex) {
740            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
741        }
742    }
743
744    @POST
745    @Path("/profiles/{profileId}/comments")
746    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
747    @Consumes("multipart/form-data")
748    public Response registerCommentInProfile(@FormDataParam(DATA_FORM_FIELD) InputStream input,
749            @PathParam("profileId") String profileId, @QueryParam(USERSPACE_PARAM) @DefaultValue("false") boolean userspace) throws ComponentRegistryException {
750        try {
751            Principal principal = checkAndGetUserPrincipal();
752            UserCredentials userCredentials = getUserCredentials(principal);
753            if (null == componentRegistryFactory.getOrCreateUser(userCredentials)) {
754                throw new UserUnauthorizedException("Cannot materialize authenticated user");
755            }
756            // TODO: Add user/group param
757            ComponentRegistry registry = getRegistry(getStatus(userspace), null, userCredentials);
758            ProfileDescription description = registry.getProfileDescription(profileId);
759            if (description != null) {
760                LOG.info("Trying to register comment to " + profileId);
761                return registerComment(input, registry, userspace, description, principal, userCredentials);
762            } else {
763                LOG.error("Attempt to post comment on nonexistent profile id (" + profileId + ") failed.");
764                return Response.serverError().entity("Invalid id, cannot comment on nonexistent profile").build();
765            }
766        } catch (UserUnauthorizedException ex) {
767            return Response.status(Status.UNAUTHORIZED).entity(ex.getMessage()).build();
768        }
769    }
770
771    @GET
772    @Path("/pingSession")
773    @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
774    public Response pingSession() {
775        boolean stillActive = false;
776        Principal userPrincipal = security.getUserPrincipal();
777        LOG.info("ping by user: " + (userPrincipal == null ? "null" : userPrincipal.getName()));
778        if (request != null) {
779            if (userPrincipal != null && !ComponentRegistryFactory.ANONYMOUS_USER.equals(userPrincipal.getName())) {
780                stillActive = !((HttpServletRequest) request).getSession().isNew();
781            }
782        }
783        return Response.ok().entity("<session stillActive=\"" + stillActive + "\"/>").build();
784    }
785
786    private Response register(InputStream input, AbstractDescription desc, UserCredentials userCredentials, boolean userspace,
787            RegisterAction action) {
788        try {
789            // TODO: Add user/group param
790            ComponentRegistry registry = getRegistry(getStatus(userspace), null, userCredentials);
791            DescriptionValidator descriptionValidator = new DescriptionValidator(desc);
792            MDValidator validator = new MDValidator(input, desc, registry, getRegistry(getStatus(true)), componentRegistryFactory.getPublicRegistry());
793            RegisterResponse response = new RegisterResponse();
794            response.setIsInUserSpace(userspace);
795            validate(response, descriptionValidator, validator);
796            if (response.getErrors().isEmpty()) {
797               
798                CMDComponentSpec spec = validator.getCMDComponentSpec();
799               
800                // Olha: removing filename from spec before it gets extended!!! recursion over all the components
801                List<CMDComponentType> listofcomponents=spec.getCMDComponent();
802                CMDComponentTypeWrapper setnulls= new CMDComponentTypeWrapper();
803               
804                for (CMDComponentType currentcomponent : listofcomponents) {
805                  setnulls.setFileNamesToNull(currentcomponent);
806                  } 
807               
808                //for (CMDComponentType currentcomponent : listofcomponents) {
809                  //((CMDComponentTypeWrapper) currentcomponent). setFileNamesToNull();
810                   
811                //}
812               
813                try {
814                       
815                   
816                    // Expand to check for recursion
817                    registry.getExpander().expandNestedComponent(spec.getCMDComponent(), desc.getId());
818
819                   
820                   
821                    // Add profile
822                   
823                   
824                    int returnCode = action.execute(desc, spec, response, registry);
825                    if (returnCode == 0) {
826                        response.setRegistered(true);
827                        response.setDescription(desc);
828                    } else {
829                        response.setRegistered(false);
830                        response.addError("Unable to register at this moment. Internal server error.");
831                    }
832                } catch (ComponentRegistryException ex) {
833                    // Recursion detected
834                    response.setRegistered(false);
835                    response.addError("Error while expanding specification. " + ex.getMessage());
836                }
837            } else {
838                LOG.info("Registration failed with validation errors:" + Arrays.toString(response.getErrors().toArray()));
839                response.setRegistered(false);
840            }
841            response.setIsProfile(desc.isProfile());
842            return Response.ok(response).build();
843        } finally {
844            try {
845                input.close();//either we read the input or there was an exception, we need to close it.
846            } catch (IOException e) {
847                LOG.error("Error when closing inputstream: ", e);
848            }
849        }
850    }
851
852    private Response registerComment(InputStream input, ComponentRegistry registry, boolean userspace,
853            AbstractDescription description, Principal principal, UserCredentials userCredentials) {
854        try {
855            CommentValidator validator = new CommentValidator(input, description);
856            CommentResponse response = new CommentResponse();
857            response.setIsInUserSpace(userspace);
858            validateComment(response, validator);
859            if (response.getErrors().isEmpty()) {
860                Comment com = validator.getCommentSpec();
861                //int returnCode = action.executeComment(com, response, registry, principal.getName());
862
863                // If user name is left empty, fill it using the user's display name
864                if (null == com.getUserName() || "".equals(com.getUserName())) {
865                    if (userCredentials != null) {
866                        com.setUserName(userCredentials.getDisplayName());
867                    } else {
868                        com.setUserName(principal.getName());
869                    }
870                }
871
872                int returnCode = registry.registerComment(com, principal.getName());
873                if (returnCode == 0) {
874                    response.setRegistered(true);
875                    response.setComment(com);
876                } else {
877                    response.setRegistered(false);
878                    response.addError("Unable to register at this moment. Internal server error.");
879                }
880            } else {
881                LOG.info("Registration failed with validation errors:" + Arrays.toString(response.getErrors().toArray()));
882                response.setRegistered(false);
883            }
884            return Response.ok(response).build();
885        } catch (ComponentRegistryException ex) {
886            LOG.error("Error while inserting comment: ", ex);
887            return Response.serverError().entity(ex.getMessage()).build();
888        } finally {
889            try {
890                input.close();//either we read the input or there was an exception, we need to close it.
891            } catch (IOException e) {
892                LOG.error("Error when closing inputstream: ", e);
893                return Response.serverError().build();
894            }
895        }
896    }
897
898    private ComponentDescription createNewComponentDescription() {
899        ComponentDescription desc = ComponentDescription.createNewDescription();
900        desc.setHref(createXlink(desc.getId()));
901        return desc;
902    }
903
904    private ProfileDescription createNewProfileDescription() {
905        ProfileDescription desc = ProfileDescription.createNewDescription();
906        desc.setHref(createXlink(desc.getId()));
907        return desc;
908    }
909
910    private Comment createNewComment() {
911        Comment com = Comment.createANewComment();
912        return com;
913    }
914
915    private String createXlink(String id) {
916        URI uri = uriInfo.getRequestUriBuilder().path(id).build();
917        return uri.toString();
918    }
919
920    private void validate(RegisterResponse response, Validator... validators) {
921        for (Validator validator : validators) {
922            if (!validator.validate()) {
923                for (String error : validator.getErrorMessages()) {
924                    response.addError(error);
925                }
926            }
927        }
928    }
929
930    private void validateComment(CommentResponse response, Validator... validators) {
931        for (Validator validator : validators) {
932            if (!validator.validate()) {
933                for (String error : validator.getErrorMessages()) {
934                    response.addError(error);
935                }
936            }
937        }
938    }
939
940    /**
941     * @param componentRegistryFactory the componentRegistryFactory to set
942     */
943    public void setComponentRegistryFactory(ComponentRegistryFactory componentRegistryFactory) {
944        this.componentRegistryFactory = componentRegistryFactory;
945    }
946   
947   
948}
Note: See TracBrowser for help on using the repository browser.