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

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

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

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