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.IClientQueryParams;
45 import org.collectionspace.services.client.IQueryManager;
46 import org.collectionspace.services.client.PoxPayloadIn;
47 import org.collectionspace.services.client.PoxPayloadOut;
48 import org.collectionspace.services.client.workflow.WorkflowClient;
49 import org.collectionspace.services.common.XmlTools;
50 import org.collectionspace.services.common.CSWebApplicationException;
51 import org.collectionspace.services.common.NuxeoBasedResource;
52 import org.collectionspace.services.common.ResourceMap;
53 import org.collectionspace.services.common.ServiceMain;
54 import org.collectionspace.services.common.ServiceMessages;
55 import org.collectionspace.services.common.StoredValuesUriTemplate;
56 import org.collectionspace.services.common.UriTemplateFactory;
57 import org.collectionspace.services.common.UriTemplateRegistry;
58 import org.collectionspace.services.common.UriTemplateRegistryKey;
59 import org.collectionspace.services.common.api.RefName;
60 import org.collectionspace.services.common.api.Tools;
61 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
62 import org.collectionspace.services.common.authorityref.AuthorityRefList;
63 import org.collectionspace.services.common.context.JaxRsContext;
64 import org.collectionspace.services.common.context.MultipartServiceContext;
65 import org.collectionspace.services.common.context.RemoteServiceContext;
66 import org.collectionspace.services.common.context.ServiceBindingUtils;
67 import org.collectionspace.services.common.context.ServiceContext;
68 import org.collectionspace.services.common.document.DocumentException;
69 import org.collectionspace.services.common.document.DocumentFilter;
70 import org.collectionspace.services.common.document.DocumentHandler;
71 import org.collectionspace.services.common.document.DocumentNotFoundException;
72 import org.collectionspace.services.common.document.DocumentWrapper;
73 import org.collectionspace.services.common.document.Hierarchy;
74 import org.collectionspace.services.common.query.QueryManager;
75 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
76 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
77 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
78 import org.collectionspace.services.config.ClientType;
79 import org.collectionspace.services.jaxb.AbstractCommonList;
80 import org.collectionspace.services.lifecycle.TransitionDef;
81 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
82 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
83 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
84 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
85 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
86 import org.collectionspace.services.workflow.WorkflowCommon;
87 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
88 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
89 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
90 import org.jboss.resteasy.util.HttpResponseCodes;
91 import org.nuxeo.ecm.core.api.DocumentModel;
92 import org.nuxeo.ecm.core.api.DocumentModelList;
93 import org.slf4j.Logger;
94 import org.slf4j.LoggerFactory;
97 * The Class AuthorityResource.
100 @Consumes("application/xml")
101 @Produces("application/xml")
102 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
103 extends NuxeoBasedResource {
105 final static String SEARCH_TYPE_TERMSTATUS = "ts";
106 public final static String hierarchy = "hierarchy";
108 protected Class<AuthCommon> authCommonClass;
109 protected Class<?> resourceClass;
110 protected String authorityCommonSchemaName;
111 protected String authorityItemCommonSchemaName;
112 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed? I see no references to it.
114 final static String FETCH_SHORT_ID = "_fetch_";
115 public final static String PARENT_WILDCARD = "_ALL_";
117 final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
120 * Instantiates a new Authority resource.
122 public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
123 String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
124 this.authCommonClass = authCommonClass;
125 this.resourceClass = resourceClass;
126 this.authorityCommonSchemaName = authorityCommonSchemaName;
127 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
130 public abstract String getItemServiceName();
132 public abstract String getItemTermInfoGroupXPathBase();
135 protected String getVersionString() {
136 return "$LastChangedRevision: 2617 $";
140 public Class<AuthCommon> getCommonPartClass() {
141 return authCommonClass;
145 * Creates the item document handler.
148 * @param inAuthority the in vocabulary
150 * @return the document handler
152 * @throws Exception the exception
154 protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
155 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
156 String inAuthority, String parentShortIdentifier)
158 String authorityRefNameBase;
159 AuthorityItemDocumentModelHandler<?> docHandler;
161 if (parentShortIdentifier == null) {
162 authorityRefNameBase = null;
164 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getServiceName());
165 if (parentShortIdentifier.equals(FETCH_SHORT_ID)) { // We need to fetch this from the repo
166 if (ctx.getCurrentRepositorySession() != null) {
167 parentCtx.setCurrentRepositorySession(ctx.getCurrentRepositorySession()); // We need to use the current repo session if one exists
169 // Get from parent document
170 parentShortIdentifier = getAuthShortIdentifier(parentCtx, inAuthority);
172 authorityRefNameBase = buildAuthorityRefNameBase(parentCtx, parentShortIdentifier);
175 docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
176 ctx.getCommonPartLabel(getItemServiceName()),
178 // FIXME - Richard and Aron think the following three lines should
179 // be in the constructor for the AuthorityItemDocumentModelHandler
180 // because all three are required fields.
181 docHandler.setInAuthority(inAuthority);
182 docHandler.setAuthorityRefNameBase(authorityRefNameBase);
183 docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
187 public String getAuthShortIdentifier(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
188 throws DocumentNotFoundException, DocumentException {
189 String shortIdentifier = null;
192 AuthorityDocumentModelHandler<?> handler = (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
193 shortIdentifier = handler.getShortIdentifier(ctx, authCSID, authorityCommonSchemaName);
194 } catch (Exception e) {
195 if (logger.isDebugEnabled()) {
196 logger.debug("Caught exception ", e);
198 throw new DocumentException(e);
201 return shortIdentifier;
204 protected String buildAuthorityRefNameBase(
205 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
206 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
207 ctx.getServiceName(),
208 null, // Only use shortId form!!!
209 shortIdentifier, null);
210 return authority.toString();
213 public static class CsidAndShortIdentifier {
215 String shortIdentifier;
218 protected String lookupParentCSID(String parentspecifier, String method,
219 String op, UriInfo uriInfo) throws Exception {
220 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(null,
221 parentspecifier, method, op, uriInfo);
222 return tempResult.CSID;
225 protected String lookupParentCSID(ServiceContext ctx, String parentspecifier, String method,
226 String op, UriInfo uriInfo) throws Exception {
227 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(ctx,
228 parentspecifier, method, op, uriInfo);
229 return tempResult.CSID;
233 private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
234 ServiceContext itemServiceCtx, // Ok to be null
235 String parentIdentifier,
240 CsidAndShortIdentifier result = new CsidAndShortIdentifier();
241 Specifier parentSpec = Specifier.getSpecifier(parentIdentifier, method, op);
244 String parentShortIdentifier;
245 if (parentSpec.form == SpecifierForm.CSID) {
246 parentShortIdentifier = null;
247 parentcsid = parentSpec.value;
248 // Uncomment when app layer is ready to integrate
249 // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
250 parentShortIdentifier = FETCH_SHORT_ID;
252 parentShortIdentifier = parentSpec.value;
253 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentShortIdentifier);
254 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
255 CoreSessionInterface repoSession = null;
256 if (itemServiceCtx != null) {
257 repoSession = (CoreSessionInterface) itemServiceCtx.getCurrentRepositorySession(); // We want to use the thread's current repo session
259 parentcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
262 result.CSID = parentcsid;
263 result.shortIdentifier = parentShortIdentifier;
268 public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String itemspecifier, String parentcsid, String method, String op)
269 throws DocumentException {
271 Specifier itemSpec = Specifier.getSpecifier(itemspecifier, method, op);
272 if (itemSpec.form == SpecifierForm.CSID) {
273 itemcsid = itemSpec.value;
275 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
276 itemcsid = getRepositoryClient(ctx).findDocCSID(null, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
282 * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
283 * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
284 * Resource. They then call this method on that resource.
287 public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
288 throws Exception, DocumentNotFoundException {
292 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
293 // Ensure we have the right context.
294 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
296 // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
297 RepositoryClientImpl client = (RepositoryClientImpl)getRepositoryClient(ctx);
298 String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
300 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
301 ctx = createServiceContext(getItemServiceName());
302 DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
303 DocumentModel docModel = docWrapper.getWrappedObject();
309 public Response createAuthority(String xmlPayload) {
311 // Requests to create new authorities come in on new threads. Unfortunately, we need to synchronize those threads on this block because, as of 8/27/2015, we can't seem to get Nuxeo
312 // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
313 // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
314 // the code that creates new authorities. The authority document model handler will first check for authorities with the same short id before
315 // trying to create a new authority.
317 synchronized(AuthorityResource.class) {
319 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
320 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
321 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
323 String csid = getRepositoryClient(ctx).create(ctx, handler);
324 UriBuilder path = UriBuilder.fromResource(resourceClass);
325 path.path("" + csid);
326 Response response = Response.created(path.build()).build();
328 } catch (Exception e) {
329 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
336 * Synchronizes the authority and its terms with a Shared Authority Server.
338 * @param specifier either a CSID or one of the urn forms
340 * @return the authority
344 public byte[] synchronize(
345 @Context Request request,
347 @PathParam("csid") String csid) {
349 boolean neededSync = false;
350 PoxPayloadOut payloadOut = null;
354 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
355 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
356 specifier = Specifier.getSpecifier(csid, "getAuthority", "GET");
357 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
358 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
359 payloadOut = ctx.getOutput();
360 } catch (Exception e) {
361 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, csid);
365 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
367 if (neededSync == true) {
368 result = payloadOut.getBytes();
370 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
371 specifier.value).getBytes();
372 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
373 throw new CSWebApplicationException(response);
379 * Gets the authority.
381 * @param specifier either a CSID or one of the urn forms
383 * @return the authority
389 @Context Request request,
391 @PathParam("csid") String specifier) {
392 PoxPayloadOut result = null;
394 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
395 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
397 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
398 if (spec.form == SpecifierForm.CSID) {
399 if (logger.isDebugEnabled()) {
400 logger.debug("getAuthority with csid=" + spec.value);
402 getRepositoryClient(ctx).get(ctx, spec.value, handler);
404 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
405 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
406 handler.setDocumentFilter(myFilter);
407 getRepositoryClient(ctx).get(ctx, handler);
409 result = ctx.getOutput();
411 } catch (Exception e) {
412 throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
415 if (result == null) {
416 Response response = Response.status(Response.Status.NOT_FOUND).entity(
417 "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
418 "text/plain").build();
419 throw new CSWebApplicationException(response);
422 return result.getBytes();
426 * Finds and populates the authority list.
430 * @return the authority list
433 @Produces("application/xml")
434 public AbstractCommonList getAuthorityList(@Context UriInfo uriInfo) { //FIXME - REM 5/3/2012 - This is not reachable from the JAX-RS dispatcher. Instead the equivalent method in ResourceBase is getting called.
435 AbstractCommonList result = null;
438 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
439 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
441 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
442 DocumentFilter myFilter = handler.getDocumentFilter();
443 // Need to make the default sort order for authority items
444 // be on the displayName field
445 String sortBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
446 if (sortBy == null || sortBy.isEmpty()) {
447 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
448 + AuthorityItemJAXBSchema.DISPLAY_NAME;
449 myFilter.setOrderByClause(qualifiedDisplayNameField);
451 String nameQ = queryParams.getFirst("refName");
453 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
455 getRepositoryClient(ctx).getFiltered(ctx, handler);
456 result = handler.getCommonPartList();
457 } catch (Exception e) {
458 throw bigReThrow(e, ServiceMessages.GET_FAILED);
465 * Overriding this methods to see if we should update the revision number during the update. We don't
466 * want to update the rev number of synchronization operations.
469 protected PoxPayloadOut update(String csid,
470 PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
471 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
473 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
474 Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
475 if (shouldUpdateRev != null) {
476 handler.setShouldUpdateRevNumber(shouldUpdateRev);
478 getRepositoryClient(ctx).update(ctx, csid, handler);
479 return ctx.getOutput();
485 * @param specifier the csid or id
487 * @return the multipart output
491 public byte[] updateAuthority(
492 @PathParam("csid") String specifier,
494 PoxPayloadOut result = null;
496 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
497 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
498 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
499 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
501 if (spec.form == SpecifierForm.CSID) {
504 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
505 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
507 getRepositoryClient(ctx).update(ctx, csid, handler);
508 result = ctx.getOutput();
509 } catch (Exception e) {
510 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
512 return result.getBytes();
518 * @param csid the csid
520 * @return the response
525 public Response old_deleteAuthority(@PathParam("csid") String csid) {
526 if (logger.isDebugEnabled()) {
527 logger.debug("deleteAuthority with csid=" + csid);
530 ensureCSID(csid, ServiceMessages.DELETE_FAILED, "Authority.csid");
531 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
532 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
533 getRepositoryClient(ctx).delete(ctx, csid, handler);
534 return Response.status(HttpResponseCodes.SC_OK).build();
535 } catch (Exception e) {
536 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
543 * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
545 * @return the response
549 public Response deleteAuthority(
550 @Context Request request,
552 @PathParam("csid") String specifier) {
553 if (logger.isDebugEnabled()) {
554 logger.debug("deleteAuthority with specifier=" + specifier);
558 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
559 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
561 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
562 if (spec.form == SpecifierForm.CSID) {
563 if (logger.isDebugEnabled()) {
564 logger.debug("deleteAuthority with csid=" + spec.value);
566 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
567 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
569 if (logger.isDebugEnabled()) {
570 logger.debug("deleteAuthority with specifier=" + spec.value);
572 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
573 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
576 return Response.status(HttpResponseCodes.SC_OK).build();
577 } catch (Exception e) {
578 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
585 * @param parentspecifier - ID of the container. Can be URN or CSID form
586 * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
587 * @param proposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
591 protected Response createAuthorityItem(ServiceContext ctx, String parentIdentifier,
592 boolean shouldUpdateRevNumber,
593 boolean proposed) throws Exception {
594 Response result = null;
596 // Note: must have the parentShortId, to do the create.
597 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
598 AuthorityItemDocumentModelHandler handler =
599 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
600 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
601 handler.setIsProposed(proposed);
602 // Make the client call
603 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
605 // Build the JAX-RS response
606 UriBuilder path = UriBuilder.fromResource(resourceClass);
607 path.path(parent.CSID + "/items/" + itemcsid);
608 result = Response.created(path.build()).build();
614 * Called with an existing context.
616 * @param parentIdentifier
621 public Response createAuthorityItemWithParentContext(ServiceContext parentCtx,
622 String parentIdentifier,
624 boolean shouldUpdateRevNumber,
625 boolean isProposed) throws Exception {
626 Response result = null;
628 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
629 parentCtx.getResourceMap(), parentCtx.getUriInfo());
630 if (parentCtx.getCurrentRepositorySession() != null) {
631 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
633 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed);
638 /*************************************************************************
639 * Create an AuthorityItem - this is a sub-resource of Authority
640 * @param specifier either a CSID or one of the urn forms
641 * @return Authority item response
642 *************************************************************************/
644 @Path("{csid}/items")
645 public Response createAuthorityItem(
646 @Context ResourceMap resourceMap,
647 @Context UriInfo uriInfo,
648 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
650 Response result = null;
653 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
654 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
655 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
656 AuthorityServiceUtils.PROPOSED);
657 } catch (Exception e) {
658 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
665 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
666 public byte[] getItemWorkflow(
667 @PathParam("csid") String csid,
668 @PathParam("itemcsid") String itemcsid) {
669 PoxPayloadOut result = null;
672 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
673 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
675 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
676 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
677 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
678 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
679 result = ctx.getOutput();
680 } catch (Exception e) {
681 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
683 return result.getBytes();
686 //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
687 // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
689 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
690 public byte[] updateItemWorkflowWithTransition(
691 @PathParam("csid") String csid,
692 @PathParam("itemcsid") String itemcsid,
693 @PathParam("transition") String transition) {
694 PoxPayloadOut result = null;
697 result = updateItemWorkflowWithTransition(null, // Ok to send null
698 csid, itemcsid, transition, AuthorityServiceUtils.UPDATE_REV);
699 } catch (Exception e) {
700 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
703 return result.getBytes();
707 * Update an authority item's workflow state.
708 * @param existingContext
714 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext existingContext,
718 boolean updateRevNumber) {
719 PoxPayloadOut result = null;
723 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
725 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
726 WorkflowClient.SERVICE_COMMONPART_NAME);
727 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
728 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
729 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If a repo session is already open, we need to use it and not create a new one
732 // Create a service context and document handler for the target resource -not the workflow resource itself.
734 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName());
735 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
736 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
737 ctx.setProperty(WorkflowClient.TARGET_DOCHANDLER, targetDocHandler); //added as a context param for the workflow document handler -it will call the parent's dochandler "prepareForWorkflowTranstion" method
739 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
741 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
742 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
744 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
745 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
746 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
748 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
749 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
750 result = ctx.getOutput();
751 } catch (Exception e) {
752 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemCsid);
758 private PoxPayloadOut getAuthorityItem(
760 String parentIdentifier,
761 String itemIdentifier) throws Exception {
762 PoxPayloadOut result = null;
764 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
765 // We omit the parentShortId, only needed when doing a create...
766 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
768 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
769 if (itemSpec.form == SpecifierForm.CSID) {
770 // TODO should we assert that the item is in the passed vocab?
771 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
773 String itemWhereClause =
774 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
775 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
776 handler.setDocumentFilter(myFilter);
777 getRepositoryClient(ctx).get(ctx, handler);
780 result = (PoxPayloadOut) ctx.getOutput();
781 if (result != null) {
782 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
783 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
784 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
785 itemSpec.value, inAuthority, parentcsid));
793 public PoxPayloadOut getAuthorityItemWithExistingContext(
794 ServiceContext existingCtx,
795 String parentIdentifier,
796 String itemIdentifier) throws Exception {
797 PoxPayloadOut result = null;
799 ServiceContext ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
800 if (existingCtx.getCurrentRepositorySession() != null) {
801 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
802 ctx.setProperties(existingCtx.getProperties());
804 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
810 * Gets the authority item.
812 * @param parentspecifier either a CSID or one of the urn forms
813 * @param itemspecifier either a CSID or one of the urn forms
815 * @return the authority item
818 @Path("{csid}/items/{itemcsid}")
819 public byte[] getAuthorityItem(
820 @Context Request request,
821 @Context UriInfo uriInfo,
822 @Context ResourceMap resourceMap,
823 @PathParam("csid") String parentIdentifier,
824 @PathParam("itemcsid") String itemIdentifier) {
825 PoxPayloadOut result = null;
827 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
828 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
830 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
831 ctx.setJaxRsContext(jaxRsContext);
833 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
834 } catch (DocumentNotFoundException dnf) {
835 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
836 } catch (Exception e) {
837 throw bigReThrow(e, ServiceMessages.GET_FAILED);
840 return result.getBytes();
844 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
845 * different enough that it will have to override this method in it's resource class.
848 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
849 String result = null;
851 result = NuxeoUtils.getPrimaryElPathPropertyName(
852 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
853 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
859 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
860 String result = null;
862 result = NuxeoUtils.getMultiElPathPropertyName(
863 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
864 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
870 * Gets the authorityItem list for the specified authority
871 * If partialPerm is specified, keywords will be ignored.
873 * @param specifier either a CSID or one of the urn forms
874 * @param partialTerm if non-null, matches partial terms
875 * @param keywords if non-null, matches terms in the keyword index for items
876 * @param ui passed to include additional parameters, like pagination controls
879 public AbstractCommonList getAuthorityItemList(ServiceContext existingContext,
881 UriInfo uriInfo) throws Exception {
882 AbstractCommonList result = null;
884 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
885 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
886 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
887 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
888 ctx.setProperties(existingContext.getProperties());
891 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
892 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
893 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
894 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
895 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
897 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
898 // We omit the parentShortId, only needed when doing a create...
899 String parentcsid = PARENT_WILDCARD.equals(specifier) ? null :
900 lookupParentCSID(specifier, "getAuthorityItemList", "LIST", uriInfo);
901 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
902 createItemDocumentHandler(ctx, parentcsid, null);
904 DocumentFilter myFilter = handler.getDocumentFilter();
905 // If we are not wildcarding the parent, add a restriction
906 if (parentcsid != null) {
907 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
908 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
909 + "'" + parentcsid + "'",
910 IQueryManager.SEARCH_QUALIFIER_AND);
913 if (Tools.notBlank(termStatus)) {
914 // Start with the qualified termStatus field
915 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
916 + AuthorityItemJAXBSchema.TERM_STATUS;
917 String[] filterTerms = termStatus.trim().split("\\|");
918 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
919 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
922 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
928 * Gets the authorityItem list for the specified authority
929 * If partialPerm is specified, keywords will be ignored.
931 * @param specifier either a CSID or one of the urn forms
932 * @param partialTerm if non-null, matches partial terms
933 * @param keywords if non-null, matches terms in the keyword index for items
934 * @param ui passed to include additional parameters, like pagination controls
936 * @return the authorityItem list
939 @Path("{csid}/items")
940 @Produces("application/xml")
941 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier,
942 @Context UriInfo uriInfo) {
943 AbstractCommonList result = null;
946 result = getAuthorityItemList(NULL_CONTEXT, specifier, uriInfo);
947 } catch (Exception e) {
948 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
955 * @return the name of the property used to specify references for items in this type of
956 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
957 * Some types (like Vocabulary) use a separate property.
959 protected String getRefPropName() {
960 return ServiceBindingUtils.AUTH_REF_PROP;
964 * Gets the entities referencing this Authority item instance. The service type
965 * can be passed as a query param "type", and must match a configured type
966 * for the service bindings. If not set, the type defaults to
967 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
969 * @param parentspecifier either a CSID or one of the urn forms
970 * @param itemspecifier either a CSID or one of the urn forms
973 * @return the info for the referencing objects
976 @Path("{csid}/items/{itemcsid}/refObjs")
977 @Produces("application/xml")
978 public AuthorityRefDocList getReferencingObjects(
979 @PathParam("csid") String parentSpecifier,
980 @PathParam("itemcsid") String itemSpecifier,
981 @Context UriTemplateRegistry uriTemplateRegistry,
982 @Context UriInfo uriInfo) {
983 AuthorityRefDocList authRefDocList = null;
985 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
986 } catch (Exception e) {
987 throw bigReThrow(e, ServiceMessages.GET_FAILED);
990 if (authRefDocList == null) {
991 Response response = Response.status(Response.Status.NOT_FOUND).entity(
992 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
993 "text/plain").build();
994 throw new CSWebApplicationException(response);
996 return authRefDocList;
999 public AuthorityRefDocList getReferencingObjects(
1000 ServiceContext existingContext,
1001 String parentspecifier,
1002 String itemspecifier,
1003 UriTemplateRegistry uriTemplateRegistry,
1004 UriInfo uriInfo) throws Exception {
1005 AuthorityRefDocList authRefDocList = null;
1007 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1008 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1010 // Merge parts of existing context with our new context
1012 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1013 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1014 ctx.setProperties(existingContext.getProperties());
1017 String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1018 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1020 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1021 if(serviceTypes == null || serviceTypes.isEmpty()) {
1022 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1025 // Note that we have to create the service context for the Items, not the main service
1026 // We omit the parentShortId, only needed when doing a create...
1027 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1028 authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1030 return authRefDocList;
1034 * Gets the authority terms used in the indicated Authority item.
1036 * @param parentspecifier either a CSID or one of the urn forms
1037 * @param itemspecifier either a CSID or one of the urn forms
1038 * @param ui passed to include additional parameters, like pagination controls
1040 * @return the authority refs for the Authority item.
1043 @Path("{csid}/items/{itemcsid}/authorityrefs")
1044 @Produces("application/xml")
1045 public AuthorityRefList getAuthorityItemAuthorityRefs(
1046 @PathParam("csid") String parentspecifier,
1047 @PathParam("itemcsid") String itemspecifier,
1048 @Context UriInfo uriInfo) {
1049 AuthorityRefList authRefList = null;
1051 // Note that we have to create the service context for the Items, not the main service
1052 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1053 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1054 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1055 // We omit the parentShortId, only needed when doing a create...
1056 DocumentModelHandler<?, AbstractCommonList> handler =
1057 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1059 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1061 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1062 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1063 } catch (Exception e) {
1064 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1070 * Synchronizes a local authority item with a share authority server (SAS) item.
1072 * @param parentIdentifier
1073 * @param itemIdentifier
1077 private PoxPayloadOut synchronizeItem(
1079 String parentIdentifier,
1080 String itemIdentifier) throws Exception {
1081 PoxPayloadOut result = null;
1082 AuthorityItemSpecifier specifier;
1083 boolean neededSync = false;
1085 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1086 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1087 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1088 // Create an authority item specifier
1089 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1090 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1091 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1093 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1094 if (neededSync == true) {
1095 result = (PoxPayloadOut) ctx.getOutput();
1102 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1103 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1104 * local authority. The parent context was created for the authority (parent) because the sync started there.
1105 * @param existingCtx
1106 * @param parentIdentifier
1107 * @param itemIdentifier
1111 public PoxPayloadOut synchronizeItemWithExistingContext(
1112 ServiceContext existingCtx,
1113 String parentIdentifier,
1114 String itemIdentifier
1115 ) throws Exception {
1116 PoxPayloadOut result = null;
1118 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1119 existingCtx.getResourceMap(),
1120 existingCtx.getUriInfo());
1121 if (existingCtx.getCurrentRepositorySession() != null) {
1122 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1124 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1130 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1132 * @param specifier either CSIDs and/or one of the urn forms
1134 * @return the authority item if it was synchronized with SAS
1137 @Path("{csid}/items/{itemcsid}/sync")
1138 public byte[] synchronizeItem(
1139 @Context ResourceMap resourceMap,
1140 @Context UriInfo uriInfo,
1141 @PathParam("csid") String parentIdentifier,
1142 @PathParam("itemcsid") String itemIdentifier) {
1144 boolean neededSync = false;
1145 PoxPayloadOut payloadOut = null;
1148 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1149 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1150 if (payloadOut != null) {
1153 } catch (Exception e) {
1154 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1158 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1160 if (neededSync == true) {
1161 result = payloadOut.getBytes();
1163 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1164 itemIdentifier).getBytes();
1165 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1166 throw new CSWebApplicationException(response);
1173 * Update authorityItem.
1175 * @param parentspecifier either a CSID or one of the urn forms
1176 * @param itemspecifier either a CSID or one of the urn forms
1178 * @return the multipart output
1181 @Path("{csid}/items/{itemcsid}")
1182 public byte[] updateAuthorityItem(
1183 @Context ResourceMap resourceMap,
1184 @Context UriInfo uriInfo,
1185 @PathParam("csid") String parentSpecifier,
1186 @PathParam("itemcsid") String itemSpecifier,
1187 String xmlPayload) {
1188 PoxPayloadOut result = null;
1191 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1192 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1193 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1194 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1195 } catch (Exception e) {
1196 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1199 return result.getBytes();
1202 public PoxPayloadOut updateAuthorityItem(
1203 ServiceContext itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
1204 ResourceMap resourceMap,
1206 String parentspecifier,
1207 String itemspecifier,
1208 PoxPayloadIn theUpdate,
1209 boolean shouldUpdateRevNumber,
1210 Boolean isProposed) throws Exception {
1211 PoxPayloadOut result = null;
1213 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
1214 String parentcsid = csidAndShortId.CSID;
1215 String parentShortId = csidAndShortId.shortIdentifier;
1217 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
1219 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
1221 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
1223 ctx.setInput(theUpdate); // the update payload
1226 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
1228 // We omit the parentShortId, only needed when doing a create...
1229 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
1230 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1231 if (isProposed != null) {
1232 handler.setIsProposed(isProposed);
1234 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
1235 result = ctx.getOutput();
1241 * Delete authorityItem.
1243 * @param parentcsid the parentcsid
1244 * @param itemcsid the itemcsid
1246 * @return the response
1249 @Path("{csid}/items/{itemcsid}")
1250 public Response deleteAuthorityItem(
1251 @PathParam("csid") String parentcsid,
1252 @PathParam("itemcsid") String itemcsid) {
1253 Response result = null;
1255 if (logger.isDebugEnabled()) {
1256 logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
1260 deleteAuthorityItem(null, parentcsid, itemcsid);
1261 result = Response.status(HttpResponseCodes.SC_OK).build();
1262 } catch (Exception e) {
1263 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
1265 //Laramie, removing this catch, since it will surely fail below, since itemcsid or parentcsid will be null.
1268 // }catch (Throwable t){
1269 public void deleteAuthorityItem(ServiceContext existingCtx,
1271 String itemcsid) throws Exception {
1272 Response result = null;
1273 // System.out.println("ERROR in setting up DELETE: "+t);
1274 ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1275 ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1277 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
1278 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1279 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists
1280 ctx.setProperties(existingCtx.getProperties());
1282 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
1283 getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
1287 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1288 @Produces("application/xml")
1289 public String getHierarchy(@PathParam("csid") String csid,
1290 @PathParam("itemcsid") String itemcsid,
1291 @Context UriInfo ui) throws Exception {
1293 // All items in dive can look at their child uri's to get uri. So we calculate the very first one. We could also do a GET and look at the common part uri field, but why...?
1294 String calledUri = ui.getPath();
1295 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1296 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), ui);
1298 String direction = ui.getQueryParameters().getFirst(Hierarchy.directionQP);
1299 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1300 return Hierarchy.surface(ctx, itemcsid, uri);
1302 return Hierarchy.dive(ctx, itemcsid, uri);
1304 } catch (Exception e) {
1305 throw bigReThrow(e, "Error showing hierarchy", itemcsid);
1309 protected String getItemDocType(String tenantId) {
1310 return getDocType(tenantId, getItemServiceName());
1314 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1315 * for the current resource, for all tenants
1317 * @return a map of URI templates for the current resource, for all tenants
1320 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1321 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1322 super.getUriRegistryEntries();
1323 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1324 for (String tenantId : tenantIds) {
1325 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1327 return uriRegistryEntriesMap;