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_CONTEXT,
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 isProposed - 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,
602 boolean isSasItem) throws Exception {
603 Response result = null;
605 // Note: must have the parentShortId, to do the create.
606 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
607 AuthorityItemDocumentModelHandler handler =
608 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
609 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
610 handler.setIsProposed(isProposed);
611 handler.setIsSASItem(isSasItem);
612 // Make the client call
613 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
615 // Build the JAX-RS response
616 UriBuilder path = UriBuilder.fromResource(resourceClass);
617 path.path(parent.CSID + "/items/" + itemcsid);
618 result = Response.created(path.build()).build();
624 * Called with an existing context.
626 * @param parentIdentifier
631 public Response createAuthorityItemWithParentContext(ServiceContext parentCtx,
632 String parentIdentifier,
634 boolean shouldUpdateRevNumber,
636 boolean isSASItem) throws Exception {
637 Response result = null;
639 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
640 parentCtx.getResourceMap(), parentCtx.getUriInfo());
641 if (parentCtx.getCurrentRepositorySession() != null) {
642 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
644 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem);
649 /*************************************************************************
650 * Create an AuthorityItem - this is a sub-resource of Authority
651 * @param specifier either a CSID or one of the urn forms
652 * @return Authority item response
653 *************************************************************************/
655 @Path("{csid}/items")
656 public Response createAuthorityItem(
657 @Context ResourceMap resourceMap,
658 @Context UriInfo uriInfo,
659 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
661 Response result = null;
664 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
665 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
666 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
667 AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM);
668 } catch (Exception e) {
669 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
676 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
677 public byte[] getItemWorkflow(
678 @PathParam("csid") String csid,
679 @PathParam("itemcsid") String itemcsid) {
680 PoxPayloadOut result = null;
683 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
684 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
686 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
687 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
688 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
689 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
690 result = ctx.getOutput();
691 } catch (Exception e) {
692 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
694 return result.getBytes();
697 //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
698 // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
700 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
701 public byte[] updateItemWorkflowWithTransition(
702 @Context UriInfo uriInfo,
703 @PathParam("csid") String parentIdentifier,
704 @PathParam("itemcsid") String itemIdentifier,
705 @PathParam("transition") String transition) {
706 PoxPayloadOut result = null;
709 ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo);
710 result = updateItemWorkflowWithTransition(ctx,
711 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
712 } catch (Exception e) {
713 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
716 return result.getBytes();
720 * Update an authority item's workflow state.
721 * @param existingContext
726 * @throws DocumentReferenceException
728 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext existingContext,
729 String parentIdentifier,
730 String itemIdentifier,
732 boolean updateRevNumber) throws DocumentReferenceException {
733 PoxPayloadOut result = null;
737 // We need CSIDs for both the parent authority and the authority item
739 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
740 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
743 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
745 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
746 WorkflowClient.SERVICE_COMMONPART_NAME);
747 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
748 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
749 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
752 // Create a service context and document handler for the target resource -not the workflow resource itself.
754 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
755 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
756 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
757 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
759 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
761 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
762 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
764 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
765 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
766 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
768 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
769 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
770 result = ctx.getOutput();
771 } catch (DocumentReferenceException de) {
773 } catch (Exception e) {
774 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
780 private PoxPayloadOut getAuthorityItem(
782 String parentIdentifier,
783 String itemIdentifier) throws Exception {
784 PoxPayloadOut result = null;
786 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
787 // We omit the parentShortId, only needed when doing a create...
788 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
790 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
791 if (itemSpec.form == SpecifierForm.CSID) {
792 // TODO should we assert that the item is in the passed vocab?
793 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
795 String itemWhereClause =
796 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
797 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
798 handler.setDocumentFilter(myFilter);
799 getRepositoryClient(ctx).get(ctx, handler);
802 result = (PoxPayloadOut) ctx.getOutput();
803 if (result != null) {
804 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
805 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
806 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
807 itemSpec.value, inAuthority, parentcsid));
814 public PoxPayloadOut getAuthorityItemWithExistingContext(
815 ServiceContext existingCtx,
816 String parentIdentifier,
817 String itemIdentifier) throws Exception {
818 PoxPayloadOut result = null;
820 ServiceContext ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
821 if (existingCtx.getCurrentRepositorySession() != null) {
822 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
823 ctx.setProperties(existingCtx.getProperties());
825 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
831 * Gets the authority item.
833 * @param parentspecifier either a CSID or one of the urn forms
834 * @param itemspecifier either a CSID or one of the urn forms
836 * @return the authority item
839 @Path("{csid}/items/{itemcsid}")
840 public byte[] getAuthorityItem(
841 @Context Request request,
842 @Context UriInfo uriInfo,
843 @Context ResourceMap resourceMap,
844 @PathParam("csid") String parentIdentifier,
845 @PathParam("itemcsid") String itemIdentifier) {
846 PoxPayloadOut result = null;
848 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
849 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
851 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
852 ctx.setJaxRsContext(jaxRsContext);
854 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
855 } catch (DocumentNotFoundException dnf) {
856 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
857 } catch (Exception e) {
858 throw bigReThrow(e, ServiceMessages.GET_FAILED);
861 return result.getBytes();
865 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
866 * different enough that it will have to override this method in it's resource class.
869 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
870 String result = null;
872 result = NuxeoUtils.getPrimaryElPathPropertyName(
873 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
874 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
880 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
881 String result = null;
883 result = NuxeoUtils.getMultiElPathPropertyName(
884 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
885 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
891 * Gets the authorityItem list for the specified authority
892 * If partialPerm is specified, keywords will be ignored.
894 * @param authorityIdentifier either a CSID or one of the urn forms
895 * @param partialTerm if non-null, matches partial terms
896 * @param keywords if non-null, matches terms in the keyword index for items
897 * @param ui passed to include additional parameters, like pagination controls
900 public AbstractCommonList getAuthorityItemList(ServiceContext existingContext,
901 String authorityIdentifier,
902 UriInfo uriInfo) throws Exception {
903 AbstractCommonList result = null;
905 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
906 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
907 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
908 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
909 ctx.setProperties(existingContext.getProperties());
912 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
913 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
914 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
915 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
916 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
918 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
919 // We omit the parentShortId, only needed when doing a create...
920 String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null :
921 lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo);
922 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
923 createItemDocumentHandler(ctx, parentcsid, null);
925 DocumentFilter myFilter = handler.getDocumentFilter();
926 // If we are not wildcarding the parent, add a restriction
927 if (parentcsid != null) {
928 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
929 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
930 + "'" + parentcsid + "'",
931 IQueryManager.SEARCH_QUALIFIER_AND);
934 if (Tools.notBlank(termStatus)) {
935 // Start with the qualified termStatus field
936 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
937 + AuthorityItemJAXBSchema.TERM_STATUS;
938 String[] filterTerms = termStatus.trim().split("\\|");
939 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
940 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
943 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
949 * Gets the authorityItem list for the specified authority
950 * If partialPerm is specified, keywords will be ignored.
952 * @param authorityIdentifier either a CSID or one of the urn forms
953 * @param partialTerm if non-null, matches partial terms
954 * @param keywords if non-null, matches terms in the keyword index for items
955 * @param ui passed to include additional parameters, like pagination controls
957 * @return the authorityItem list
960 @Path("{csid}/items")
961 @Produces("application/xml")
962 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier,
963 @Context UriInfo uriInfo) {
964 AbstractCommonList result = null;
967 result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo);
968 } catch (Exception e) {
969 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
976 * @return the name of the property used to specify references for items in this type of
977 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
978 * Some types (like Vocabulary) use a separate property.
980 protected String getRefPropName() {
981 return ServiceBindingUtils.AUTH_REF_PROP;
985 * Gets the entities referencing this Authority item instance. The service type
986 * can be passed as a query param "type", and must match a configured type
987 * for the service bindings. If not set, the type defaults to
988 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
990 * @param parentspecifier either a CSID or one of the urn forms
991 * @param itemspecifier either a CSID or one of the urn forms
994 * @return the info for the referencing objects
997 @Path("{csid}/items/{itemcsid}/refObjs")
998 @Produces("application/xml")
999 public AuthorityRefDocList getReferencingObjects(
1000 @PathParam("csid") String parentSpecifier,
1001 @PathParam("itemcsid") String itemSpecifier,
1002 @Context UriTemplateRegistry uriTemplateRegistry,
1003 @Context UriInfo uriInfo) {
1004 AuthorityRefDocList authRefDocList = null;
1006 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
1007 } catch (Exception e) {
1008 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1011 if (authRefDocList == null) {
1012 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1013 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1014 "text/plain").build();
1015 throw new CSWebApplicationException(response);
1017 return authRefDocList;
1020 public AuthorityRefDocList getReferencingObjects(
1021 ServiceContext existingContext,
1022 String parentspecifier,
1023 String itemspecifier,
1024 UriTemplateRegistry uriTemplateRegistry,
1025 UriInfo uriInfo) throws Exception {
1026 AuthorityRefDocList authRefDocList = null;
1028 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1029 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1031 // Merge parts of existing context with our new context
1033 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1034 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1035 ctx.setProperties(existingContext.getProperties());
1038 String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1039 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1041 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1042 if (serviceTypes == null || serviceTypes.isEmpty()) {
1043 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1046 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1047 authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1049 return authRefDocList;
1053 * Gets the authority terms used in the indicated Authority item.
1055 * @param parentspecifier either a CSID or one of the urn forms
1056 * @param itemspecifier either a CSID or one of the urn forms
1057 * @param ui passed to include additional parameters, like pagination controls
1059 * @return the authority refs for the Authority item.
1062 @Path("{csid}/items/{itemcsid}/authorityrefs")
1063 @Produces("application/xml")
1064 public AuthorityRefList getAuthorityItemAuthorityRefs(
1065 @PathParam("csid") String parentspecifier,
1066 @PathParam("itemcsid") String itemspecifier,
1067 @Context UriInfo uriInfo) {
1068 AuthorityRefList authRefList = null;
1071 // Note that we have to create the service context for the Items, not the main service
1072 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1073 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1074 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1075 // We omit the parentShortId, only needed when doing a create...
1076 DocumentModelHandler<?, AbstractCommonList> handler =
1077 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1079 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1081 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1082 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1083 } catch (Exception e) {
1084 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1091 * Synchronizes a local authority item with a share authority server (SAS) item.
1093 * @param parentIdentifier
1094 * @param itemIdentifier
1098 private PoxPayloadOut synchronizeItem(
1100 String parentIdentifier,
1101 String itemIdentifier) throws Exception {
1102 PoxPayloadOut result = null;
1103 AuthorityItemSpecifier specifier;
1104 boolean neededSync = false;
1106 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1107 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1108 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1109 handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1110 // Create an authority item specifier
1111 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1112 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1113 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1115 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1116 if (neededSync == true) {
1117 result = (PoxPayloadOut) ctx.getOutput();
1124 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1125 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1126 * local authority. The parent context was created for the authority (parent) because the sync started there.
1127 * @param existingCtx
1128 * @param parentIdentifier
1129 * @param itemIdentifier
1133 public PoxPayloadOut synchronizeItemWithExistingContext(
1134 ServiceContext existingCtx,
1135 String parentIdentifier,
1136 String itemIdentifier
1137 ) throws Exception {
1138 PoxPayloadOut result = null;
1140 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1141 existingCtx.getResourceMap(),
1142 existingCtx.getUriInfo());
1143 if (existingCtx.getCurrentRepositorySession() != null) {
1144 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1146 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1152 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1154 * @param specifier either CSIDs and/or one of the urn forms
1156 * @return the authority item if it was synchronized with SAS
1159 @Path("{csid}/items/{itemcsid}/sync")
1160 public byte[] synchronizeItem(
1161 @Context ResourceMap resourceMap,
1162 @Context UriInfo uriInfo,
1163 @PathParam("csid") String parentIdentifier,
1164 @PathParam("itemcsid") String itemIdentifier) {
1166 boolean neededSync = false;
1167 PoxPayloadOut payloadOut = null;
1170 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1171 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1172 if (payloadOut != null) {
1175 } catch (Exception e) {
1176 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1180 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1182 if (neededSync == true) {
1183 result = payloadOut.getBytes();
1185 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1186 itemIdentifier).getBytes();
1187 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1188 throw new CSWebApplicationException(response);
1195 * Update authorityItem.
1197 * @param parentspecifier either a CSID or one of the urn forms
1198 * @param itemspecifier either a CSID or one of the urn forms
1200 * @return the multipart output
1203 @Path("{csid}/items/{itemcsid}")
1204 public byte[] updateAuthorityItem(
1205 @Context ResourceMap resourceMap,
1206 @Context UriInfo uriInfo,
1207 @PathParam("csid") String parentSpecifier,
1208 @PathParam("itemcsid") String itemSpecifier,
1209 String xmlPayload) {
1210 PoxPayloadOut result = null;
1213 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1214 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1215 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1216 AuthorityServiceUtils.NO_CHANGE, // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1217 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1218 } catch (Exception e) {
1219 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1222 return result.getBytes();
1225 public PoxPayloadOut updateAuthorityItem(
1226 ServiceContext itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
1227 ResourceMap resourceMap,
1229 String parentspecifier,
1230 String itemspecifier,
1231 PoxPayloadIn theUpdate,
1232 boolean shouldUpdateRevNumber,
1235 ) throws Exception {
1236 PoxPayloadOut result = null;
1238 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
1239 String parentcsid = csidAndShortId.CSID;
1240 String parentShortId = csidAndShortId.shortIdentifier;
1242 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
1244 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
1246 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
1248 ctx.setInput(theUpdate); // the update payload
1251 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
1253 // We omit the parentShortId, only needed when doing a create...
1254 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
1255 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1256 if (isProposed != null) {
1257 handler.setIsProposed(isProposed);
1259 if (isSASItem != null) {
1260 handler.setIsSASItem(isSASItem);
1262 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
1263 result = ctx.getOutput();
1269 * Delete authorityItem.
1271 * @param parentIdentifier the parentcsid
1272 * @param itemIdentifier the itemcsid
1274 * @return the response
1277 @Path("{csid}/items/{itemcsid}")
1278 public Response deleteAuthorityItem(
1279 @Context UriInfo uriInfo,
1280 @PathParam("csid") String parentIdentifier,
1281 @PathParam("itemcsid") String itemIdentifier) {
1282 Response result = null;
1284 ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1285 ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1286 if (logger.isDebugEnabled()) {
1287 logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1291 ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo);
1292 deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1293 result = Response.status(HttpResponseCodes.SC_OK).build();
1294 } catch (Exception e) {
1295 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1303 * @param existingCtx
1304 * @param parentIdentifier
1305 * @param itemIdentifier
1308 public void deleteAuthorityItem(ServiceContext existingCtx,
1309 String parentIdentifier,
1310 String itemIdentifier,
1311 boolean shouldUpdateRevNumber
1312 ) throws Exception {
1313 Response result = null;
1315 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1316 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1317 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1318 ctx.setProperties(existingCtx.getProperties());
1321 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1322 String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1324 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
1325 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, shouldUpdateRevNumber); // Sometimes we can only soft-delete, so if it is during a sync we dont' update the revision number
1327 getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1331 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1332 @Produces("application/xml")
1333 public String getHierarchy(
1334 @PathParam("csid") String parentIdentifier,
1335 @PathParam("itemcsid") String itemIdentifier,
1336 @Context UriInfo uriInfo) throws Exception {
1337 String result = null;
1341 // 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...?
1343 String calledUri = uriInfo.getPath();
1344 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1345 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1347 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1348 String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1350 String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1351 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1352 result = Hierarchy.surface(ctx, itemcsid, uri);
1354 result = Hierarchy.dive(ctx, itemcsid, uri);
1356 } catch (Exception e) {
1357 throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1368 protected String getItemDocType(String tenantId) {
1369 return getDocType(tenantId, getItemServiceName());
1373 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1374 * for the current resource, for all tenants
1376 * @return a map of URI templates for the current resource, for all tenants
1379 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1380 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1381 super.getUriRegistryEntries();
1382 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1383 for (String tenantId : tenantIds) {
1384 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1386 return uriRegistryEntriesMap;