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.common.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.core.Context;
38 import javax.ws.rs.core.MultivaluedMap;
39 import javax.ws.rs.core.Request;
40 import javax.ws.rs.core.Response;
41 import javax.ws.rs.core.UriBuilder;
42 import javax.ws.rs.core.UriInfo;
44 import org.collectionspace.services.client.*;
45 import org.collectionspace.services.common.CSWebApplicationException;
46 import org.collectionspace.services.common.ResourceMap;
47 import org.collectionspace.services.common.ServiceMessages;
48 import org.collectionspace.services.common.StoredValuesUriTemplate;
49 import org.collectionspace.services.common.UriInfoWrapper;
50 import org.collectionspace.services.common.UriTemplateFactory;
51 import org.collectionspace.services.common.UriTemplateRegistryKey;
52 import org.collectionspace.services.common.vocabulary.AuthorityResource;
53 import org.collectionspace.services.common.context.JaxRsContext;
54 import org.collectionspace.services.common.context.RemoteServiceContext;
55 import org.collectionspace.services.common.context.ServiceContext;
56 import org.collectionspace.services.common.document.BadRequestException;
57 import org.collectionspace.services.common.document.DocumentException;
58 import org.collectionspace.services.common.document.DocumentFilter;
59 import org.collectionspace.services.common.document.DocumentHandler;
60 import org.collectionspace.services.common.document.DocumentNotFoundException;
61 import org.collectionspace.services.contact.ContactResource;
62 import org.collectionspace.services.contact.ContactsCommon;
63 import org.collectionspace.services.contact.ContactJAXBSchema;
64 import org.collectionspace.services.contact.nuxeo.ContactConstants;
65 import org.collectionspace.services.contact.nuxeo.ContactDocumentModelHandler;
66 import org.collectionspace.services.jaxb.AbstractCommonList;
67 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
68 import org.jboss.resteasy.util.HttpResponseCodes;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71 import org.w3c.dom.Element;
74 * The Class AuthorityResourceWithContacts.
76 @Consumes("application/xml")
77 @Produces("application/xml")
78 public abstract class AuthorityResourceWithContacts<AuthCommon, AuthItemHandler> extends //FIXME: REM - Why is this resource in this package instead of somewhere in 'common'?
79 AuthorityResource<AuthCommon, AuthItemHandler> {
81 private ContactResource contactResource = new ContactResource(); // Warning: ContactResource is a singleton.
82 final Logger logger = LoggerFactory.getLogger(AuthorityResourceWithContacts.class);
84 public AuthorityResourceWithContacts(
85 Class<AuthCommon> authCommonClass, Class<?> resourceClass,
86 String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
87 super(authCommonClass, resourceClass,
88 authorityCommonSchemaName, authorityItemCommonSchemaName);
91 public abstract String getItemServiceName();
93 public String getContactServiceName() {
94 return contactResource.getServiceName();
97 private DocumentHandler createContactDocumentHandler(
98 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String inAuthority,
99 String inItem) throws Exception {
101 return createContactDocumentHandler(ctx, inAuthority, inItem, ui);
104 private DocumentHandler createContactDocumentHandler(
105 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String inAuthority,
106 String inItem, UriInfo ui) throws Exception {
107 ContactDocumentModelHandler docHandler = (ContactDocumentModelHandler) createDocumentHandler(
109 ctx.getCommonPartLabel(getContactServiceName()),
110 ContactsCommon.class);
111 docHandler.setInAuthority(inAuthority);
112 docHandler.setInItem(inItem);
113 docHandler.getServiceContext().setUriInfo(ui);
117 /*************************************************************************
118 * Contact parts - this is a sub-resource of the AuthorityItem
119 * @param parentspecifier either a CSID or one of the urn forms
120 * @param itemspecifier either a CSID or one of the urn forms
122 *************************************************************************/
124 @Path("{parentcsid}/items/{itemcsid}/contacts")
125 public Response createContact(
126 @PathParam("parentcsid") String parentspecifier,
127 @PathParam("itemcsid") String itemspecifier,
129 @Context UriInfo ui) {
131 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
132 String parentcsid = lookupParentCSID(parentspecifier, "createContact(authority)", "CREATE_ITEM_CONTACT", null);
134 ServiceContext itemCtx = createServiceContext(getItemServiceName());
135 String itemcsid = lookupItemCSID(itemCtx, itemspecifier, parentcsid, "createContact(item)", "CREATE_ITEM_CONTACT");
137 // Note that we have to create the service context and document
138 // handler for the Contact service, not the main service.
139 ServiceContext ctx = createServiceContext(getContactServiceName(), input);
140 DocumentHandler handler = createContactDocumentHandler(ctx, parentcsid, itemcsid, ui);
141 String csid = getRepositoryClient(ctx).create(ctx, handler);
143 UriBuilder path = UriBuilder.fromResource(resourceClass);
144 path.path("" + parentcsid + "/items/" + itemcsid + "/contacts/" + csid);
145 Response response = Response.created(path.build()).build();
147 } catch (Exception e) {
149 "Create Contact failed; one of the requested specifiers for authority:"
150 + parentspecifier + ": and item:" + itemspecifier + ": was not found.",
155 public String createContact(ServiceContext existingCtx, String parentCsid, String itemCsid, PoxPayloadIn input,
156 UriInfo ui) throws Exception {
157 ServiceContext ctx = createServiceContext(getContactServiceName(), input);
158 if (existingCtx != null) {
159 Object repoSession = existingCtx.getCurrentRepositorySession();
160 if (repoSession != null) {
161 ctx.setCurrentRepositorySession(repoSession);
162 ctx.setProperties(existingCtx.getProperties());
166 DocumentHandler handler = createContactDocumentHandler(ctx, parentCsid, itemCsid, ui);
167 String csid = getRepositoryClient(ctx).create(ctx, handler);
173 * Gets the contact list.
175 * @param parentspecifier either a CSID or one of the urn forms
176 * @param itemspecifier either a CSID or one of the urn forms
179 * @return the contact list
182 @Produces({"application/xml"})
183 @Path("{parentcsid}/items/{itemcsid}/contacts/")
184 public AbstractCommonList getContactList(
185 @PathParam("parentcsid") String parentspecifier,
186 @PathParam("itemcsid") String itemspecifier,
187 @Context UriInfo uriInfo) {
188 AbstractCommonList contactObjectList = new AbstractCommonList();
190 contactObjectList = getContactList(null, parentspecifier, itemspecifier, uriInfo);
192 return contactObjectList;
195 public AbstractCommonList getContactList(
196 ServiceContext existingCtx,
197 String parentspecifier,
198 String itemspecifier,
200 AbstractCommonList contactObjectList = new AbstractCommonList();
203 ServiceContext ctx = createServiceContext(getContactServiceName(), uriInfo);
204 if (existingCtx != null) {
205 Object repoSession = existingCtx.getCurrentRepositorySession();
206 if (repoSession != null) {
207 ctx.setCurrentRepositorySession(repoSession);
208 ctx.setProperties(existingCtx.getProperties());
212 String parentcsid = lookupParentCSID(parentspecifier, "getContactList(parent)", "GET_CONTACT_LIST", null);
213 ServiceContext itemCtx = createServiceContext(getItemServiceName());
214 String itemcsid = lookupItemCSID(itemCtx, itemspecifier, parentcsid, "getContactList(item)", "GET_CONTACT_LIST");
216 DocumentHandler handler = createContactDocumentHandler(ctx, parentcsid, itemcsid, uriInfo);
217 DocumentFilter myFilter = handler.getDocumentFilter(); //new DocumentFilter();
218 myFilter.appendWhereClause(ContactJAXBSchema.CONTACTS_COMMON + ":"
219 + ContactJAXBSchema.IN_AUTHORITY
220 + "='" + parentcsid + "'"
221 + IQueryManager.SEARCH_QUALIFIER_AND
222 + ContactJAXBSchema.CONTACTS_COMMON + ":"
223 + ContactJAXBSchema.IN_ITEM
224 + "='" + itemcsid + "'",
225 IQueryManager.SEARCH_QUALIFIER_AND); // "AND" this clause to any existing
226 getRepositoryClient(ctx).getFiltered(ctx, handler);
227 contactObjectList = (AbstractCommonList) handler.getCommonPartList();
228 } catch (Exception e) {
230 "Get ContactList failed; one of the requested specifiers for authority:"
231 + parentspecifier + ": and item:" + itemspecifier + ": was not found.",
235 return contactObjectList;
239 @Path("{csid}/items/{itemcsid}")
240 public byte[] getAuthorityItem(
241 @Context Request request,
242 @Context UriInfo uriInfo,
243 @Context ResourceMap resourceMap,
244 @PathParam("csid") String parentIdentifier,
245 @PathParam("itemcsid") String itemIdentifier) {
246 uriInfo = new UriInfoWrapper(uriInfo);
247 PoxPayloadOut result = null;
249 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
250 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
252 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
253 ctx.setJaxRsContext(jaxRsContext);
255 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
258 // Include the Contact subresource(s) as part of the payload. The current UI supports a single contact resource only, so
259 // this code will return only the first contact resource
262 //FIXME: Need to support paging
263 AbstractCommonList contactObjectList = getContactList(null, parentIdentifier, itemIdentifier, uriInfo);
264 if (contactObjectList.getTotalItems() > 1) {
265 String errMsg = String.format("Can't get complete list of contacts for authority term '%s' in authority '%s'.", parentIdentifier, itemIdentifier);
269 if (contactObjectList.getTotalItems() > 1) {
270 ListItem item = contactObjectList.getListItem().get(0);
271 String csid = this.getCsid(item);
272 PoxPayloadOut contactPayloadOut = getContactPayload(parentIdentifier, itemIdentifier, csid);
273 PayloadOutputPart contactCommonPart = contactPayloadOut.getPart(ContactClient.PART_COMMON_LABEL);
274 result.addPart(contactCommonPart);
277 } catch (DocumentNotFoundException dnf) {
278 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
279 } catch (Exception e) {
280 throw bigReThrow(e, ServiceMessages.GET_FAILED);
283 return result.getBytes();
289 * @param parentspecifier either a CSID or one of the urn forms
290 * @param itemspecifier either a CSID or one of the urn forms
291 * @param csid the csid
293 * @return the contact
296 @Path("{parentcsid}/items/{itemcsid}/contacts/{csid}")
297 public String getContact(
298 @PathParam("parentcsid") String parentspecifier,
299 @PathParam("itemcsid") String itemspecifier,
300 @PathParam("csid") String csid) {
301 PoxPayloadOut result = null;
303 result = getContactPayload(parentspecifier, itemspecifier, csid);
304 } catch (Exception e) {
305 throw bigReThrow(e, "Get failed, the requested Contact CSID:" + csid
306 + ": or one of the specifiers for authority:" + parentspecifier
307 + ": and item:" + itemspecifier + ": was not found.",
310 if (result == null) {
311 Response response = Response.status(Response.Status.NOT_FOUND).entity("Get failed, the requested Contact CSID:" + csid + ": was not found.").type("text/plain").build();
312 throw new CSWebApplicationException(response);
314 return result.toXML();
317 protected PoxPayloadOut getContactPayload(
318 String parentspecifier,
319 String itemspecifier,
320 String csid) throws Exception {
321 PoxPayloadOut result = null;
323 String parentcsid = lookupParentCSID(parentspecifier, "getContact(parent)", "GET_ITEM_CONTACT", null);
325 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemCtx = createServiceContext(getItemServiceName());
326 String itemcsid = lookupItemCSID(itemCtx, itemspecifier, parentcsid, "getContact(item)", "GET_ITEM_CONTACT");
328 // Note that we have to create the service context and document handler for the Contact service, not the main service.
329 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getContactServiceName());
330 DocumentHandler handler = createContactDocumentHandler(ctx, parentcsid, itemcsid);
331 getRepositoryClient(ctx).get(ctx, csid, handler);
332 result = (PoxPayloadOut) ctx.getOutput();
340 * @param parentspecifier either a CSID or one of the urn forms
341 * @param itemspecifier either a CSID or one of the urn forms
342 * @param csid the csid
344 * @return the multipart output
347 @Path("{parentcsid}/items/{itemcsid}/contacts/{csid}")
348 public String updateContact(
349 @PathParam("parentcsid") String parentspecifier,
350 @PathParam("itemcsid") String itemspecifier,
351 @PathParam("csid") String csid,
353 PoxPayloadOut result = null;
355 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
356 String parentcsid = lookupParentCSID(parentspecifier, "updateContact(authority)", "UPDATE_CONTACT", null);
358 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemCtx = createServiceContext(getItemServiceName());
359 String itemcsid = lookupItemCSID(itemCtx, itemspecifier, parentcsid, "updateContact(item)", "UPDATE_CONTACT");
361 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
362 // Note that we have to create the service context and document handler for the Contact service, not the main service.
363 ctx = createServiceContext(getContactServiceName(), theUpdate);
364 DocumentHandler handler = createContactDocumentHandler(ctx, parentcsid, itemcsid);
365 getRepositoryClient(ctx).update(ctx, csid, handler);
366 result = (PoxPayloadOut) ctx.getOutput();
367 } catch (Exception e) {
368 throw bigReThrow(e, "Update failed, the requested Contact CSID:" + csid
369 + ": or one of the specifiers for authority:" + parentspecifier
370 + ": and item:" + itemspecifier + ": was not found.",
374 return result.toXML();
377 public void updateContact(ServiceContext existingCtx, String parentCsid, String itemCsid, String csid,
378 PayloadInputPart theUpdate) throws Exception {
379 PoxPayloadOut result = null;
381 String payloadTemplate = "<?xml version='1.0' encoding='UTF-8'?><document>%s</document>";
382 String xmlPayload = String.format(payloadTemplate, theUpdate.asXML());
383 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
385 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getContactServiceName(), input);
386 if (existingCtx != null) {
387 Object repoSession = existingCtx.getCurrentRepositorySession();
388 if (repoSession != null) {
389 ctx.setCurrentRepositorySession(repoSession);
390 ctx.setProperties(existingCtx.getProperties());
394 DocumentHandler handler = createContactDocumentHandler(ctx, parentCsid, itemCsid);
395 getRepositoryClient(ctx).update(ctx, csid, handler);
401 * @param parentspecifier either a CSID or one of the urn forms
402 * @param itemspecifier either a CSID or one of the urn forms
403 * @param csid the csid
405 * @return the response
408 @Path("{parentcsid}/items/{itemcsid}/contacts/{csid}")
409 public Response deleteContact(
410 @PathParam("parentcsid") String parentspecifier,
411 @PathParam("itemcsid") String itemspecifier,
412 @PathParam("csid") String csid) {
414 String parentcsid = lookupParentCSID(parentspecifier, "deleteContact(authority)", "DELETE_CONTACT", null);
416 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemCtx = createServiceContext(getItemServiceName());
417 String itemcsid = lookupItemCSID(itemCtx, itemspecifier, parentcsid, "deleteContact(item)", "DELETE_CONTACT");
418 //NOTE: itemcsid is not used below. Leaving the above call in for possible side effects??? CSPACE-3175
420 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
421 // Note that we have to create the service context for the Contact service, not the main service.
422 ctx = createServiceContext(getContactServiceName());
423 DocumentHandler handler = createDocumentHandler(ctx);
424 getRepositoryClient(ctx).delete(ctx, csid, handler);
425 return Response.status(HttpResponseCodes.SC_OK).build();
426 } catch (Exception e) {
427 throw bigReThrow(e, "DELETE failed, the requested Contact CSID:" + csid
428 + ": or one of the specifiers for authority:" + parentspecifier
429 + ": and item:" + itemspecifier + ": was not found.", csid);
433 protected String getContactDocType() {
434 return ContactConstants.NUXEO_DOCTYPE;
438 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
439 * for the current resource, for all tenants
441 * @return a map of URI templates for the current resource, for all tenants
444 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
445 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
446 super.getUriRegistryEntries();
447 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
448 for (String tenantId : tenantIds) {
449 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getContactDocType(), UriTemplateFactory.CONTACT));
451 return uriRegistryEntriesMap;