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

Last change on this file since 1862 was 1862, checked in by twagoo, 12 years ago

Fixed NPE because of eager log message

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