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 @Context UriInfo uriInfo,
700 @PathParam("csid") String parentIdentifier,
701 @PathParam("itemcsid") String itemIdentifier,
702 @PathParam("transition") String transition) {
703 PoxPayloadOut result = null;
706 ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo);
707 result = updateItemWorkflowWithTransition(ctx,
708 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
709 } catch (Exception e) {
710 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
713 return result.getBytes();
717 * Update an authority item's workflow state.
718 * @param existingContext
723 * @throws DocumentReferenceException
725 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext existingContext,
726 String parentIdentifier,
727 String itemIdentifier,
729 boolean updateRevNumber) throws DocumentReferenceException {
730 PoxPayloadOut result = null;
734 // We need CSIDs for both the parent authority and the authority item
736 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
737 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
740 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
742 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
743 WorkflowClient.SERVICE_COMMONPART_NAME);
744 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
745 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
746 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
749 // Create a service context and document handler for the target resource -not the workflow resource itself.
751 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
752 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
753 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
754 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
756 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
758 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
759 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
761 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
762 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
763 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
765 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
766 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
767 result = ctx.getOutput();
768 } catch (DocumentReferenceException de) {
770 } catch (Exception e) {
771 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
777 private PoxPayloadOut getAuthorityItem(
779 String parentIdentifier,
780 String itemIdentifier) throws Exception {
781 PoxPayloadOut result = null;
783 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
784 // We omit the parentShortId, only needed when doing a create...
785 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
787 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
788 if (itemSpec.form == SpecifierForm.CSID) {
789 // TODO should we assert that the item is in the passed vocab?
790 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
792 String itemWhereClause =
793 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
794 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
795 handler.setDocumentFilter(myFilter);
796 getRepositoryClient(ctx).get(ctx, handler);
799 result = (PoxPayloadOut) ctx.getOutput();
800 if (result != null) {
801 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
802 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
803 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
804 itemSpec.value, inAuthority, parentcsid));
811 public PoxPayloadOut getAuthorityItemWithExistingContext(
812 ServiceContext existingCtx,
813 String parentIdentifier,
814 String itemIdentifier) throws Exception {
815 PoxPayloadOut result = null;
817 ServiceContext ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
818 if (existingCtx.getCurrentRepositorySession() != null) {
819 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
820 ctx.setProperties(existingCtx.getProperties());
822 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
828 * Gets the authority item.
830 * @param parentspecifier either a CSID or one of the urn forms
831 * @param itemspecifier either a CSID or one of the urn forms
833 * @return the authority item
836 @Path("{csid}/items/{itemcsid}")
837 public byte[] getAuthorityItem(
838 @Context Request request,
839 @Context UriInfo uriInfo,
840 @Context ResourceMap resourceMap,
841 @PathParam("csid") String parentIdentifier,
842 @PathParam("itemcsid") String itemIdentifier) {
843 PoxPayloadOut result = null;
845 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
846 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
848 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
849 ctx.setJaxRsContext(jaxRsContext);
851 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
852 } catch (DocumentNotFoundException dnf) {
853 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
854 } catch (Exception e) {
855 throw bigReThrow(e, ServiceMessages.GET_FAILED);
858 return result.getBytes();
862 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
863 * different enough that it will have to override this method in it's resource class.
866 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
867 String result = null;
869 result = NuxeoUtils.getPrimaryElPathPropertyName(
870 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
871 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
877 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
878 String result = null;
880 result = NuxeoUtils.getMultiElPathPropertyName(
881 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
882 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
888 * Gets the authorityItem list for the specified authority
889 * If partialPerm is specified, keywords will be ignored.
891 * @param specifier either a CSID or one of the urn forms
892 * @param partialTerm if non-null, matches partial terms
893 * @param keywords if non-null, matches terms in the keyword index for items
894 * @param ui passed to include additional parameters, like pagination controls
897 public AbstractCommonList getAuthorityItemList(ServiceContext existingContext,
899 UriInfo uriInfo) throws Exception {
900 AbstractCommonList result = null;
902 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
903 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
904 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
905 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
906 ctx.setProperties(existingContext.getProperties());
909 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
910 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
911 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
912 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
913 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
915 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
916 // We omit the parentShortId, only needed when doing a create...
917 String parentcsid = PARENT_WILDCARD.equals(specifier) ? null :
918 lookupParentCSID(specifier, "getAuthorityItemList", "LIST", uriInfo);
919 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
920 createItemDocumentHandler(ctx, parentcsid, null);
922 DocumentFilter myFilter = handler.getDocumentFilter();
923 // If we are not wildcarding the parent, add a restriction
924 if (parentcsid != null) {
925 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
926 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
927 + "'" + parentcsid + "'",
928 IQueryManager.SEARCH_QUALIFIER_AND);
931 if (Tools.notBlank(termStatus)) {
932 // Start with the qualified termStatus field
933 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
934 + AuthorityItemJAXBSchema.TERM_STATUS;
935 String[] filterTerms = termStatus.trim().split("\\|");
936 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
937 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
940 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
946 * Gets the authorityItem list for the specified authority
947 * If partialPerm is specified, keywords will be ignored.
949 * @param specifier either a CSID or one of the urn forms
950 * @param partialTerm if non-null, matches partial terms
951 * @param keywords if non-null, matches terms in the keyword index for items
952 * @param ui passed to include additional parameters, like pagination controls
954 * @return the authorityItem list
957 @Path("{csid}/items")
958 @Produces("application/xml")
959 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier,
960 @Context UriInfo uriInfo) {
961 AbstractCommonList result = null;
964 result = getAuthorityItemList(NULL_CONTEXT, specifier, uriInfo);
965 } catch (Exception e) {
966 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
973 * @return the name of the property used to specify references for items in this type of
974 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
975 * Some types (like Vocabulary) use a separate property.
977 protected String getRefPropName() {
978 return ServiceBindingUtils.AUTH_REF_PROP;
982 * Gets the entities referencing this Authority item instance. The service type
983 * can be passed as a query param "type", and must match a configured type
984 * for the service bindings. If not set, the type defaults to
985 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
987 * @param parentspecifier either a CSID or one of the urn forms
988 * @param itemspecifier either a CSID or one of the urn forms
991 * @return the info for the referencing objects
994 @Path("{csid}/items/{itemcsid}/refObjs")
995 @Produces("application/xml")
996 public AuthorityRefDocList getReferencingObjects(
997 @PathParam("csid") String parentSpecifier,
998 @PathParam("itemcsid") String itemSpecifier,
999 @Context UriTemplateRegistry uriTemplateRegistry,
1000 @Context UriInfo uriInfo) {
1001 AuthorityRefDocList authRefDocList = null;
1003 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
1004 } catch (Exception e) {
1005 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1008 if (authRefDocList == null) {
1009 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1010 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1011 "text/plain").build();
1012 throw new CSWebApplicationException(response);
1014 return authRefDocList;
1017 public AuthorityRefDocList getReferencingObjects(
1018 ServiceContext existingContext,
1019 String parentspecifier,
1020 String itemspecifier,
1021 UriTemplateRegistry uriTemplateRegistry,
1022 UriInfo uriInfo) throws Exception {
1023 AuthorityRefDocList authRefDocList = null;
1025 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1026 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1028 // Merge parts of existing context with our new context
1030 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1031 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1032 ctx.setProperties(existingContext.getProperties());
1035 String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1036 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1038 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1039 if (serviceTypes == null || serviceTypes.isEmpty()) {
1040 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1043 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1044 authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1046 return authRefDocList;
1050 * Gets the authority terms used in the indicated Authority item.
1052 * @param parentspecifier either a CSID or one of the urn forms
1053 * @param itemspecifier either a CSID or one of the urn forms
1054 * @param ui passed to include additional parameters, like pagination controls
1056 * @return the authority refs for the Authority item.
1059 @Path("{csid}/items/{itemcsid}/authorityrefs")
1060 @Produces("application/xml")
1061 public AuthorityRefList getAuthorityItemAuthorityRefs(
1062 @PathParam("csid") String parentspecifier,
1063 @PathParam("itemcsid") String itemspecifier,
1064 @Context UriInfo uriInfo) {
1065 AuthorityRefList authRefList = null;
1067 // Note that we have to create the service context for the Items, not the main service
1068 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1069 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1070 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1071 // We omit the parentShortId, only needed when doing a create...
1072 DocumentModelHandler<?, AbstractCommonList> handler =
1073 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1075 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1077 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1078 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1079 } catch (Exception e) {
1080 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1086 * Synchronizes a local authority item with a share authority server (SAS) item.
1088 * @param parentIdentifier
1089 * @param itemIdentifier
1093 private PoxPayloadOut synchronizeItem(
1095 String parentIdentifier,
1096 String itemIdentifier) throws Exception {
1097 PoxPayloadOut result = null;
1098 AuthorityItemSpecifier specifier;
1099 boolean neededSync = false;
1101 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1102 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1103 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1104 // Create an authority item specifier
1105 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1106 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1107 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1109 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1110 if (neededSync == true) {
1111 result = (PoxPayloadOut) ctx.getOutput();
1118 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1119 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1120 * local authority. The parent context was created for the authority (parent) because the sync started there.
1121 * @param existingCtx
1122 * @param parentIdentifier
1123 * @param itemIdentifier
1127 public PoxPayloadOut synchronizeItemWithExistingContext(
1128 ServiceContext existingCtx,
1129 String parentIdentifier,
1130 String itemIdentifier
1131 ) throws Exception {
1132 PoxPayloadOut result = null;
1134 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1135 existingCtx.getResourceMap(),
1136 existingCtx.getUriInfo());
1137 if (existingCtx.getCurrentRepositorySession() != null) {
1138 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1140 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1146 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1148 * @param specifier either CSIDs and/or one of the urn forms
1150 * @return the authority item if it was synchronized with SAS
1153 @Path("{csid}/items/{itemcsid}/sync")
1154 public byte[] synchronizeItem(
1155 @Context ResourceMap resourceMap,
1156 @Context UriInfo uriInfo,
1157 @PathParam("csid") String parentIdentifier,
1158 @PathParam("itemcsid") String itemIdentifier) {
1160 boolean neededSync = false;
1161 PoxPayloadOut payloadOut = null;
1164 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1165 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1166 if (payloadOut != null) {
1169 } catch (Exception e) {
1170 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1174 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1176 if (neededSync == true) {
1177 result = payloadOut.getBytes();
1179 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1180 itemIdentifier).getBytes();
1181 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1182 throw new CSWebApplicationException(response);
1189 * Update authorityItem.
1191 * @param parentspecifier either a CSID or one of the urn forms
1192 * @param itemspecifier either a CSID or one of the urn forms
1194 * @return the multipart output
1197 @Path("{csid}/items/{itemcsid}")
1198 public byte[] updateAuthorityItem(
1199 @Context ResourceMap resourceMap,
1200 @Context UriInfo uriInfo,
1201 @PathParam("csid") String parentSpecifier,
1202 @PathParam("itemcsid") String itemSpecifier,
1203 String xmlPayload) {
1204 PoxPayloadOut result = null;
1207 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1208 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1209 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1210 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1211 } catch (Exception e) {
1212 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1215 return result.getBytes();
1218 public PoxPayloadOut updateAuthorityItem(
1219 ServiceContext itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
1220 ResourceMap resourceMap,
1222 String parentspecifier,
1223 String itemspecifier,
1224 PoxPayloadIn theUpdate,
1225 boolean shouldUpdateRevNumber,
1226 Boolean isProposed) throws Exception {
1227 PoxPayloadOut result = null;
1229 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
1230 String parentcsid = csidAndShortId.CSID;
1231 String parentShortId = csidAndShortId.shortIdentifier;
1233 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
1235 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
1237 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
1239 ctx.setInput(theUpdate); // the update payload
1242 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
1244 // We omit the parentShortId, only needed when doing a create...
1245 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
1246 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1247 if (isProposed != null) {
1248 handler.setIsProposed(isProposed);
1250 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
1251 result = ctx.getOutput();
1257 * Delete authorityItem.
1259 * @param parentIdentifier the parentcsid
1260 * @param itemIdentifier the itemcsid
1262 * @return the response
1265 @Path("{csid}/items/{itemcsid}")
1266 public Response deleteAuthorityItem(
1267 @Context UriInfo uriInfo,
1268 @PathParam("csid") String parentIdentifier,
1269 @PathParam("itemcsid") String itemIdentifier) {
1270 Response result = null;
1272 ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1273 ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1274 if (logger.isDebugEnabled()) {
1275 logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1279 ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo);
1280 deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1281 result = Response.status(HttpResponseCodes.SC_OK).build();
1282 } catch (Exception e) {
1283 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1291 * @param existingCtx
1292 * @param parentIdentifier
1293 * @param itemIdentifier
1296 public void deleteAuthorityItem(ServiceContext existingCtx,
1297 String parentIdentifier,
1298 String itemIdentifier) throws Exception {
1299 Response result = null;
1301 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1302 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1303 String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1305 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1306 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists
1307 ctx.setProperties(existingCtx.getProperties());
1310 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
1311 getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1315 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1316 @Produces("application/xml")
1317 public String getHierarchy(
1318 @PathParam("csid") String parentIdentifier,
1319 @PathParam("itemcsid") String itemIdentifier,
1320 @Context UriInfo uriInfo) throws Exception {
1321 String result = null;
1325 // 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...?
1327 String calledUri = uriInfo.getPath();
1328 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1329 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1331 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1332 String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1334 String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1335 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1336 result = Hierarchy.surface(ctx, itemcsid, uri);
1338 result = Hierarchy.dive(ctx, itemcsid, uri);
1340 } catch (Exception e) {
1341 throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1352 protected String getItemDocType(String tenantId) {
1353 return getDocType(tenantId, getItemServiceName());
1357 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1358 * for the current resource, for all tenants
1360 * @return a map of URI templates for the current resource, for all tenants
1363 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1364 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1365 super.getUriRegistryEntries();
1366 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1367 for (String tenantId : tenantIds) {
1368 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1370 return uriRegistryEntriesMap;