2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.vocabulary;
26 import java.util.List;
29 import javax.ws.rs.Consumes;
30 import javax.ws.rs.DELETE;
31 import javax.ws.rs.GET;
32 import javax.ws.rs.POST;
33 import javax.ws.rs.PUT;
34 import javax.ws.rs.Path;
35 import javax.ws.rs.PathParam;
36 import javax.ws.rs.Produces;
37 import javax.ws.rs.QueryParam;
38 import javax.ws.rs.WebApplicationException;
39 import javax.ws.rs.core.Context;
40 import javax.ws.rs.core.MultivaluedMap;
41 import javax.ws.rs.core.Response;
42 import javax.ws.rs.core.UriBuilder;
43 import javax.ws.rs.core.UriInfo;
45 import org.collectionspace.services.common.AbstractCollectionSpaceResource;
46 import org.collectionspace.services.common.ClientType;
47 import org.collectionspace.services.common.ServiceMain;
48 import org.collectionspace.services.common.context.RemoteServiceContext;
49 import org.collectionspace.services.common.context.ServiceContext;
50 import org.collectionspace.services.common.repository.DocumentFilter;
51 import org.collectionspace.services.common.repository.DocumentHandler;
52 import org.collectionspace.services.common.repository.DocumentNotFoundException;
53 import org.collectionspace.services.vocabulary.nuxeo.VocabularyHandlerFactory;
54 import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemDocumentModelHandler;
55 import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemHandlerFactory;
56 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
57 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
58 import org.jboss.resteasy.util.HttpResponseCodes;
59 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
60 import org.nuxeo.ecm.core.client.NuxeoClient;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
64 @Path("/vocabularies")
65 @Consumes("multipart/mixed")
66 @Produces("multipart/mixed")
67 public class VocabularyResource extends AbstractCollectionSpaceResource {
69 private final static String vocabularyServiceName = "vocabularies";
70 private final static String vocabularyItemServiceName = "vocabularyitems";
71 final Logger logger = LoggerFactory.getLogger(VocabularyResource.class);
72 //FIXME retrieve client type from configuration
73 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType();
75 public VocabularyResource() {
80 public String getServiceName() {
81 return vocabularyServiceName;
84 public String getItemServiceName() {
85 return vocabularyItemServiceName;
89 public RemoteServiceContext createItemServiceContext(MultipartInput input) throws Exception {
90 RemoteServiceContext ctx = new RemoteServiceContextImpl(getItemServiceName());
97 public DocumentHandler createDocumentHandler(RemoteServiceContext ctx) throws Exception {
98 DocumentHandler docHandler = VocabularyHandlerFactory.getInstance().getHandler(
99 ctx.getRepositoryClientType().toString());
100 docHandler.setServiceContext(ctx);
101 if(ctx.getInput() != null){
102 Object obj = ctx.getInputPart(ctx.getCommonPartLabel(), VocabulariesCommon.class);
104 docHandler.setCommonPart((VocabulariesCommon) obj);
110 private DocumentHandler createItemDocumentHandler(
111 RemoteServiceContext ctx,
112 String inVocabulary) throws Exception {
113 DocumentHandler docHandler = VocabularyItemHandlerFactory.getInstance().getHandler(
114 ctx.getRepositoryClientType().toString());
115 docHandler.setServiceContext(ctx);
116 ((VocabularyItemDocumentModelHandler)docHandler).setInVocabulary(inVocabulary);
117 if(ctx.getInput() != null){
118 Object obj = ctx.getInputPart(ctx.getCommonPartLabel(getItemServiceName()),
119 VocabularyitemsCommon.class);
121 docHandler.setCommonPart((VocabularyitemsCommon) obj);
128 public Response createVocabulary(MultipartInput input) {
130 RemoteServiceContext ctx = createServiceContext(input);
131 DocumentHandler handler = createDocumentHandler(ctx);
132 String csid = getRepositoryClient(ctx).create(ctx, handler);
133 //vocabularyObject.setCsid(csid);
134 UriBuilder path = UriBuilder.fromResource(VocabularyResource.class);
135 path.path("" + csid);
136 Response response = Response.created(path.build()).build();
139 if(logger.isDebugEnabled()){
140 logger.debug("Caught exception in createVocabulary", e);
142 Response response = Response.status(
143 Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
144 throw new WebApplicationException(response);
150 public MultipartOutput getVocabulary(@PathParam("csid") String csid) {
151 String idValue = null;
153 logger.error("getVocabulary: missing csid!");
154 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
155 "get failed on Vocabulary csid=" + csid).type(
156 "text/plain").build();
157 throw new WebApplicationException(response);
159 if(logger.isDebugEnabled()){
160 logger.debug("getVocabulary with path(id)=" + csid);
162 MultipartOutput result = null;
164 RemoteServiceContext ctx = createServiceContext(null);
165 DocumentHandler handler = createDocumentHandler(ctx);
166 getRepositoryClient(ctx).get(ctx, csid, handler);
167 result = ctx.getOutput();
168 }catch(DocumentNotFoundException dnfe){
169 if(logger.isDebugEnabled()){
170 logger.debug("getVocabulary", dnfe);
172 Response response = Response.status(Response.Status.NOT_FOUND).entity(
173 "Get failed on Vocabulary csid=" + csid).type(
174 "text/plain").build();
175 throw new WebApplicationException(response);
177 if(logger.isDebugEnabled()){
178 logger.debug("getVocabulary", e);
180 Response response = Response.status(
181 Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
182 throw new WebApplicationException(response);
185 Response response = Response.status(Response.Status.NOT_FOUND).entity(
186 "Get failed, the requested Vocabulary CSID:" + csid + ": was not found.").type(
187 "text/plain").build();
188 throw new WebApplicationException(response);
194 @Produces("application/xml")
195 public VocabulariesCommonList getVocabularyList(@Context UriInfo ui) {
196 VocabulariesCommonList vocabularyObjectList = new VocabulariesCommonList();
198 RemoteServiceContext ctx = createServiceContext(null);
199 DocumentHandler handler = createDocumentHandler(ctx);
200 MultivaluedMap<String,String> queryParams = ui.getQueryParameters();
201 if(queryParams.size()>0) {
202 String nameQ = queryParams.getFirst("name");
204 DocumentFilter myFilter = new DocumentFilter(
205 "vocabularies_common:refName='"+nameQ+"'", 0, 0);
206 handler.setDocumentFilter(myFilter);
209 getRepositoryClient(ctx).getFiltered(ctx, handler);
210 vocabularyObjectList = (VocabulariesCommonList) handler.getCommonPartList();
212 if(logger.isDebugEnabled()){
213 logger.debug("Caught exception in getVocabularyList", e);
215 Response response = Response.status(
216 Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
217 throw new WebApplicationException(response);
219 return vocabularyObjectList;
224 public MultipartOutput updateVocabulary(
225 @PathParam("csid") String csid,
226 MultipartInput theUpdate) {
227 if(logger.isDebugEnabled()){
228 logger.debug("updateVocabulary with csid=" + csid);
230 if(csid == null || "".equals(csid)){
231 logger.error("updateVocabulary: missing csid!");
232 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
233 "update failed on Vocabulary csid=" + csid).type(
234 "text/plain").build();
235 throw new WebApplicationException(response);
237 MultipartOutput result = null;
239 RemoteServiceContext ctx = createServiceContext(theUpdate);
240 DocumentHandler handler = createDocumentHandler(ctx);
241 getRepositoryClient(ctx).update(ctx, csid, handler);
242 result = ctx.getOutput();
243 }catch(DocumentNotFoundException dnfe){
244 if(logger.isDebugEnabled()){
245 logger.debug("caugth exception in updateVocabulary", dnfe);
247 Response response = Response.status(Response.Status.NOT_FOUND).entity(
248 "Update failed on Vocabulary csid=" + csid).type(
249 "text/plain").build();
250 throw new WebApplicationException(response);
252 Response response = Response.status(
253 Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
254 throw new WebApplicationException(response);
261 public Response deleteVocabulary(@PathParam("csid") String csid) {
263 if(logger.isDebugEnabled()){
264 logger.debug("deleteVocabulary with csid=" + csid);
266 if(csid == null || "".equals(csid)){
267 logger.error("deleteVocabulary: missing csid!");
268 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
269 "delete failed on Vocabulary csid=" + csid).type(
270 "text/plain").build();
271 throw new WebApplicationException(response);
274 ServiceContext ctx = createServiceContext(null);
275 getRepositoryClient(ctx).delete(ctx, csid);
276 return Response.status(HttpResponseCodes.SC_OK).build();
277 }catch(DocumentNotFoundException dnfe){
278 if(logger.isDebugEnabled()){
279 logger.debug("caught exception in deleteVocabulary", dnfe);
281 Response response = Response.status(Response.Status.NOT_FOUND).entity(
282 "Delete failed on Vocabulary csid=" + csid).type(
283 "text/plain").build();
284 throw new WebApplicationException(response);
286 Response response = Response.status(
287 Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
288 throw new WebApplicationException(response);
293 /*************************************************************************
294 * VocabularyItem parts - this is a sub-resource of Vocabulary
295 *************************************************************************/
298 @Path("{csid}/items")
299 public Response createVocabularyItem(@PathParam("csid") String parentcsid, MultipartInput input) {
301 RemoteServiceContext ctx = createServiceContext(input, getItemServiceName());
302 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
303 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
304 UriBuilder path = UriBuilder.fromResource(VocabularyResource.class);
305 path.path(parentcsid + "/items/" + itemcsid);
306 Response response = Response.created(path.build()).build();
309 if(logger.isDebugEnabled()){
310 logger.debug("Caught exception in createVocabularyItem", e);
312 Response response = Response.status(
313 Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
314 throw new WebApplicationException(response);
319 @Path("{csid}/items/{itemcsid}")
320 public MultipartOutput getVocabularyItem(
321 @PathParam("csid") String parentcsid,
322 @PathParam("itemcsid") String itemcsid) {
323 if(logger.isDebugEnabled()){
324 logger.debug("getVocabularyItem with parentcsid="
325 + parentcsid + " and itemcsid=" + itemcsid);
327 if(parentcsid == null || "".equals(parentcsid)){
328 logger.error("getVocabularyItem: missing csid!");
329 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
330 "get failed on VocabularyItem csid=" + parentcsid).type(
331 "text/plain").build();
332 throw new WebApplicationException(response);
334 if(itemcsid == null || "".equals(itemcsid)){
335 logger.error("getVocabularyItem: missing itemcsid!");
336 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
337 "get failed on VocabularyItem itemcsid=" + itemcsid).type(
338 "text/plain").build();
339 throw new WebApplicationException(response);
341 MultipartOutput result = null;
343 // Note that we have to create the service context for the Items, not the main service
344 RemoteServiceContext ctx = createServiceContext(null, getItemServiceName());
345 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
346 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
347 // TODO should we assert that the item is in the passed vocab?
348 result = ctx.getOutput();
349 }catch(DocumentNotFoundException dnfe){
350 if(logger.isDebugEnabled()){
351 logger.debug("getVocabularyItem", dnfe);
353 Response response = Response.status(Response.Status.NOT_FOUND).entity(
354 "Get failed on VocabularyItem csid=" + itemcsid).type(
355 "text/plain").build();
356 throw new WebApplicationException(response);
358 if(logger.isDebugEnabled()){
359 logger.debug("getVocabularyItem", e);
361 Response response = Response.status(
362 Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
363 throw new WebApplicationException(response);
366 Response response = Response.status(Response.Status.NOT_FOUND).entity(
367 "Get failed, the requested VocabularyItem CSID:" + itemcsid + ": was not found.").type(
368 "text/plain").build();
369 throw new WebApplicationException(response);
375 @Path("{csid}/items")
376 @Produces("application/xml")
377 public VocabularyitemsCommonList getVocabularyItemList(
378 @PathParam("csid") String parentcsid,
379 @Context UriInfo ui) {
380 VocabularyitemsCommonList vocabularyItemObjectList = new VocabularyitemsCommonList();
381 RepositoryInstance repoSession = null;
382 NuxeoClient client = null;
384 // Note that docType defaults to the ServiceName, so we're fine with that.
385 RemoteServiceContext ctx = createServiceContext(null, getItemServiceName());
386 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
388 // Note that we replace the getAll() call with a basic search on the parent vocab
389 handler.prepare(Action.GET_ALL);
390 client = NuxeoConnector.getInstance().getClient();
391 repoSession = client.openRepository();
392 if (logger.isDebugEnabled()) {
393 logger.debug("getVocabularyItemList() repository root: " + repoSession.getRootDocument());
395 DocumentModelList docList =
396 repoSession.query("SELECT * FROM Vocabularyitem WHERE vocabularyitems_common:inVocabulary='"
398 //set repoSession to handle the document
399 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
400 DocumentModelListWrapper wrapDoc = new DocumentModelListWrapper(
402 handler.handle(Action.GET_ALL, wrapDoc);
403 handler.complete(Action.GET_ALL, wrapDoc);
405 DocumentFilter myFilter = new DocumentFilter(
406 "vocabularyitems_common:inVocabulary='"+parentcsid+"'", 0, 0);
407 handler.setDocumentFilter(myFilter);
408 getRepositoryClient(ctx).getFiltered(ctx, handler);
409 vocabularyItemObjectList = (VocabularyitemsCommonList) handler.getCommonPartList();
411 if(logger.isDebugEnabled()){
412 logger.debug("Caught exception in getVocabularyItemList", e);
414 Response response = Response.status(
415 Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
416 throw new WebApplicationException(response);
418 if(repoSession != null) {
421 client.releaseRepository(repoSession);
422 } catch (Exception e) {
423 logger.error("Could not close the repository session", e);
424 // no need to throw this service specific exception
428 return vocabularyItemObjectList;
432 @Path("{csid}/items/{itemcsid}")
433 public MultipartOutput updateVocabularyItem(
434 @PathParam("csid") String parentcsid,
435 @PathParam("itemcsid") String itemcsid,
436 MultipartInput theUpdate) {
437 if(logger.isDebugEnabled()){
438 logger.debug("updateVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
440 if(parentcsid == null || "".equals(parentcsid)){
441 logger.error("updateVocabularyItem: missing csid!");
442 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
443 "update failed on VocabularyItem parentcsid=" + parentcsid).type(
444 "text/plain").build();
445 throw new WebApplicationException(response);
447 if(itemcsid == null || "".equals(itemcsid)){
448 logger.error("updateVocabularyItem: missing itemcsid!");
449 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
450 "update failed on VocabularyItem=" + itemcsid).type(
451 "text/plain").build();
452 throw new WebApplicationException(response);
454 MultipartOutput result = null;
456 // Note that we have to create the service context for the Items, not the main service
457 RemoteServiceContext ctx = createServiceContext(theUpdate, getItemServiceName());
458 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
459 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
460 result = ctx.getOutput();
461 }catch(DocumentNotFoundException dnfe){
462 if(logger.isDebugEnabled()){
463 logger.debug("caugth exception in updateVocabularyItem", dnfe);
465 Response response = Response.status(Response.Status.NOT_FOUND).entity(
466 "Update failed on VocabularyItem csid=" + itemcsid).type(
467 "text/plain").build();
468 throw new WebApplicationException(response);
470 Response response = Response.status(
471 Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
472 throw new WebApplicationException(response);
478 @Path("{csid}/items/{itemcsid}")
479 public Response deleteVocabularyItem(
480 @PathParam("csid") String parentcsid,
481 @PathParam("itemcsid") String itemcsid) {
482 if(logger.isDebugEnabled()){
483 logger.debug("deleteVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
485 if(parentcsid == null || "".equals(parentcsid)){
486 logger.error("deleteVocabularyItem: missing csid!");
487 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
488 "delete failed on VocabularyItem parentcsid=" + parentcsid).type(
489 "text/plain").build();
490 throw new WebApplicationException(response);
492 if(itemcsid == null || "".equals(itemcsid)){
493 logger.error("deleteVocabularyItem: missing itemcsid!");
494 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
495 "delete failed on VocabularyItem=" + itemcsid).type(
496 "text/plain").build();
497 throw new WebApplicationException(response);
500 // Note that we have to create the service context for the Items, not the main service
501 RemoteServiceContext ctx = createServiceContext(null, getItemServiceName());
502 getRepositoryClient(ctx).delete(ctx, itemcsid);
503 return Response.status(HttpResponseCodes.SC_OK).build();
504 }catch(DocumentNotFoundException dnfe){
505 if(logger.isDebugEnabled()){
506 logger.debug("caught exception in deleteVocabulary", dnfe);
508 Response response = Response.status(Response.Status.NOT_FOUND).entity(
509 "Delete failed on VocabularyItem itemcsid=" + itemcsid).type(
510 "text/plain").build();
511 throw new WebApplicationException(response);
513 Response response = Response.status(
514 Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
515 throw new WebApplicationException(response);