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.AbstractMultiPartCollectionSpaceResourceImpl;
44 import org.collectionspace.services.common.ClientType;
45 import org.collectionspace.services.common.ServiceMain;
46 import org.collectionspace.services.common.context.ServiceContext;
47 import org.collectionspace.services.common.document.BadRequestException;
48 import org.collectionspace.services.common.document.DocumentFilter;
49 import org.collectionspace.services.common.document.DocumentHandler;
50 import org.collectionspace.services.common.document.DocumentNotFoundException;
51 import org.collectionspace.services.common.security.UnauthorizedException;
52 import org.collectionspace.services.common.query.IQueryManager;
53 import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemDocumentModelHandler;
54 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
55 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
56 import org.jboss.resteasy.util.HttpResponseCodes;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
61 * The Class VocabularyResource.
63 @Path("/vocabularies")
64 @Consumes("multipart/mixed")
65 @Produces("multipart/mixed")
66 public class VocabularyResource extends
67 AbstractMultiPartCollectionSpaceResourceImpl {
69 /** The Constant vocabularyServiceName. */
70 private final static String vocabularyServiceName = "vocabularies";
72 /** The Constant vocabularyItemServiceName. */
73 private final static String vocabularyItemServiceName = "vocabularyitems";
76 final Logger logger = LoggerFactory.getLogger(VocabularyResource.class);
77 //FIXME retrieve client type from configuration
78 /** The Constant CLIENT_TYPE. */
79 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType();
82 * Instantiates a new vocabulary resource.
84 public VocabularyResource() {
89 * @see org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl#getVersionString()
92 protected String getVersionString() {
93 /** The last change revision. */
94 final String lastChangeRevision = "$LastChangedRevision$";
95 return lastChangeRevision;
99 * @see org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl#getServiceName()
102 public String getServiceName() {
103 return vocabularyServiceName;
107 * @see org.collectionspace.services.common.CollectionSpaceResource#getCommonPartClass()
110 public Class<VocabulariesCommon> getCommonPartClass() {
111 return VocabulariesCommon.class;
115 * Gets the item service name.
117 * @return the item service name
119 public String getItemServiceName() {
120 return vocabularyItemServiceName;
124 * Creates the item document handler.
127 * @param inVocabulary the in vocabulary
129 * @return the document handler
131 * @throws Exception the exception
133 private DocumentHandler createItemDocumentHandler(
134 ServiceContext<MultipartInput, MultipartOutput> ctx,
137 VocabularyItemDocumentModelHandler docHandler;
139 docHandler = (VocabularyItemDocumentModelHandler)createDocumentHandler(ctx,
140 ctx.getCommonPartLabel(getItemServiceName()),
141 VocabularyitemsCommon.class);
142 docHandler.setInVocabulary(inVocabulary);
148 * Creates the vocabulary.
150 * @param input the input
152 * @return the response
155 public Response createVocabulary(MultipartInput input) {
157 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(input);
158 DocumentHandler handler = createDocumentHandler(ctx);
159 String csid = getRepositoryClient(ctx).create(ctx, handler);
160 //vocabularyObject.setCsid(csid);
161 UriBuilder path = UriBuilder.fromResource(VocabularyResource.class);
162 path.path("" + csid);
163 Response response = Response.created(path.build()).build();
165 } catch (UnauthorizedException ue) {
166 Response response = Response.status(
167 Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
168 throw new WebApplicationException(response);
169 } catch (Exception e) {
170 if (logger.isDebugEnabled()) {
171 logger.debug("Caught exception in createVocabulary", e);
173 Response response = Response.status(
174 Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
175 throw new WebApplicationException(response);
180 * Gets the vocabulary.
182 * @param csid the csid
184 * @return the vocabulary
188 public MultipartOutput getVocabulary(@PathParam("csid") String csid) {
189 // String idValue = null;
191 logger.error("getVocabulary: missing csid!");
192 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
193 "get failed on Vocabulary csid=" + csid).type(
194 "text/plain").build();
195 throw new WebApplicationException(response);
197 if (logger.isDebugEnabled()) {
198 logger.debug("getVocabulary with path(id)=" + csid);
200 MultipartOutput result = null;
202 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext();
203 DocumentHandler handler = createDocumentHandler(ctx);
204 getRepositoryClient(ctx).get(ctx, csid, handler);
205 result = (MultipartOutput) ctx.getOutput();
206 } catch (UnauthorizedException ue) {
207 Response response = Response.status(
208 Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
209 throw new WebApplicationException(response);
210 } catch (DocumentNotFoundException dnfe) {
211 if (logger.isDebugEnabled()) {
212 logger.debug("getVocabulary", dnfe);
214 Response response = Response.status(Response.Status.NOT_FOUND).entity(
215 "Get failed on Vocabulary csid=" + csid).type(
216 "text/plain").build();
217 throw new WebApplicationException(response);
218 } catch (Exception e) {
219 if (logger.isDebugEnabled()) {
220 logger.debug("getVocabulary", e);
222 Response response = Response.status(
223 Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
224 throw new WebApplicationException(response);
227 if (result == null) {
228 Response response = Response.status(Response.Status.NOT_FOUND).entity(
229 "Get failed, the requested Vocabulary CSID:" + csid + ": was not found.").type(
230 "text/plain").build();
231 throw new WebApplicationException(response);
238 * Gets the vocabulary list.
242 * @return the vocabulary list
245 @Produces("application/xml")
246 public VocabulariesCommonList getVocabularyList(@Context UriInfo ui) {
247 VocabulariesCommonList vocabularyObjectList = new VocabulariesCommonList();
249 MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
250 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(queryParams);
251 DocumentHandler handler = createDocumentHandler(ctx);
252 // DocumentFilter myFilter = handler.createDocumentFilter(); //new DocumentFilter();
253 DocumentFilter myFilter = handler.getDocumentFilter();
254 // myFilter.setPagination(queryParams);
255 String nameQ = queryParams.getFirst("refName");
257 myFilter.setWhereClause("vocabularies_common:refName='" + nameQ + "'");
259 // handler.setDocumentFilter(myFilter);
260 getRepositoryClient(ctx).getFiltered(ctx, handler);
261 vocabularyObjectList = (VocabulariesCommonList) handler.getCommonPartList();
262 } catch (UnauthorizedException ue) {
263 Response response = Response.status(
264 Response.Status.UNAUTHORIZED).entity("Index failed reason " + ue.getErrorReason()).type("text/plain").build();
265 throw new WebApplicationException(response);
266 } catch (Exception e) {
267 if (logger.isDebugEnabled()) {
268 logger.debug("Caught exception in getVocabularyList", e);
270 Response response = Response.status(
271 Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
272 throw new WebApplicationException(response);
274 return vocabularyObjectList;
280 * @param csid the csid
281 * @param theUpdate the the update
283 * @return the multipart output
287 public MultipartOutput updateVocabulary(
288 @PathParam("csid") String csid,
289 MultipartInput theUpdate) {
290 if (logger.isDebugEnabled()) {
291 logger.debug("updateVocabulary with csid=" + csid);
293 if (csid == null || "".equals(csid)) {
294 logger.error("updateVocabulary: missing csid!");
295 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
296 "update failed on Vocabulary csid=" + csid).type(
297 "text/plain").build();
298 throw new WebApplicationException(response);
300 MultipartOutput result = null;
302 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(theUpdate);
303 DocumentHandler handler = createDocumentHandler(ctx);
304 getRepositoryClient(ctx).update(ctx, csid, handler);
305 result = (MultipartOutput) ctx.getOutput();
306 } catch (UnauthorizedException ue) {
307 Response response = Response.status(
308 Response.Status.UNAUTHORIZED).entity("Update failed reason " + ue.getErrorReason()).type("text/plain").build();
309 throw new WebApplicationException(response);
310 } catch (DocumentNotFoundException dnfe) {
311 if (logger.isDebugEnabled()) {
312 logger.debug("caugth exception in updateVocabulary", dnfe);
314 Response response = Response.status(Response.Status.NOT_FOUND).entity(
315 "Update failed on Vocabulary csid=" + csid).type(
316 "text/plain").build();
317 throw new WebApplicationException(response);
318 } catch (Exception e) {
319 Response response = Response.status(
320 Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
321 throw new WebApplicationException(response);
329 * @param csid the csid
331 * @return the response
335 public Response deleteVocabulary(@PathParam("csid") String csid) {
337 if (logger.isDebugEnabled()) {
338 logger.debug("deleteVocabulary with csid=" + csid);
340 if (csid == null || "".equals(csid)) {
341 logger.error("deleteVocabulary: missing csid!");
342 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
343 "delete failed on Vocabulary csid=" + csid).type(
344 "text/plain").build();
345 throw new WebApplicationException(response);
348 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext();
349 getRepositoryClient(ctx).delete(ctx, csid);
350 return Response.status(HttpResponseCodes.SC_OK).build();
351 } catch (UnauthorizedException ue) {
352 Response response = Response.status(
353 Response.Status.UNAUTHORIZED).entity("Delete failed reason " + ue.getErrorReason()).type("text/plain").build();
354 throw new WebApplicationException(response);
355 } catch (DocumentNotFoundException dnfe) {
356 if (logger.isDebugEnabled()) {
357 logger.debug("caught exception in deleteVocabulary", dnfe);
359 Response response = Response.status(Response.Status.NOT_FOUND).entity(
360 "Delete failed on Vocabulary csid=" + csid).type(
361 "text/plain").build();
362 throw new WebApplicationException(response);
363 } catch (Exception e) {
364 Response response = Response.status(
365 Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
366 throw new WebApplicationException(response);
371 /*************************************************************************
372 * VocabularyItem parts - this is a sub-resource of Vocabulary
375 * @return vocab item response
376 *************************************************************************/
378 @Path("{csid}/items")
379 public Response createVocabularyItem(@PathParam("csid") String parentcsid, MultipartInput input) {
381 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(getItemServiceName(),
383 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
384 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
385 UriBuilder path = UriBuilder.fromResource(VocabularyResource.class);
386 path.path(parentcsid + "/items/" + itemcsid);
387 Response response = Response.created(path.build()).build();
389 } catch (BadRequestException bre) {
390 Response response = Response.status(
391 Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
392 throw new WebApplicationException(response);
393 } catch (UnauthorizedException ue) {
394 Response response = Response.status(
395 Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
396 throw new WebApplicationException(response);
397 } catch (Exception e) {
398 if (logger.isDebugEnabled()) {
399 logger.debug("Caught exception in createVocabularyItem", e);
401 Response response = Response.status(
402 Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
403 throw new WebApplicationException(response);
408 * Gets the vocabulary item.
410 * @param parentcsid the parentcsid
411 * @param itemcsid the itemcsid
413 * @return the vocabulary item
416 @Path("{csid}/items/{itemcsid}")
417 public MultipartOutput getVocabularyItem(
418 @PathParam("csid") String parentcsid,
419 @PathParam("itemcsid") String itemcsid) {
420 if (logger.isDebugEnabled()) {
421 logger.debug("getVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
423 if (parentcsid == null || "".equals(parentcsid)) {
424 logger.error("getVocabularyItem: missing csid!");
425 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
426 "get failed on VocabularyItem csid=" + parentcsid).type(
427 "text/plain").build();
428 throw new WebApplicationException(response);
430 if (itemcsid == null || "".equals(itemcsid)) {
431 logger.error("getVocabularyItem: missing itemcsid!");
432 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
433 "get failed on VocabularyItem itemcsid=" + itemcsid).type(
434 "text/plain").build();
435 throw new WebApplicationException(response);
437 MultipartOutput result = null;
439 // Note that we have to create the service context for the Items, not the main service
440 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(getItemServiceName());
441 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
442 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
443 // TODO should we assert that the item is in the passed vocab?
444 result = (MultipartOutput) ctx.getOutput();
445 } catch (UnauthorizedException ue) {
446 Response response = Response.status(
447 Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
448 throw new WebApplicationException(response);
449 } catch (DocumentNotFoundException dnfe) {
450 if (logger.isDebugEnabled()) {
451 logger.debug("getVocabularyItem", dnfe);
453 Response response = Response.status(Response.Status.NOT_FOUND).entity(
454 "Get failed on VocabularyItem csid=" + itemcsid).type(
455 "text/plain").build();
456 throw new WebApplicationException(response);
457 } catch (Exception e) {
458 if (logger.isDebugEnabled()) {
459 logger.debug("getVocabularyItem", e);
461 Response response = Response.status(
462 Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
463 throw new WebApplicationException(response);
465 if (result == null) {
466 Response response = Response.status(Response.Status.NOT_FOUND).entity(
467 "Get failed, the requested VocabularyItem CSID:" + itemcsid + ": was not found.").type(
468 "text/plain").build();
469 throw new WebApplicationException(response);
475 * Gets the vocabulary item list.
477 * @param parentcsid the parentcsid
478 * @param partialTerm the partial term
481 * @return the vocabulary item list
484 @Path("{csid}/items")
485 @Produces("application/xml")
486 public VocabularyitemsCommonList getVocabularyItemList(
487 @PathParam("csid") String parentcsid,
488 @QueryParam(IQueryManager.SEARCH_TYPE_PARTIALTERM) String partialTerm,
489 @Context UriInfo ui) {
490 VocabularyitemsCommonList vocabularyItemObjectList = new VocabularyitemsCommonList();
492 MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
493 // Note that docType defaults to the ServiceName, so we're fine with that.
494 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(getItemServiceName(),
496 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
497 DocumentFilter myFilter = handler.getDocumentFilter();
498 myFilter.setWhereClause(
499 VocabularyItemJAXBSchema.VOCABULARYITEMS_COMMON + ":"
500 + VocabularyItemJAXBSchema.IN_VOCABULARY + "="
501 + "'" + parentcsid + "'");
503 // AND vocabularyitems_common:displayName LIKE '%partialTerm%'
504 if (partialTerm != null && !partialTerm.isEmpty()) {
505 String ptClause = VocabularyItemJAXBSchema.VOCABULARYITEMS_COMMON + ":"
506 + VocabularyItemJAXBSchema.DISPLAY_NAME
507 + IQueryManager.SEARCH_LIKE
508 + "'%" + partialTerm + "%'";
509 myFilter.appendWhereClause(ptClause, IQueryManager.SEARCH_QUALIFIER_AND);
511 if (logger.isDebugEnabled()) {
512 logger.debug("getVocabularyItemList filtered WHERE clause: "
513 + myFilter.getWhereClause());
515 getRepositoryClient(ctx).getFiltered(ctx, handler);
516 vocabularyItemObjectList = (VocabularyitemsCommonList) handler.getCommonPartList();
517 } catch (UnauthorizedException ue) {
518 Response response = Response.status(
519 Response.Status.UNAUTHORIZED).entity("Index failed reason " + ue.getErrorReason()).type("text/plain").build();
520 throw new WebApplicationException(response);
521 } catch (Exception e) {
522 if (logger.isDebugEnabled()) {
523 logger.debug("Caught exception in getVocabularyItemList", e);
525 Response response = Response.status(
526 Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
527 throw new WebApplicationException(response);
529 return vocabularyItemObjectList;
533 * Update vocabulary item.
535 * @param parentcsid the parentcsid
536 * @param itemcsid the itemcsid
537 * @param theUpdate the the update
539 * @return the multipart output
542 @Path("{csid}/items/{itemcsid}")
543 public MultipartOutput updateVocabularyItem(
544 @PathParam("csid") String parentcsid,
545 @PathParam("itemcsid") String itemcsid,
546 MultipartInput theUpdate) {
547 if (logger.isDebugEnabled()) {
548 logger.debug("updateVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
550 if (parentcsid == null || "".equals(parentcsid)) {
551 logger.error("updateVocabularyItem: missing csid!");
552 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
553 "update failed on VocabularyItem parentcsid=" + parentcsid).type(
554 "text/plain").build();
555 throw new WebApplicationException(response);
557 if (itemcsid == null || "".equals(itemcsid)) {
558 logger.error("updateVocabularyItem: missing itemcsid!");
559 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
560 "update failed on VocabularyItem=" + itemcsid).type(
561 "text/plain").build();
562 throw new WebApplicationException(response);
564 MultipartOutput result = null;
566 // Note that we have to create the service context for the Items, not the main service
567 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(getItemServiceName(),
569 DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
570 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
571 result = (MultipartOutput) ctx.getOutput();
572 } catch (BadRequestException bre) {
573 Response response = Response.status(
574 Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
575 throw new WebApplicationException(response);
576 } catch (UnauthorizedException ue) {
577 Response response = Response.status(
578 Response.Status.UNAUTHORIZED).entity("Update failed reason " + ue.getErrorReason()).type("text/plain").build();
579 throw new WebApplicationException(response);
580 } catch (DocumentNotFoundException dnfe) {
581 if (logger.isDebugEnabled()) {
582 logger.debug("caught DNF exception in updateVocabularyItem", dnfe);
584 Response response = Response.status(Response.Status.NOT_FOUND).entity(
585 "Update failed on VocabularyItem csid=" + itemcsid).type(
586 "text/plain").build();
587 throw new WebApplicationException(response);
588 } catch (Exception e) {
589 Response response = Response.status(
590 Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
591 throw new WebApplicationException(response);
597 * Delete vocabulary item.
599 * @param parentcsid the parentcsid
600 * @param itemcsid the itemcsid
602 * @return the response
605 @Path("{csid}/items/{itemcsid}")
606 public Response deleteVocabularyItem(
607 @PathParam("csid") String parentcsid,
608 @PathParam("itemcsid") String itemcsid) {
609 if (logger.isDebugEnabled()) {
610 logger.debug("deleteVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
612 if (parentcsid == null || "".equals(parentcsid)) {
613 logger.error("deleteVocabularyItem: missing csid!");
614 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
615 "delete failed on VocabularyItem parentcsid=" + parentcsid).type(
616 "text/plain").build();
617 throw new WebApplicationException(response);
619 if (itemcsid == null || "".equals(itemcsid)) {
620 logger.error("deleteVocabularyItem: missing itemcsid!");
621 Response response = Response.status(Response.Status.BAD_REQUEST).entity(
622 "delete failed on VocabularyItem=" + itemcsid).type(
623 "text/plain").build();
624 throw new WebApplicationException(response);
627 // Note that we have to create the service context for the Items, not the main service
628 ServiceContext<MultipartInput, MultipartOutput> ctx = createServiceContext(getItemServiceName());
629 getRepositoryClient(ctx).delete(ctx, itemcsid);
630 return Response.status(HttpResponseCodes.SC_OK).build();
631 } catch (UnauthorizedException ue) {
632 Response response = Response.status(
633 Response.Status.UNAUTHORIZED).entity("Delete failed reason " + ue.getErrorReason()).type("text/plain").build();
634 throw new WebApplicationException(response);
635 } catch (DocumentNotFoundException dnfe) {
636 if (logger.isDebugEnabled()) {
637 logger.debug("caught exception in deleteVocabulary", dnfe);
639 Response response = Response.status(Response.Status.NOT_FOUND).entity(
640 "Delete failed on VocabularyItem itemcsid=" + itemcsid).type(
641 "text/plain").build();
642 throw new WebApplicationException(response);
643 } catch (Exception e) {
644 Response response = Response.status(
645 Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
646 throw new WebApplicationException(response);