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.DocumentReferenceException;
73 import org.collectionspace.services.common.document.DocumentWrapper;
74 import org.collectionspace.services.common.document.Hierarchy;
75 import org.collectionspace.services.common.query.QueryManager;
76 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
77 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
78 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
79 import org.collectionspace.services.config.ClientType;
80 import org.collectionspace.services.jaxb.AbstractCommonList;
81 import org.collectionspace.services.lifecycle.TransitionDef;
82 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
83 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
84 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
85 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
86 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
87 import org.collectionspace.services.workflow.WorkflowCommon;
88 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
89 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
90 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
91 import org.jboss.resteasy.util.HttpResponseCodes;
92 import org.nuxeo.ecm.core.api.DocumentModel;
93 import org.nuxeo.ecm.core.api.DocumentModelList;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
98 * The Class AuthorityResource.
101 @Consumes("application/xml")
102 @Produces("application/xml")
103 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
104 extends NuxeoBasedResource {
106 final static String SEARCH_TYPE_TERMSTATUS = "ts";
107 public final static String hierarchy = "hierarchy";
109 protected Class<AuthCommon> authCommonClass;
110 protected Class<?> resourceClass;
111 protected String authorityCommonSchemaName;
112 protected String authorityItemCommonSchemaName;
113 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed? I see no references to it.
115 final static String FETCH_SHORT_ID = "_fetch_";
116 public final static String PARENT_WILDCARD = "_ALL_";
118 final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
121 * Instantiates a new Authority resource.
123 public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
124 String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
125 this.authCommonClass = authCommonClass;
126 this.resourceClass = resourceClass;
127 this.authorityCommonSchemaName = authorityCommonSchemaName;
128 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
131 public abstract String getItemServiceName();
133 public abstract String getItemTermInfoGroupXPathBase();
136 protected String getVersionString() {
137 return "$LastChangedRevision: 2617 $";
141 public Class<AuthCommon> getCommonPartClass() {
142 return authCommonClass;
146 * Creates the item document handler.
149 * @param inAuthority the in vocabulary
151 * @return the document handler
153 * @throws Exception the exception
155 protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
156 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
157 String inAuthority, String parentShortIdentifier)
159 String authorityRefNameBase;
160 AuthorityItemDocumentModelHandler<?> docHandler;
162 if (parentShortIdentifier == null) {
163 authorityRefNameBase = null;
165 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getServiceName());
166 if (parentShortIdentifier.equals(FETCH_SHORT_ID)) { // We need to fetch this from the repo
167 if (ctx.getCurrentRepositorySession() != null) {
168 parentCtx.setCurrentRepositorySession(ctx.getCurrentRepositorySession()); // We need to use the current repo session if one exists
170 // Get from parent document
171 parentShortIdentifier = getAuthShortIdentifier(parentCtx, inAuthority);
173 authorityRefNameBase = buildAuthorityRefNameBase(parentCtx, parentShortIdentifier);
176 docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
177 ctx.getCommonPartLabel(getItemServiceName()),
179 // FIXME - Richard and Aron think the following three lines should
180 // be in the constructor for the AuthorityItemDocumentModelHandler
181 // because all three are required fields.
182 docHandler.setInAuthority(inAuthority);
183 docHandler.setAuthorityRefNameBase(authorityRefNameBase);
184 docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
188 public String getAuthShortIdentifier(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
189 throws DocumentNotFoundException, DocumentException {
190 String shortIdentifier = null;
193 AuthorityDocumentModelHandler<?> handler = (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
194 shortIdentifier = handler.getShortIdentifier(ctx, authCSID, authorityCommonSchemaName);
195 } catch (Exception e) {
196 if (logger.isDebugEnabled()) {
197 logger.debug("Caught exception ", e);
199 throw new DocumentException(e);
202 return shortIdentifier;
205 protected String buildAuthorityRefNameBase(
206 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
207 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
208 ctx.getServiceName(),
209 null, // Only use shortId form!!!
210 shortIdentifier, null);
211 return authority.toString();
214 public static class CsidAndShortIdentifier {
216 String shortIdentifier;
219 protected String lookupParentCSID(String parentspecifier, String method,
220 String op, UriInfo uriInfo) throws Exception {
221 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(null,
222 parentspecifier, method, op, uriInfo);
223 return tempResult.CSID;
226 protected String lookupParentCSID(ServiceContext ctx, String parentspecifier, String method,
227 String op, UriInfo uriInfo) throws Exception {
228 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(ctx,
229 parentspecifier, method, op, uriInfo);
230 return tempResult.CSID;
234 private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
235 ServiceContext existingCtx, // Ok to be null
236 String parentIdentifier,
241 CsidAndShortIdentifier result = new CsidAndShortIdentifier();
242 Specifier parentSpec = Specifier.getSpecifier(parentIdentifier, method, op);
245 String parentShortIdentifier;
246 if (parentSpec.form == SpecifierForm.CSID) {
247 parentShortIdentifier = null;
248 parentcsid = parentSpec.value;
249 // Uncomment when app layer is ready to integrate
250 // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
251 parentShortIdentifier = FETCH_SHORT_ID;
253 parentShortIdentifier = parentSpec.value;
254 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentShortIdentifier);
255 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
256 CoreSessionInterface repoSession = null;
257 if (existingCtx != null) {
258 repoSession = (CoreSessionInterface) existingCtx.getCurrentRepositorySession(); // We want to use the thread's current repo session
260 parentcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
263 result.CSID = parentcsid;
264 result.shortIdentifier = parentShortIdentifier;
269 public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext, String itemspecifier, String parentcsid, String method, String op)
273 Specifier itemSpec = Specifier.getSpecifier(itemspecifier, method, op);
274 if (itemSpec.form == SpecifierForm.CSID) {
275 itemcsid = itemSpec.value;
277 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
278 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(getItemServiceName());
279 CoreSessionInterface repoSession = null;
280 if (existingContext != null) {
281 repoSession = (CoreSessionInterface) existingContext.getCurrentRepositorySession(); // We want to use the thread's current repo session
283 itemcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
290 * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
291 * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
292 * Resource. They then call this method on that resource.
295 public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
296 throws Exception, DocumentNotFoundException {
300 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
301 // Ensure we have the right context.
302 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
304 // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
305 RepositoryClientImpl client = (RepositoryClientImpl)getRepositoryClient(ctx);
306 String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
308 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
309 ctx = createServiceContext(getItemServiceName());
310 DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
311 DocumentModel docModel = docWrapper.getWrappedObject();
317 public Response createAuthority(String xmlPayload) {
319 // 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
320 // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
321 // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
322 // the code that creates new authorities. The authority document model handler will first check for authorities with the same short id before
323 // trying to create a new authority.
325 synchronized(AuthorityResource.class) {
327 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
328 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
329 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
331 String csid = getRepositoryClient(ctx).create(ctx, handler);
332 UriBuilder path = UriBuilder.fromResource(resourceClass);
333 path.path("" + csid);
334 Response response = Response.created(path.build()).build();
336 } catch (Exception e) {
337 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
344 * Synchronizes the authority and its terms with a Shared Authority Server.
346 * @param specifier either a CSID or one of the urn forms
348 * @return the authority
352 public byte[] synchronize(
353 @Context Request request,
355 @PathParam("csid") String csid) {
357 boolean neededSync = false;
358 PoxPayloadOut payloadOut = null;
362 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
363 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
364 specifier = Specifier.getSpecifier(csid, "getAuthority", "GET");
365 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
366 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
367 payloadOut = ctx.getOutput();
368 } catch (Exception e) {
369 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, csid);
373 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
375 if (neededSync == true) {
376 result = payloadOut.getBytes();
378 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
379 specifier.value).getBytes();
380 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
381 throw new CSWebApplicationException(response);
387 * Gets the authority.
389 * @param specifier either a CSID or one of the urn forms
391 * @return the authority
397 @Context Request request,
399 @PathParam("csid") String specifier) {
400 PoxPayloadOut result = null;
402 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
403 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
405 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
406 if (spec.form == SpecifierForm.CSID) {
407 if (logger.isDebugEnabled()) {
408 logger.debug("getAuthority with csid=" + spec.value);
410 getRepositoryClient(ctx).get(ctx, spec.value, handler);
412 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
413 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
414 handler.setDocumentFilter(myFilter);
415 getRepositoryClient(ctx).get(ctx, handler);
417 result = ctx.getOutput();
419 } catch (Exception e) {
420 throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
423 if (result == null) {
424 Response response = Response.status(Response.Status.NOT_FOUND).entity(
425 "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
426 "text/plain").build();
427 throw new CSWebApplicationException(response);
430 return result.getBytes();
434 * Finds and populates the authority list.
438 * @return the authority list
441 @Produces("application/xml")
442 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.
443 AbstractCommonList result = null;
446 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
447 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
449 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
450 DocumentFilter myFilter = handler.getDocumentFilter();
451 // Need to make the default sort order for authority items
452 // be on the displayName field
453 String sortBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
454 if (sortBy == null || sortBy.isEmpty()) {
455 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
456 + AuthorityItemJAXBSchema.DISPLAY_NAME;
457 myFilter.setOrderByClause(qualifiedDisplayNameField);
459 String nameQ = queryParams.getFirst("refName");
461 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
463 getRepositoryClient(ctx).getFiltered(ctx, handler);
464 result = handler.getCommonPartList();
465 } catch (Exception e) {
466 throw bigReThrow(e, ServiceMessages.GET_FAILED);
473 * Overriding this methods to see if we should update the revision number during the update. We don't
474 * want to update the rev number of synchronization operations.
477 protected PoxPayloadOut update(String csid,
478 PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
479 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
481 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
482 Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
483 if (shouldUpdateRev != null) {
484 handler.setShouldUpdateRevNumber(shouldUpdateRev);
486 getRepositoryClient(ctx).update(ctx, csid, handler);
487 return ctx.getOutput();
493 * @param specifier the csid or id
495 * @return the multipart output
499 public byte[] updateAuthority(
500 @PathParam("csid") String specifier,
502 PoxPayloadOut result = null;
504 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
505 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
506 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
507 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
509 if (spec.form == SpecifierForm.CSID) {
512 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
513 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
515 getRepositoryClient(ctx).update(ctx, csid, handler);
516 result = ctx.getOutput();
517 } catch (Exception e) {
518 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
520 return result.getBytes();
526 * @param csid the csid
528 * @return the response
533 public Response old_deleteAuthority(@PathParam("csid") String csid) {
534 if (logger.isDebugEnabled()) {
535 logger.debug("deleteAuthority with csid=" + csid);
538 ensureCSID(csid, ServiceMessages.DELETE_FAILED, "Authority.csid");
539 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
540 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
541 getRepositoryClient(ctx).delete(ctx, csid, handler);
542 return Response.status(HttpResponseCodes.SC_OK).build();
543 } catch (Exception e) {
544 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
551 * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
553 * @return the response
557 public Response deleteAuthority(
558 @Context Request request,
560 @PathParam("csid") String specifier) {
561 if (logger.isDebugEnabled()) {
562 logger.debug("deleteAuthority with specifier=" + specifier);
566 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
567 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
569 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
570 if (spec.form == SpecifierForm.CSID) {
571 if (logger.isDebugEnabled()) {
572 logger.debug("deleteAuthority with csid=" + spec.value);
574 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
575 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
577 if (logger.isDebugEnabled()) {
578 logger.debug("deleteAuthority with specifier=" + spec.value);
580 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
581 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
584 return Response.status(HttpResponseCodes.SC_OK).build();
585 } catch (Exception e) {
586 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
593 * @param parentspecifier - ID of the container. Can be URN or CSID form
594 * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
595 * @param proposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
599 protected Response createAuthorityItem(ServiceContext ctx, String parentIdentifier,
600 boolean shouldUpdateRevNumber,
601 boolean proposed) throws Exception {
602 Response result = null;
604 // Note: must have the parentShortId, to do the create.
605 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
606 AuthorityItemDocumentModelHandler handler =
607 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
608 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
609 handler.setIsProposed(proposed);
610 // Make the client call
611 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
613 // Build the JAX-RS response
614 UriBuilder path = UriBuilder.fromResource(resourceClass);
615 path.path(parent.CSID + "/items/" + itemcsid);
616 result = Response.created(path.build()).build();
622 * Called with an existing context.
624 * @param parentIdentifier
629 public Response createAuthorityItemWithParentContext(ServiceContext parentCtx,
630 String parentIdentifier,
632 boolean shouldUpdateRevNumber,
633 boolean isProposed) throws Exception {
634 Response result = null;
636 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
637 parentCtx.getResourceMap(), parentCtx.getUriInfo());
638 if (parentCtx.getCurrentRepositorySession() != null) {
639 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
641 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed);
646 /*************************************************************************
647 * Create an AuthorityItem - this is a sub-resource of Authority
648 * @param specifier either a CSID or one of the urn forms
649 * @return Authority item response
650 *************************************************************************/
652 @Path("{csid}/items")
653 public Response createAuthorityItem(
654 @Context ResourceMap resourceMap,
655 @Context UriInfo uriInfo,
656 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
658 Response result = null;
661 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
662 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
663 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
664 AuthorityServiceUtils.PROPOSED);
665 } catch (Exception e) {
666 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
673 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
674 public byte[] getItemWorkflow(
675 @PathParam("csid") String csid,
676 @PathParam("itemcsid") String itemcsid) {
677 PoxPayloadOut result = null;
680 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
681 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
683 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
684 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
685 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
686 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
687 result = ctx.getOutput();
688 } catch (Exception e) {
689 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
691 return result.getBytes();
694 //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
695 // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
697 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
698 public byte[] updateItemWorkflowWithTransition(
699 @PathParam("csid") String parentIdentifier,
700 @PathParam("itemcsid") String itemIdentifier,
701 @PathParam("transition") String transition) {
702 PoxPayloadOut result = null;
705 result = updateItemWorkflowWithTransition(NULL_CONTEXT,
706 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
707 } catch (Exception e) {
708 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
711 return result.getBytes();
715 * Update an authority item's workflow state.
716 * @param existingContext
721 * @throws DocumentReferenceException
723 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext existingContext,
724 String parentIdentifier,
725 String itemIdentifier,
727 boolean updateRevNumber) throws DocumentReferenceException {
728 PoxPayloadOut result = null;
732 // We need CSIDs for both the parent authority and the authority item
734 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
735 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
738 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
740 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
741 WorkflowClient.SERVICE_COMMONPART_NAME);
742 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
743 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
744 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
747 // Create a service context and document handler for the target resource -not the workflow resource itself.
749 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
750 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
751 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
752 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
754 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
756 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
757 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
759 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
760 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
761 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
763 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
764 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
765 result = ctx.getOutput();
766 } catch (DocumentReferenceException de) {
768 } catch (Exception e) {
769 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
775 private PoxPayloadOut getAuthorityItem(
777 String parentIdentifier,
778 String itemIdentifier) throws Exception {
779 PoxPayloadOut result = null;
781 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
782 // We omit the parentShortId, only needed when doing a create...
783 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
785 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
786 if (itemSpec.form == SpecifierForm.CSID) {
787 // TODO should we assert that the item is in the passed vocab?
788 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
790 String itemWhereClause =
791 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
792 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
793 handler.setDocumentFilter(myFilter);
794 getRepositoryClient(ctx).get(ctx, handler);
797 result = (PoxPayloadOut) ctx.getOutput();
798 if (result != null) {
799 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
800 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
801 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
802 itemSpec.value, inAuthority, parentcsid));
809 public PoxPayloadOut getAuthorityItemWithExistingContext(
810 ServiceContext existingCtx,
811 String parentIdentifier,
812 String itemIdentifier) throws Exception {
813 PoxPayloadOut result = null;
815 ServiceContext ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
816 if (existingCtx.getCurrentRepositorySession() != null) {
817 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
818 ctx.setProperties(existingCtx.getProperties());
820 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
826 * Gets the authority item.
828 * @param parentspecifier either a CSID or one of the urn forms
829 * @param itemspecifier either a CSID or one of the urn forms
831 * @return the authority item
834 @Path("{csid}/items/{itemcsid}")
835 public byte[] getAuthorityItem(
836 @Context Request request,
837 @Context UriInfo uriInfo,
838 @Context ResourceMap resourceMap,
839 @PathParam("csid") String parentIdentifier,
840 @PathParam("itemcsid") String itemIdentifier) {
841 PoxPayloadOut result = null;
843 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
844 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
846 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
847 ctx.setJaxRsContext(jaxRsContext);
849 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
850 } catch (DocumentNotFoundException dnf) {
851 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
852 } catch (Exception e) {
853 throw bigReThrow(e, ServiceMessages.GET_FAILED);
856 return result.getBytes();
860 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
861 * different enough that it will have to override this method in it's resource class.
864 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
865 String result = null;
867 result = NuxeoUtils.getPrimaryElPathPropertyName(
868 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
869 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
875 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
876 String result = null;
878 result = NuxeoUtils.getMultiElPathPropertyName(
879 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
880 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
886 * Gets the authorityItem list for the specified authority
887 * If partialPerm is specified, keywords will be ignored.
889 * @param specifier either a CSID or one of the urn forms
890 * @param partialTerm if non-null, matches partial terms
891 * @param keywords if non-null, matches terms in the keyword index for items
892 * @param ui passed to include additional parameters, like pagination controls
895 public AbstractCommonList getAuthorityItemList(ServiceContext existingContext,
897 UriInfo uriInfo) throws Exception {
898 AbstractCommonList result = null;
900 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
901 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
902 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
903 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
904 ctx.setProperties(existingContext.getProperties());
907 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
908 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
909 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
910 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
911 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
913 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
914 // We omit the parentShortId, only needed when doing a create...
915 String parentcsid = PARENT_WILDCARD.equals(specifier) ? null :
916 lookupParentCSID(specifier, "getAuthorityItemList", "LIST", uriInfo);
917 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
918 createItemDocumentHandler(ctx, parentcsid, null);
920 DocumentFilter myFilter = handler.getDocumentFilter();
921 // If we are not wildcarding the parent, add a restriction
922 if (parentcsid != null) {
923 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
924 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
925 + "'" + parentcsid + "'",
926 IQueryManager.SEARCH_QUALIFIER_AND);
929 if (Tools.notBlank(termStatus)) {
930 // Start with the qualified termStatus field
931 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
932 + AuthorityItemJAXBSchema.TERM_STATUS;
933 String[] filterTerms = termStatus.trim().split("\\|");
934 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
935 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
938 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
944 * Gets the authorityItem list for the specified authority
945 * If partialPerm is specified, keywords will be ignored.
947 * @param specifier either a CSID or one of the urn forms
948 * @param partialTerm if non-null, matches partial terms
949 * @param keywords if non-null, matches terms in the keyword index for items
950 * @param ui passed to include additional parameters, like pagination controls
952 * @return the authorityItem list
955 @Path("{csid}/items")
956 @Produces("application/xml")
957 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier,
958 @Context UriInfo uriInfo) {
959 AbstractCommonList result = null;
962 result = getAuthorityItemList(NULL_CONTEXT, specifier, uriInfo);
963 } catch (Exception e) {
964 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
971 * @return the name of the property used to specify references for items in this type of
972 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
973 * Some types (like Vocabulary) use a separate property.
975 protected String getRefPropName() {
976 return ServiceBindingUtils.AUTH_REF_PROP;
980 * Gets the entities referencing this Authority item instance. The service type
981 * can be passed as a query param "type", and must match a configured type
982 * for the service bindings. If not set, the type defaults to
983 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
985 * @param parentspecifier either a CSID or one of the urn forms
986 * @param itemspecifier either a CSID or one of the urn forms
989 * @return the info for the referencing objects
992 @Path("{csid}/items/{itemcsid}/refObjs")
993 @Produces("application/xml")
994 public AuthorityRefDocList getReferencingObjects(
995 @PathParam("csid") String parentSpecifier,
996 @PathParam("itemcsid") String itemSpecifier,
997 @Context UriTemplateRegistry uriTemplateRegistry,
998 @Context UriInfo uriInfo) {
999 AuthorityRefDocList authRefDocList = null;
1001 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
1002 } catch (Exception e) {
1003 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1006 if (authRefDocList == null) {
1007 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1008 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1009 "text/plain").build();
1010 throw new CSWebApplicationException(response);
1012 return authRefDocList;
1015 public AuthorityRefDocList getReferencingObjects(
1016 ServiceContext existingContext,
1017 String parentspecifier,
1018 String itemspecifier,
1019 UriTemplateRegistry uriTemplateRegistry,
1020 UriInfo uriInfo) throws Exception {
1021 AuthorityRefDocList authRefDocList = null;
1023 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1024 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1026 // Merge parts of existing context with our new context
1028 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1029 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1030 ctx.setProperties(existingContext.getProperties());
1033 String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1034 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1036 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1037 if (serviceTypes == null || serviceTypes.isEmpty()) {
1038 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1041 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1042 authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1044 return authRefDocList;
1048 * Gets the authority terms used in the indicated Authority item.
1050 * @param parentspecifier either a CSID or one of the urn forms
1051 * @param itemspecifier either a CSID or one of the urn forms
1052 * @param ui passed to include additional parameters, like pagination controls
1054 * @return the authority refs for the Authority item.
1057 @Path("{csid}/items/{itemcsid}/authorityrefs")
1058 @Produces("application/xml")
1059 public AuthorityRefList getAuthorityItemAuthorityRefs(
1060 @PathParam("csid") String parentspecifier,
1061 @PathParam("itemcsid") String itemspecifier,
1062 @Context UriInfo uriInfo) {
1063 AuthorityRefList authRefList = null;
1065 // Note that we have to create the service context for the Items, not the main service
1066 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1067 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1068 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1069 // We omit the parentShortId, only needed when doing a create...
1070 DocumentModelHandler<?, AbstractCommonList> handler =
1071 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1073 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1075 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1076 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1077 } catch (Exception e) {
1078 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1084 * Synchronizes a local authority item with a share authority server (SAS) item.
1086 * @param parentIdentifier
1087 * @param itemIdentifier
1091 private PoxPayloadOut synchronizeItem(
1093 String parentIdentifier,
1094 String itemIdentifier) throws Exception {
1095 PoxPayloadOut result = null;
1096 AuthorityItemSpecifier specifier;
1097 boolean neededSync = false;
1099 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1100 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1101 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1102 // Create an authority item specifier
1103 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1104 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1105 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1107 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1108 if (neededSync == true) {
1109 result = (PoxPayloadOut) ctx.getOutput();
1116 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1117 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1118 * local authority. The parent context was created for the authority (parent) because the sync started there.
1119 * @param existingCtx
1120 * @param parentIdentifier
1121 * @param itemIdentifier
1125 public PoxPayloadOut synchronizeItemWithExistingContext(
1126 ServiceContext existingCtx,
1127 String parentIdentifier,
1128 String itemIdentifier
1129 ) throws Exception {
1130 PoxPayloadOut result = null;
1132 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1133 existingCtx.getResourceMap(),
1134 existingCtx.getUriInfo());
1135 if (existingCtx.getCurrentRepositorySession() != null) {
1136 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1138 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1144 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1146 * @param specifier either CSIDs and/or one of the urn forms
1148 * @return the authority item if it was synchronized with SAS
1151 @Path("{csid}/items/{itemcsid}/sync")
1152 public byte[] synchronizeItem(
1153 @Context ResourceMap resourceMap,
1154 @Context UriInfo uriInfo,
1155 @PathParam("csid") String parentIdentifier,
1156 @PathParam("itemcsid") String itemIdentifier) {
1158 boolean neededSync = false;
1159 PoxPayloadOut payloadOut = null;
1162 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1163 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1164 if (payloadOut != null) {
1167 } catch (Exception e) {
1168 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1172 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1174 if (neededSync == true) {
1175 result = payloadOut.getBytes();
1177 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1178 itemIdentifier).getBytes();
1179 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1180 throw new CSWebApplicationException(response);
1187 * Update authorityItem.
1189 * @param parentspecifier either a CSID or one of the urn forms
1190 * @param itemspecifier either a CSID or one of the urn forms
1192 * @return the multipart output
1195 @Path("{csid}/items/{itemcsid}")
1196 public byte[] updateAuthorityItem(
1197 @Context ResourceMap resourceMap,
1198 @Context UriInfo uriInfo,
1199 @PathParam("csid") String parentSpecifier,
1200 @PathParam("itemcsid") String itemSpecifier,
1201 String xmlPayload) {
1202 PoxPayloadOut result = null;
1205 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1206 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1207 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1208 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1209 } catch (Exception e) {
1210 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1213 return result.getBytes();
1216 public PoxPayloadOut updateAuthorityItem(
1217 ServiceContext itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
1218 ResourceMap resourceMap,
1220 String parentspecifier,
1221 String itemspecifier,
1222 PoxPayloadIn theUpdate,
1223 boolean shouldUpdateRevNumber,
1224 Boolean isProposed) throws Exception {
1225 PoxPayloadOut result = null;
1227 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
1228 String parentcsid = csidAndShortId.CSID;
1229 String parentShortId = csidAndShortId.shortIdentifier;
1231 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
1233 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
1235 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
1237 ctx.setInput(theUpdate); // the update payload
1240 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
1242 // We omit the parentShortId, only needed when doing a create...
1243 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
1244 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1245 if (isProposed != null) {
1246 handler.setIsProposed(isProposed);
1248 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
1249 result = ctx.getOutput();
1255 * Delete authorityItem.
1257 * @param parentIdentifier the parentcsid
1258 * @param itemIdentifier the itemcsid
1260 * @return the response
1263 @Path("{csid}/items/{itemcsid}")
1264 public Response deleteAuthorityItem(
1265 @PathParam("csid") String parentIdentifier,
1266 @PathParam("itemcsid") String itemIdentifier) {
1267 Response result = null;
1269 ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1270 ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1271 if (logger.isDebugEnabled()) {
1272 logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1276 deleteAuthorityItem(null, parentIdentifier, itemIdentifier);
1277 result = Response.status(HttpResponseCodes.SC_OK).build();
1278 } catch (Exception e) {
1279 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1287 * @param existingCtx
1288 * @param parentIdentifier
1289 * @param itemIdentifier
1292 public void deleteAuthorityItem(ServiceContext existingCtx,
1293 String parentIdentifier,
1294 String itemIdentifier) throws Exception {
1295 Response result = null;
1297 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
1298 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1299 String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1301 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1302 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists
1303 ctx.setProperties(existingCtx.getProperties());
1306 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
1307 getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1311 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1312 @Produces("application/xml")
1313 public String getHierarchy(
1314 @PathParam("csid") String parentIdentifier,
1315 @PathParam("itemcsid") String itemIdentifier,
1316 @Context UriInfo uriInfo) throws Exception {
1317 String result = null;
1321 // 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...?
1323 String calledUri = uriInfo.getPath();
1324 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1325 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1327 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1328 String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1330 String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1331 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1332 result = Hierarchy.surface(ctx, itemcsid, uri);
1334 result = Hierarchy.dive(ctx, itemcsid, uri);
1336 } catch (Exception e) {
1337 throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1348 protected String getItemDocType(String tenantId) {
1349 return getDocType(tenantId, getItemServiceName());
1353 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1354 * for the current resource, for all tenants
1356 * @return a map of URI templates for the current resource, for all tenants
1359 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1360 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1361 super.getUriRegistryEntries();
1362 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1363 for (String tenantId : tenantIds) {
1364 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1366 return uriRegistryEntriesMap;