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 javax.ws.rs.Consumes;
27 import javax.ws.rs.DELETE;
28 import javax.ws.rs.GET;
29 import javax.ws.rs.POST;
30 import javax.ws.rs.PUT;
31 import javax.ws.rs.Path;
32 import javax.ws.rs.PathParam;
33 import javax.ws.rs.Produces;
34 import javax.ws.rs.QueryParam;
35 import javax.ws.rs.WebApplicationException;
36 import javax.ws.rs.core.Context;
37 import javax.ws.rs.core.MultivaluedMap;
38 import javax.ws.rs.core.Response;
39 import javax.ws.rs.core.UriBuilder;
40 import javax.ws.rs.core.UriInfo;
42 import org.collectionspace.services.VocabularyItemJAXBSchema;
43 import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
44 import org.collectionspace.services.common.ClientType;
45 import org.collectionspace.services.common.ServiceMain;
46 import org.collectionspace.services.common.context.MultipartServiceContext;
47 import org.collectionspace.services.common.context.MultipartServiceContextFactory;
48 import org.collectionspace.services.common.context.ServiceContext;
49 import org.collectionspace.services.common.document.BadRequestException;
50 import org.collectionspace.services.common.document.DocumentFilter;
51 import org.collectionspace.services.common.document.DocumentHandler;
52 import org.collectionspace.services.common.document.DocumentNotFoundException;
53 import org.collectionspace.services.common.security.UnauthorizedException;
54 import org.collectionspace.services.common.query.IQueryManager;
55 import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemDocumentModelHandler;
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.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 @Path("/vocabularies")
63 @Consumes("multipart/mixed")
64 @Produces("multipart/mixed")
65 public class VocabularyResource extends AbstractCollectionSpaceResourceImpl {
67 private final static String vocabularyServiceName = "vocabularies";
68 private final static String vocabularyItemServiceName = "vocabularyitems";
69 final Logger logger = LoggerFactory.getLogger(VocabularyResource.class);
70 //FIXME retrieve client type from configuration
71 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType();
73 public VocabularyResource() {
78 protected String getVersionString() {
79 /** The last change revision. */
80 final String lastChangeRevision = "$LastChangedRevision$";
81 return lastChangeRevision;
85 public String getServiceName() {
86 return vocabularyServiceName;
89 public String getItemServiceName() {
90 return vocabularyItemServiceName;
94 public RemoteServiceContext createItemServiceContext(MultipartInput input) throws Exception {
95 RemoteServiceContext ctx = new RemoteServiceContextImpl(getItemServiceName());
101 public DocumentHandler createDocumentHandler(ServiceContext ctx) throws Exception {
102 DocumentHandler docHandler = ctx.getDocumentHandler();
103 if (ctx.getInput() != null) {
104 Object obj = ((MultipartServiceContext) ctx).getInputPart(ctx.getCommonPartLabel(), VocabulariesCommon.class);
106 docHandler.setCommonPart((VocabulariesCommon) obj);
112 private DocumentHandler createItemDocumentHandler(
114 String inVocabulary) throws Exception {
115 DocumentHandler docHandler = ctx.getDocumentHandler();
116 ((VocabularyItemDocumentModelHandler) docHandler).setInVocabulary(inVocabulary);
117 if (ctx.getInput() != null) {
118 Object obj = ((MultipartServiceContext) ctx).getInputPart(ctx.getCommonPartLabel(getItemServiceName()),
119 VocabularyitemsCommon.class);
121 docHandler.setCommonPart((VocabularyitemsCommon) obj);
128 public Response createVocabulary(MultipartInput input) {
130 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(input, getServiceName());
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();
138 } catch (UnauthorizedException ue) {
139 Response response = Response.status(
140 Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
141 throw new WebApplicationException(response);
142 } catch (Exception e) {
143 if (logger.isDebugEnabled()) {
144 logger.debug("Caught exception in createVocabulary", e);
146 Response response = Response.status(
147 Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
148 throw new WebApplicationException(response);
154 public MultipartOutput getVocabulary(@PathParam("csid") String csid) {
155 String idValue = null;
157 logger.error("getVocabulary: missing csid!");
158 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
159 "get failed on Vocabulary csid=" + csid).type(
160 "text/plain").build();
161 throw new WebApplicationException(response);
163 if (logger.isDebugEnabled()) {
164 logger.debug("getVocabulary with path(id)=" + csid);
166 MultipartOutput result = null;
168 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getServiceName());
169 DocumentHandler handler = createDocumentHandler(ctx);
170 getRepositoryClient(ctx).get(ctx, csid, handler);
171 result = (MultipartOutput) ctx.getOutput();
172 } catch (UnauthorizedException ue) {
173 Response response = Response.status(
174 Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
175 throw new WebApplicationException(response);
176 } catch (DocumentNotFoundException dnfe) {
177 if (logger.isDebugEnabled()) {
178 logger.debug("getVocabulary", dnfe);
180 Response response = Response.status(Response.Status.NOT_FOUND).entity(
181 "Get failed on Vocabulary csid=" + csid).type(
182 "text/plain").build();
183 throw new WebApplicationException(response);
184 } catch (Exception e) {
185 if (logger.isDebugEnabled()) {
186 logger.debug("getVocabulary", e);
188 Response response = Response.status(
189 Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
190 throw new WebApplicationException(response);
192 if (result == null) {
193 Response response = Response.status(Response.Status.NOT_FOUND).entity(
194 "Get failed, the requested Vocabulary CSID:" + csid + ": was not found.").type(
195 "text/plain").build();
196 throw new WebApplicationException(response);
202 @Produces("application/xml")
203 public VocabulariesCommonList getVocabularyList(@Context UriInfo ui) {
204 VocabulariesCommonList vocabularyObjectList = new VocabulariesCommonList();
206 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getServiceName());
207 MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
208 DocumentHandler handler = createDocumentHandler(ctx);
209 DocumentFilter myFilter = handler.createDocumentFilter(ctx); //new DocumentFilter();
210 myFilter.setPagination(queryParams);
211 String nameQ = queryParams.getFirst("refName");
213 myFilter.setWhereClause("vocabularies_common:refName='" + nameQ + "'");
215 handler.setDocumentFilter(myFilter);
216 getRepositoryClient(ctx).getFiltered(ctx, handler);
217 vocabularyObjectList = (VocabulariesCommonList) handler.getCommonPartList();
218 } catch (UnauthorizedException ue) {
219 Response response = Response.status(
220 Response.Status.UNAUTHORIZED).entity("Index failed reason " + ue.getErrorReason()).type("text/plain").build();
221 throw new WebApplicationException(response);
222 } catch (Exception e) {
223 if (logger.isDebugEnabled()) {
224 logger.debug("Caught exception in getVocabularyList", e);
226 Response response = Response.status(
227 Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
228 throw new WebApplicationException(response);
230 return vocabularyObjectList;
235 public MultipartOutput updateVocabulary(
236 @PathParam("csid") String csid,
237 MultipartInput theUpdate) {
238 if (logger.isDebugEnabled()) {
239 logger.debug("updateVocabulary with csid=" + csid);
241 if (csid == null || "".equals(csid)) {
242 logger.error("updateVocabulary: missing csid!");
243 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
244 "update failed on Vocabulary csid=" + csid).type(
245 "text/plain").build();
246 throw new WebApplicationException(response);
248 MultipartOutput result = null;
250 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(theUpdate, getServiceName());
251 DocumentHandler handler = createDocumentHandler(ctx);
252 getRepositoryClient(ctx).update(ctx, csid, handler);
253 result = (MultipartOutput) ctx.getOutput();
254 } catch (UnauthorizedException ue) {
255 Response response = Response.status(
256 Response.Status.UNAUTHORIZED).entity("Update failed reason " + ue.getErrorReason()).type("text/plain").build();
257 throw new WebApplicationException(response);
258 } catch (DocumentNotFoundException dnfe) {
259 if (logger.isDebugEnabled()) {
260 logger.debug("caugth exception in updateVocabulary", dnfe);
262 Response response = Response.status(Response.Status.NOT_FOUND).entity(
263 "Update failed on Vocabulary csid=" + csid).type(
264 "text/plain").build();
265 throw new WebApplicationException(response);
266 } catch (Exception e) {
267 Response response = Response.status(
268 Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
269 throw new WebApplicationException(response);
276 public Response deleteVocabulary(@PathParam("csid") String csid) {
278 if (logger.isDebugEnabled()) {
279 logger.debug("deleteVocabulary with csid=" + csid);
281 if (csid == null || "".equals(csid)) {
282 logger.error("deleteVocabulary: missing csid!");
283 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
284 "delete failed on Vocabulary csid=" + csid).type(
285 "text/plain").build();
286 throw new WebApplicationException(response);
289 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getServiceName());
290 getRepositoryClient(ctx).delete(ctx, csid);
291 return Response.status(HttpResponseCodes.SC_OK).build();
292 } catch (UnauthorizedException ue) {
293 Response response = Response.status(
294 Response.Status.UNAUTHORIZED).entity("Delete failed reason " + ue.getErrorReason()).type("text/plain").build();
295 throw new WebApplicationException(response);
296 } catch (DocumentNotFoundException dnfe) {
297 if (logger.isDebugEnabled()) {
298 logger.debug("caught exception in deleteVocabulary", dnfe);
300 Response response = Response.status(Response.Status.NOT_FOUND).entity(
301 "Delete failed on Vocabulary csid=" + csid).type(
302 "text/plain").build();
303 throw new WebApplicationException(response);
304 } catch (Exception e) {
305 Response response = Response.status(
306 Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
307 throw new WebApplicationException(response);
312 /*************************************************************************
313 * VocabularyItem parts - this is a sub-resource of Vocabulary
314 *************************************************************************/
316 @Path("{csid}/items")
317 public Response createVocabularyItem(@PathParam("csid") String parentcsid, MultipartInput input) {
319 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(input, getItemServiceName());
320 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
321 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
322 UriBuilder path = UriBuilder.fromResource(VocabularyResource.class);
323 path.path(parentcsid + "/items/" + itemcsid);
324 Response response = Response.created(path.build()).build();
326 } catch (BadRequestException bre) {
327 Response response = Response.status(
328 Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
329 throw new WebApplicationException(response);
330 } catch (UnauthorizedException ue) {
331 Response response = Response.status(
332 Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
333 throw new WebApplicationException(response);
334 } catch (Exception e) {
335 if (logger.isDebugEnabled()) {
336 logger.debug("Caught exception in createVocabularyItem", e);
338 Response response = Response.status(
339 Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
340 throw new WebApplicationException(response);
345 @Path("{csid}/items/{itemcsid}")
346 public MultipartOutput getVocabularyItem(
347 @PathParam("csid") String parentcsid,
348 @PathParam("itemcsid") String itemcsid) {
349 if (logger.isDebugEnabled()) {
350 logger.debug("getVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
352 if (parentcsid == null || "".equals(parentcsid)) {
353 logger.error("getVocabularyItem: missing csid!");
354 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
355 "get failed on VocabularyItem csid=" + parentcsid).type(
356 "text/plain").build();
357 throw new WebApplicationException(response);
359 if (itemcsid == null || "".equals(itemcsid)) {
360 logger.error("getVocabularyItem: missing itemcsid!");
361 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
362 "get failed on VocabularyItem itemcsid=" + itemcsid).type(
363 "text/plain").build();
364 throw new WebApplicationException(response);
366 MultipartOutput result = null;
368 // Note that we have to create the service context for the Items, not the main service
369 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getItemServiceName());
370 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
371 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
372 // TODO should we assert that the item is in the passed vocab?
373 result = (MultipartOutput) ctx.getOutput();
374 } catch (UnauthorizedException ue) {
375 Response response = Response.status(
376 Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
377 throw new WebApplicationException(response);
378 } catch (DocumentNotFoundException dnfe) {
379 if (logger.isDebugEnabled()) {
380 logger.debug("getVocabularyItem", dnfe);
382 Response response = Response.status(Response.Status.NOT_FOUND).entity(
383 "Get failed on VocabularyItem csid=" + itemcsid).type(
384 "text/plain").build();
385 throw new WebApplicationException(response);
386 } catch (Exception e) {
387 if (logger.isDebugEnabled()) {
388 logger.debug("getVocabularyItem", e);
390 Response response = Response.status(
391 Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
392 throw new WebApplicationException(response);
394 if (result == null) {
395 Response response = Response.status(Response.Status.NOT_FOUND).entity(
396 "Get failed, the requested VocabularyItem CSID:" + itemcsid + ": was not found.").type(
397 "text/plain").build();
398 throw new WebApplicationException(response);
404 @Path("{csid}/items")
405 @Produces("application/xml")
406 public VocabularyitemsCommonList getVocabularyItemList(
407 @PathParam("csid") String parentcsid,
408 @QueryParam(IQueryManager.SEARCH_TYPE_PARTIALTERM) String partialTerm,
409 @Context UriInfo ui) {
410 VocabularyitemsCommonList vocabularyItemObjectList = new VocabularyitemsCommonList();
412 // Note that docType defaults to the ServiceName, so we're fine with that.
413 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getItemServiceName());
414 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
415 MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
416 DocumentFilter myFilter = handler.createDocumentFilter(ctx); //new DocumentFilter();
417 myFilter.setPagination(queryParams);
418 // "vocabularyitems_common:inVocabulary='" + parentcsid + "'");
419 myFilter.setWhereClause(
420 VocabularyItemJAXBSchema.VOCABULARYITEMS_COMMON + ":"
421 + VocabularyItemJAXBSchema.IN_VOCABULARY + "="
422 + "'" + parentcsid + "'");
424 // AND vocabularyitems_common:displayName LIKE '%partialTerm%'
425 if (partialTerm != null && !partialTerm.isEmpty()) {
426 String ptClause = "AND "
427 + VocabularyItemJAXBSchema.VOCABULARYITEMS_COMMON + ":"
428 + VocabularyItemJAXBSchema.DISPLAY_NAME
430 + "'%" + partialTerm + "%'";
431 myFilter.appendWhereClause(ptClause);
434 if (logger.isDebugEnabled()) {
435 logger.debug("getVocabularyItemList filtered WHERE clause: "
436 + myFilter.getWhereClause());
439 handler.setDocumentFilter(myFilter);
440 getRepositoryClient(ctx).getFiltered(ctx, handler);
442 vocabularyItemObjectList = (VocabularyitemsCommonList) handler.getCommonPartList();
443 } catch (UnauthorizedException ue) {
444 Response response = Response.status(
445 Response.Status.UNAUTHORIZED).entity("Index failed reason " + ue.getErrorReason()).type("text/plain").build();
446 throw new WebApplicationException(response);
447 } catch (Exception e) {
448 if (logger.isDebugEnabled()) {
449 logger.debug("Caught exception in getVocabularyItemList", e);
451 Response response = Response.status(
452 Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
453 throw new WebApplicationException(response);
455 return vocabularyItemObjectList;
459 @Path("{csid}/items/{itemcsid}")
460 public MultipartOutput updateVocabularyItem(
461 @PathParam("csid") String parentcsid,
462 @PathParam("itemcsid") String itemcsid,
463 MultipartInput theUpdate) {
464 if (logger.isDebugEnabled()) {
465 logger.debug("updateVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
467 if (parentcsid == null || "".equals(parentcsid)) {
468 logger.error("updateVocabularyItem: missing csid!");
469 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
470 "update failed on VocabularyItem parentcsid=" + parentcsid).type(
471 "text/plain").build();
472 throw new WebApplicationException(response);
474 if (itemcsid == null || "".equals(itemcsid)) {
475 logger.error("updateVocabularyItem: missing itemcsid!");
476 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
477 "update failed on VocabularyItem=" + itemcsid).type(
478 "text/plain").build();
479 throw new WebApplicationException(response);
481 MultipartOutput result = null;
483 // Note that we have to create the service context for the Items, not the main service
484 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(theUpdate, getItemServiceName());
485 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
486 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
487 result = (MultipartOutput) ctx.getOutput();
488 } catch (BadRequestException bre) {
489 Response response = Response.status(
490 Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
491 throw new WebApplicationException(response);
492 } catch (UnauthorizedException ue) {
493 Response response = Response.status(
494 Response.Status.UNAUTHORIZED).entity("Update failed reason " + ue.getErrorReason()).type("text/plain").build();
495 throw new WebApplicationException(response);
496 } catch (DocumentNotFoundException dnfe) {
497 if (logger.isDebugEnabled()) {
498 logger.debug("caught DNF exception in updateVocabularyItem", dnfe);
500 Response response = Response.status(Response.Status.NOT_FOUND).entity(
501 "Update failed on VocabularyItem csid=" + itemcsid).type(
502 "text/plain").build();
503 throw new WebApplicationException(response);
504 } catch (Exception e) {
505 Response response = Response.status(
506 Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
507 throw new WebApplicationException(response);
513 @Path("{csid}/items/{itemcsid}")
514 public Response deleteVocabularyItem(
515 @PathParam("csid") String parentcsid,
516 @PathParam("itemcsid") String itemcsid) {
517 if (logger.isDebugEnabled()) {
518 logger.debug("deleteVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
520 if (parentcsid == null || "".equals(parentcsid)) {
521 logger.error("deleteVocabularyItem: missing csid!");
522 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
523 "delete failed on VocabularyItem parentcsid=" + parentcsid).type(
524 "text/plain").build();
525 throw new WebApplicationException(response);
527 if (itemcsid == null || "".equals(itemcsid)) {
528 logger.error("deleteVocabularyItem: missing itemcsid!");
529 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
530 "delete failed on VocabularyItem=" + itemcsid).type(
531 "text/plain").build();
532 throw new WebApplicationException(response);
535 // Note that we have to create the service context for the Items, not the main service
536 ServiceContext ctx = MultipartServiceContextFactory.get().createServiceContext(null, getItemServiceName());
537 getRepositoryClient(ctx).delete(ctx, itemcsid);
538 return Response.status(HttpResponseCodes.SC_OK).build();
539 } catch (UnauthorizedException ue) {
540 Response response = Response.status(
541 Response.Status.UNAUTHORIZED).entity("Delete failed reason " + ue.getErrorReason()).type("text/plain").build();
542 throw new WebApplicationException(response);
543 } catch (DocumentNotFoundException dnfe) {
544 if (logger.isDebugEnabled()) {
545 logger.debug("caught exception in deleteVocabulary", dnfe);
547 Response response = Response.status(Response.Status.NOT_FOUND).entity(
548 "Delete failed on VocabularyItem itemcsid=" + itemcsid).type(
549 "text/plain").build();
550 throw new WebApplicationException(response);
551 } catch (Exception e) {
552 Response response = Response.status(
553 Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
554 throw new WebApplicationException(response);