source: VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/rest/VirtualCollectionResource.java @ 5616

Last change on this file since 5616 was 5616, checked in by Twan Goosen, 10 years ago

Extracted interface from VirtualCollectionRegistry.
Created test for VirtualCollectionResource? of REST service that uses this interface for mocking.

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1package eu.clarin.cmdi.virtualcollectionregistry.rest;
2
3import com.sun.jersey.api.core.InjectParam;
4import eu.clarin.cmdi.virtualcollectionregistry.VirtualCollectionRegistry;
5import eu.clarin.cmdi.virtualcollectionregistry.VirtualCollectionRegistryException;
6import eu.clarin.cmdi.virtualcollectionregistry.VirtualCollectionRegistryUsageException;
7import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollection;
8import eu.clarin.cmdi.virtualcollectionregistry.service.VirtualCollectionMarshaller;
9import java.io.IOException;
10import java.io.InputStream;
11import java.net.URI;
12import java.security.Principal;
13import java.util.List;
14import javax.ws.rs.Consumes;
15import javax.ws.rs.DELETE;
16import javax.ws.rs.GET;
17import javax.ws.rs.POST;
18import javax.ws.rs.PUT;
19import javax.ws.rs.Path;
20import javax.ws.rs.PathParam;
21import javax.ws.rs.Produces;
22import javax.ws.rs.core.Context;
23import javax.ws.rs.core.HttpHeaders;
24import javax.ws.rs.core.MediaType;
25import javax.ws.rs.core.Request;
26import javax.ws.rs.core.Response;
27import javax.ws.rs.core.SecurityContext;
28import javax.ws.rs.core.UriBuilder;
29import javax.ws.rs.core.UriInfo;
30import javax.ws.rs.core.Variant;
31
32/**
33 * REST resource representing an individual virtual collection.
34 *
35 * This was designed to act as a managed subresource of
36 * {@link VirtualCollectionsResource}. The user of this class is responsible for
37 * calling {@link #setId(long) } before handing it over or doing anything else
38 * with it.
39 *
40 * @author twagoo
41 */
42public final class VirtualCollectionResource {
43
44    public static class MediaTypes {
45
46        public static final String CMDI = "application/x-cmdi+xml";
47        public static final MediaType CMDI_TYPE = new MediaType("application", "x-cmdi+xml");
48    }
49
50    @InjectParam
51    private VirtualCollectionRegistry registry;
52    @InjectParam
53    private VirtualCollectionMarshaller marshaller;
54    @Context
55    private SecurityContext security;
56    @Context
57    private HttpHeaders headers;
58    @Context
59    private UriInfo uriInfo;
60
61    private Long id;
62
63    /**
64     * Default constructor needed so that it can act as a managed subresource of
65     * {@link VirtualCollectionsResource}, remember to
66     * {@link #setId(long) set the id} after construction!
67     */
68    public VirtualCollectionResource() {
69    }
70
71    // for testing
72    protected VirtualCollectionResource(VirtualCollectionRegistry registry, VirtualCollectionMarshaller marshaller, SecurityContext security, HttpHeaders headers, UriInfo uriInfo, Long id) {
73        this.registry = registry;
74        this.marshaller = marshaller;
75        this.security = security;
76        this.headers = headers;
77        this.uriInfo = uriInfo;
78        this.id = id;
79    }
80
81   
82   
83    /**
84     * Sets the id for this resource; should be called exactly once per
85     * instance; <strong>mandatory call</strong>, not setting will lead to
86     * NullPointerExceptions
87     *
88     * @param id
89     */
90    public synchronized void setId(long id) {
91        if (this.id != null) {
92            throw new IllegalStateException("Id was already set for Virtual Collection resource! Resource is recycled (by Jersey)?");
93        }
94        this.id = id;
95    }
96
97    /**
98     * The virtual collection referenced by the URI will be retrieved
99     *
100     * @param request request object, to be injected by JAX-RS context
101     * @return A response containing a representation of the requested Virtual
102     * Collection. If the virtual collection is not found the appropriate HTTP
103     * status code is issued and an error message is returned.
104     * @throws VirtualCollectionRegistryException
105     */
106    @GET
107    @Produces({VirtualCollectionResource.MediaTypes.CMDI,
108        MediaType.TEXT_XML,
109        MediaType.APPLICATION_XML,
110        MediaType.APPLICATION_JSON})
111    public Response getVirtualCollection(@Context Request request)
112            throws VirtualCollectionRegistryException {
113        final VirtualCollection vc = registry.retrieveVirtualCollection(id);
114        // CMDI's should not be returned for non-public VC's, so check this...
115        if (!vc.isPublic() || (vc.getPersistentIdentifier() == null)) {
116            // exclude CMDI from the options and check if this is ok for request
117            final List<Variant> variants = Variant.mediaTypes(
118                    MediaType.TEXT_XML_TYPE,
119                    MediaType.APPLICATION_XML_TYPE,
120                    MediaType.APPLICATION_JSON_TYPE).add().build();
121            final Variant selectVariant = request.selectVariant(variants);
122            if (selectVariant != null) {
123                // alternative option is accepted, return this
124                return Response.ok(vc, selectVariant).build();
125            }
126            // else proceed anyway, will probably fail on writing CMDI body
127        }
128        return Response.ok(vc).build();
129    }
130
131    /**
132     * Redirects the client to the VC's details page in the Wicket frontend
133     *
134     * @return
135     * @throws VirtualCollectionRegistryException
136     */
137    @GET
138    @Produces({MediaType.TEXT_HTML})
139    public Response getVirtualCollectionDetailsRedirect()
140            throws VirtualCollectionRegistryException {
141        final UriBuilder pathBuilder = uriInfo.getBaseUriBuilder().path("../app/details/{arg1}");
142        final URI detailsUri = pathBuilder.build(id);
143        return Response.seeOther(detailsUri).build();
144    }
145
146    /**
147     * The virtual collection identified by the URI will be updated, actually
148     * replaced, with the representation of the virtual collection sent in the
149     * request body.
150     *
151     * @param input Depending on Content-Type header either a valid XML instance
152     * or the JSON representation of a virtual collection conforming to the
153     * above mentioned XML schema. The root element is expected to be
154     * "VirtualCollection"
155     * @return A response containing a {@link RestResponse}
156     * @throws VirtualCollectionRegistryException
157     */
158    @PUT
159    @Consumes({MediaType.TEXT_XML,
160        MediaType.APPLICATION_XML,
161        MediaType.APPLICATION_JSON})
162    @Produces({MediaType.TEXT_XML,
163        MediaType.APPLICATION_XML,
164        MediaType.APPLICATION_JSON})
165    public Response updateVirtualCollection(InputStream input) throws VirtualCollectionRegistryException {
166        Principal principal = security.getUserPrincipal();
167        if (principal == null) {
168            throw new NullPointerException("princial == null");
169        }
170        try {
171            VirtualCollectionMarshaller.Format format = RestUtils.getInputFormat(headers);
172            String encoding = RestUtils.getInputEncoding(headers);
173            VirtualCollection vc
174                    = marshaller.unmarshal(input, format, encoding);
175            registry.updateVirtualCollection(principal, id, vc);
176            RestResponse response = new RestResponse();
177            response.setIsSuccess(true);
178            response.setInfo("updated");
179            response.setId(id);
180            return Response.ok(response).build();
181        } catch (IOException e) {
182            throw new VirtualCollectionRegistryException("update", e);
183
184        }
185    }
186
187    /**
188     * The virtual collection referenced by the URI will be deleted.
189     *
190     * @return A response containing a {@link RestResponse}
191     * @throws VirtualCollectionRegistryException
192     */
193    @DELETE
194    @Produces({MediaType.TEXT_XML,
195        MediaType.APPLICATION_XML,
196        MediaType.APPLICATION_JSON})
197    public Response deleteVirtualCollection()
198            throws VirtualCollectionRegistryException {
199        Principal principal = security.getUserPrincipal();
200        if (principal == null) {
201            throw new NullPointerException("principal == null");
202        }
203        registry.deleteVirtualCollection(principal, id);
204        RestResponse response = new RestResponse();
205        response.setIsSuccess(true);
206        response.setInfo("deleted");
207        response.setId(id);
208        return Response.ok(response).build();
209    }
210
211    /**
212     * The publication state of the virtual collection referenced by the URI
213     *
214     * @return a response containing the {@link State} of the identified Virtual
215     * Collection
216     * @throws VirtualCollectionRegistryException
217     */
218    @GET
219    @Path("/state")
220    @Produces({MediaType.TEXT_XML,
221        MediaType.APPLICATION_XML,
222        MediaType.APPLICATION_JSON})
223    public Response getVirtualCollectionState()
224            throws VirtualCollectionRegistryException {
225        VirtualCollection.State state = registry.getVirtualCollectionState(id);
226        final State result;
227        switch (state) {
228            case PUBLIC_PENDING:
229            /* FALL-THROUGH */
230            case PUBLIC:
231                result = State.PUBLIC;
232                break;
233            default:
234                result = State.PRIVATE;
235        } // switch
236        return Response.ok(result).build();
237    }
238
239    /**
240     * Updates the publication state of the virtual collection referenced by the
241     * URI
242     *
243     * @param id
244     * @param state
245     * @return a response containg a {@link RestResponse}
246     * @throws VirtualCollectionRegistryException
247     */
248    @POST
249    @Path("/state")
250    @Consumes({MediaType.TEXT_XML,
251        MediaType.APPLICATION_XML,
252        MediaType.APPLICATION_JSON})
253    @Produces({MediaType.TEXT_XML,
254        MediaType.APPLICATION_XML,
255        MediaType.APPLICATION_JSON})
256    public Response setVirtualCollectionState(@PathParam("id") long id,
257            State state)
258            throws VirtualCollectionRegistryException {
259        Principal principal = security.getUserPrincipal();
260        if (principal == null) {
261            throw new NullPointerException("principal == null");
262        }
263        if (state == null) {
264            throw new VirtualCollectionRegistryUsageException("invalid state");
265        }
266        VirtualCollection.State vc_state = null;
267        switch (state) {
268            case PUBLIC:
269                vc_state = VirtualCollection.State.PUBLIC_PENDING;
270                break;
271            case PRIVATE:
272                vc_state = VirtualCollection.State.PRIVATE;
273                break;
274            default:
275                throw new VirtualCollectionRegistryUsageException("invalid state");
276        }
277        registry.setVirtualCollectionState(principal, id, vc_state);
278        RestResponse response = new RestResponse();
279        response.setIsSuccess(true);
280        response.setInfo("updated state to '" + state + "'");
281        response.setId(id);
282        return Response.ok(response).build();
283    }
284}
Note: See TracBrowser for help on using the repository browser.