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)
272 Specifier itemSpec = Specifier.getSpecifier(itemspecifier, method, op);
273 if (itemSpec.form == SpecifierForm.CSID) {
274 itemcsid = itemSpec.value;
276 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
277 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(getItemServiceName());
278 CoreSessionInterface repoSession = null;
279 if (existingContext != null) {
280 repoSession = (CoreSessionInterface) existingContext.getCurrentRepositorySession(); // We want to use the thread's current repo session
282 itemcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
288 * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
289 * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
290 * Resource. They then call this method on that resource.
293 public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
294 throws Exception, DocumentNotFoundException {
298 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
299 // Ensure we have the right context.
300 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
302 // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
303 RepositoryClientImpl client = (RepositoryClientImpl)getRepositoryClient(ctx);
304 String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
306 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
307 ctx = createServiceContext(getItemServiceName());
308 DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
309 DocumentModel docModel = docWrapper.getWrappedObject();
315 public Response createAuthority(String xmlPayload) {
317 // 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
318 // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
319 // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
320 // the code that creates new authorities. The authority document model handler will first check for authorities with the same short id before
321 // trying to create a new authority.
323 synchronized(AuthorityResource.class) {
325 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
326 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
327 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
329 String csid = getRepositoryClient(ctx).create(ctx, handler);
330 UriBuilder path = UriBuilder.fromResource(resourceClass);
331 path.path("" + csid);
332 Response response = Response.created(path.build()).build();
334 } catch (Exception e) {
335 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
342 * Synchronizes the authority and its terms with a Shared Authority Server.
344 * @param specifier either a CSID or one of the urn forms
346 * @return the authority
350 public byte[] synchronize(
351 @Context Request request,
353 @PathParam("csid") String csid) {
355 boolean neededSync = false;
356 PoxPayloadOut payloadOut = null;
360 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
361 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
362 specifier = Specifier.getSpecifier(csid, "getAuthority", "GET");
363 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
364 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
365 payloadOut = ctx.getOutput();
366 } catch (Exception e) {
367 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, csid);
371 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
373 if (neededSync == true) {
374 result = payloadOut.getBytes();
376 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
377 specifier.value).getBytes();
378 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
379 throw new CSWebApplicationException(response);
385 * Gets the authority.
387 * @param specifier either a CSID or one of the urn forms
389 * @return the authority
395 @Context Request request,
397 @PathParam("csid") String specifier) {
398 PoxPayloadOut result = null;
400 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
401 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
403 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
404 if (spec.form == SpecifierForm.CSID) {
405 if (logger.isDebugEnabled()) {
406 logger.debug("getAuthority with csid=" + spec.value);
408 getRepositoryClient(ctx).get(ctx, spec.value, handler);
410 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
411 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
412 handler.setDocumentFilter(myFilter);
413 getRepositoryClient(ctx).get(ctx, handler);
415 result = ctx.getOutput();
417 } catch (Exception e) {
418 throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
421 if (result == null) {
422 Response response = Response.status(Response.Status.NOT_FOUND).entity(
423 "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
424 "text/plain").build();
425 throw new CSWebApplicationException(response);
428 return result.getBytes();
432 * Finds and populates the authority list.
436 * @return the authority list
439 @Produces("application/xml")
440 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.
441 AbstractCommonList result = null;
444 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
445 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
447 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
448 DocumentFilter myFilter = handler.getDocumentFilter();
449 // Need to make the default sort order for authority items
450 // be on the displayName field
451 String sortBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
452 if (sortBy == null || sortBy.isEmpty()) {
453 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
454 + AuthorityItemJAXBSchema.DISPLAY_NAME;
455 myFilter.setOrderByClause(qualifiedDisplayNameField);
457 String nameQ = queryParams.getFirst("refName");
459 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
461 getRepositoryClient(ctx).getFiltered(ctx, handler);
462 result = handler.getCommonPartList();
463 } catch (Exception e) {
464 throw bigReThrow(e, ServiceMessages.GET_FAILED);
471 * Overriding this methods to see if we should update the revision number during the update. We don't
472 * want to update the rev number of synchronization operations.
475 protected PoxPayloadOut update(String csid,
476 PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
477 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
479 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
480 Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
481 if (shouldUpdateRev != null) {
482 handler.setShouldUpdateRevNumber(shouldUpdateRev);
484 getRepositoryClient(ctx).update(ctx, csid, handler);
485 return ctx.getOutput();
491 * @param specifier the csid or id
493 * @return the multipart output
497 public byte[] updateAuthority(
498 @PathParam("csid") String specifier,
500 PoxPayloadOut result = null;
502 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
503 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
504 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
505 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
507 if (spec.form == SpecifierForm.CSID) {
510 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
511 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
513 getRepositoryClient(ctx).update(ctx, csid, handler);
514 result = ctx.getOutput();
515 } catch (Exception e) {
516 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
518 return result.getBytes();
524 * @param csid the csid
526 * @return the response
531 public Response old_deleteAuthority(@PathParam("csid") String csid) {
532 if (logger.isDebugEnabled()) {
533 logger.debug("deleteAuthority with csid=" + csid);
536 ensureCSID(csid, ServiceMessages.DELETE_FAILED, "Authority.csid");
537 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
538 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
539 getRepositoryClient(ctx).delete(ctx, csid, handler);
540 return Response.status(HttpResponseCodes.SC_OK).build();
541 } catch (Exception e) {
542 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
549 * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
551 * @return the response
555 public Response deleteAuthority(
556 @Context Request request,
558 @PathParam("csid") String specifier) {
559 if (logger.isDebugEnabled()) {
560 logger.debug("deleteAuthority with specifier=" + specifier);
564 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
565 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
567 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
568 if (spec.form == SpecifierForm.CSID) {
569 if (logger.isDebugEnabled()) {
570 logger.debug("deleteAuthority with csid=" + spec.value);
572 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
573 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
575 if (logger.isDebugEnabled()) {
576 logger.debug("deleteAuthority with specifier=" + spec.value);
578 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
579 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
582 return Response.status(HttpResponseCodes.SC_OK).build();
583 } catch (Exception e) {
584 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
591 * @param parentspecifier - ID of the container. Can be URN or CSID form
592 * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
593 * @param proposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
597 protected Response createAuthorityItem(ServiceContext ctx, String parentIdentifier,
598 boolean shouldUpdateRevNumber,
599 boolean proposed) throws Exception {
600 Response result = null;
602 // Note: must have the parentShortId, to do the create.
603 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
604 AuthorityItemDocumentModelHandler handler =
605 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
606 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
607 handler.setIsProposed(proposed);
608 // Make the client call
609 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
611 // Build the JAX-RS response
612 UriBuilder path = UriBuilder.fromResource(resourceClass);
613 path.path(parent.CSID + "/items/" + itemcsid);
614 result = Response.created(path.build()).build();
620 * Called with an existing context.
622 * @param parentIdentifier
627 public Response createAuthorityItemWithParentContext(ServiceContext parentCtx,
628 String parentIdentifier,
630 boolean shouldUpdateRevNumber,
631 boolean isProposed) throws Exception {
632 Response result = null;
634 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
635 parentCtx.getResourceMap(), parentCtx.getUriInfo());
636 if (parentCtx.getCurrentRepositorySession() != null) {
637 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
639 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed);
644 /*************************************************************************
645 * Create an AuthorityItem - this is a sub-resource of Authority
646 * @param specifier either a CSID or one of the urn forms
647 * @return Authority item response
648 *************************************************************************/
650 @Path("{csid}/items")
651 public Response createAuthorityItem(
652 @Context ResourceMap resourceMap,
653 @Context UriInfo uriInfo,
654 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
656 Response result = null;
659 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
660 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
661 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
662 AuthorityServiceUtils.PROPOSED);
663 } catch (Exception e) {
664 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
671 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
672 public byte[] getItemWorkflow(
673 @PathParam("csid") String csid,
674 @PathParam("itemcsid") String itemcsid) {
675 PoxPayloadOut result = null;
678 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
679 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
681 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
682 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
683 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
684 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
685 result = ctx.getOutput();
686 } catch (Exception e) {
687 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
689 return result.getBytes();
692 //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
693 // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
695 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
696 public byte[] updateItemWorkflowWithTransition(
697 @PathParam("csid") String parentIdentifier,
698 @PathParam("itemcsid") String itemIdentifier,
699 @PathParam("transition") String transition) {
700 PoxPayloadOut result = null;
703 result = updateItemWorkflowWithTransition(NULL_CONTEXT,
704 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
705 } catch (Exception e) {
706 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
709 return result.getBytes();
713 * Update an authority item's workflow state.
714 * @param existingContext
719 * @throws DocumentReferenceException
721 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext existingContext,
722 String parentIdentifier,
723 String itemIdentifier,
725 boolean updateRevNumber) throws DocumentReferenceException {
726 PoxPayloadOut result = null;
730 // We need CSIDs for both the parent authority and the authority item
732 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
733 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
736 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
738 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
739 WorkflowClient.SERVICE_COMMONPART_NAME);
740 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
741 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
742 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If a repo session is already open, we need to use it and not create a new one
745 // Create a service context and document handler for the target resource -not the workflow resource itself.
747 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName());
748 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
749 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
750 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
752 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
754 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
755 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
757 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
758 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
759 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
761 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
762 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
763 result = ctx.getOutput();
764 } catch (DocumentReferenceException de) {
766 } catch (Exception e) {
767 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
773 private PoxPayloadOut getAuthorityItem(
775 String parentIdentifier,
776 String itemIdentifier) throws Exception {
777 PoxPayloadOut result = null;
779 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
780 // We omit the parentShortId, only needed when doing a create...
781 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
783 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
784 if (itemSpec.form == SpecifierForm.CSID) {
785 // TODO should we assert that the item is in the passed vocab?
786 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
788 String itemWhereClause =
789 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
790 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
791 handler.setDocumentFilter(myFilter);
792 getRepositoryClient(ctx).get(ctx, handler);
795 result = (PoxPayloadOut) ctx.getOutput();
796 if (result != null) {
797 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
798 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
799 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
800 itemSpec.value, inAuthority, parentcsid));
807 public PoxPayloadOut getAuthorityItemWithExistingContext(
808 ServiceContext existingCtx,
809 String parentIdentifier,
810 String itemIdentifier) throws Exception {
811 PoxPayloadOut result = null;
813 ServiceContext ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
814 if (existingCtx.getCurrentRepositorySession() != null) {
815 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
816 ctx.setProperties(existingCtx.getProperties());
818 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
824 * Gets the authority item.
826 * @param parentspecifier either a CSID or one of the urn forms
827 * @param itemspecifier either a CSID or one of the urn forms
829 * @return the authority item
832 @Path("{csid}/items/{itemcsid}")
833 public byte[] getAuthorityItem(
834 @Context Request request,
835 @Context UriInfo uriInfo,
836 @Context ResourceMap resourceMap,
837 @PathParam("csid") String parentIdentifier,
838 @PathParam("itemcsid") String itemIdentifier) {
839 PoxPayloadOut result = null;
841 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
842 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
844 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
845 ctx.setJaxRsContext(jaxRsContext);
847 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
848 } catch (DocumentNotFoundException dnf) {
849 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
850 } catch (Exception e) {
851 throw bigReThrow(e, ServiceMessages.GET_FAILED);
854 return result.getBytes();
858 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
859 * different enough that it will have to override this method in it's resource class.
862 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
863 String result = null;
865 result = NuxeoUtils.getPrimaryElPathPropertyName(
866 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
867 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
873 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
874 String result = null;
876 result = NuxeoUtils.getMultiElPathPropertyName(
877 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
878 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
884 * Gets the authorityItem list for the specified authority
885 * If partialPerm is specified, keywords will be ignored.
887 * @param specifier either a CSID or one of the urn forms
888 * @param partialTerm if non-null, matches partial terms
889 * @param keywords if non-null, matches terms in the keyword index for items
890 * @param ui passed to include additional parameters, like pagination controls
893 public AbstractCommonList getAuthorityItemList(ServiceContext existingContext,
895 UriInfo uriInfo) throws Exception {
896 AbstractCommonList result = null;
898 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
899 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
900 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
901 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
902 ctx.setProperties(existingContext.getProperties());
905 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
906 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
907 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
908 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
909 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
911 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
912 // We omit the parentShortId, only needed when doing a create...
913 String parentcsid = PARENT_WILDCARD.equals(specifier) ? null :
914 lookupParentCSID(specifier, "getAuthorityItemList", "LIST", uriInfo);
915 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
916 createItemDocumentHandler(ctx, parentcsid, null);
918 DocumentFilter myFilter = handler.getDocumentFilter();
919 // If we are not wildcarding the parent, add a restriction
920 if (parentcsid != null) {
921 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
922 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
923 + "'" + parentcsid + "'",
924 IQueryManager.SEARCH_QUALIFIER_AND);
927 if (Tools.notBlank(termStatus)) {
928 // Start with the qualified termStatus field
929 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
930 + AuthorityItemJAXBSchema.TERM_STATUS;
931 String[] filterTerms = termStatus.trim().split("\\|");
932 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
933 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
936 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
942 * Gets the authorityItem list for the specified authority
943 * If partialPerm is specified, keywords will be ignored.
945 * @param specifier either a CSID or one of the urn forms
946 * @param partialTerm if non-null, matches partial terms
947 * @param keywords if non-null, matches terms in the keyword index for items
948 * @param ui passed to include additional parameters, like pagination controls
950 * @return the authorityItem list
953 @Path("{csid}/items")
954 @Produces("application/xml")
955 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier,
956 @Context UriInfo uriInfo) {
957 AbstractCommonList result = null;
960 result = getAuthorityItemList(NULL_CONTEXT, specifier, uriInfo);
961 } catch (Exception e) {
962 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
969 * @return the name of the property used to specify references for items in this type of
970 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
971 * Some types (like Vocabulary) use a separate property.
973 protected String getRefPropName() {
974 return ServiceBindingUtils.AUTH_REF_PROP;
978 * Gets the entities referencing this Authority item instance. The service type
979 * can be passed as a query param "type", and must match a configured type
980 * for the service bindings. If not set, the type defaults to
981 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
983 * @param parentspecifier either a CSID or one of the urn forms
984 * @param itemspecifier either a CSID or one of the urn forms
987 * @return the info for the referencing objects
990 @Path("{csid}/items/{itemcsid}/refObjs")
991 @Produces("application/xml")
992 public AuthorityRefDocList getReferencingObjects(
993 @PathParam("csid") String parentSpecifier,
994 @PathParam("itemcsid") String itemSpecifier,
995 @Context UriTemplateRegistry uriTemplateRegistry,
996 @Context UriInfo uriInfo) {
997 AuthorityRefDocList authRefDocList = null;
999 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
1000 } catch (Exception e) {
1001 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1004 if (authRefDocList == null) {
1005 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1006 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1007 "text/plain").build();
1008 throw new CSWebApplicationException(response);
1010 return authRefDocList;
1013 public AuthorityRefDocList getReferencingObjects(
1014 ServiceContext existingContext,
1015 String parentspecifier,
1016 String itemspecifier,
1017 UriTemplateRegistry uriTemplateRegistry,
1018 UriInfo uriInfo) throws Exception {
1019 AuthorityRefDocList authRefDocList = null;
1021 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1022 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1024 // Merge parts of existing context with our new context
1026 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1027 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1028 ctx.setProperties(existingContext.getProperties());
1031 String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1032 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1034 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1035 if (serviceTypes == null || serviceTypes.isEmpty()) {
1036 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1039 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1040 authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1042 return authRefDocList;
1046 * Gets the authority terms used in the indicated Authority item.
1048 * @param parentspecifier either a CSID or one of the urn forms
1049 * @param itemspecifier either a CSID or one of the urn forms
1050 * @param ui passed to include additional parameters, like pagination controls
1052 * @return the authority refs for the Authority item.
1055 @Path("{csid}/items/{itemcsid}/authorityrefs")
1056 @Produces("application/xml")
1057 public AuthorityRefList getAuthorityItemAuthorityRefs(
1058 @PathParam("csid") String parentspecifier,
1059 @PathParam("itemcsid") String itemspecifier,
1060 @Context UriInfo uriInfo) {
1061 AuthorityRefList authRefList = null;
1063 // Note that we have to create the service context for the Items, not the main service
1064 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1065 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1066 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1067 // We omit the parentShortId, only needed when doing a create...
1068 DocumentModelHandler<?, AbstractCommonList> handler =
1069 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1071 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1073 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1074 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1075 } catch (Exception e) {
1076 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1082 * Synchronizes a local authority item with a share authority server (SAS) item.
1084 * @param parentIdentifier
1085 * @param itemIdentifier
1089 private PoxPayloadOut synchronizeItem(
1091 String parentIdentifier,
1092 String itemIdentifier) throws Exception {
1093 PoxPayloadOut result = null;
1094 AuthorityItemSpecifier specifier;
1095 boolean neededSync = false;
1097 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1098 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1099 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1100 // Create an authority item specifier
1101 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1102 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1103 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1105 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1106 if (neededSync == true) {
1107 result = (PoxPayloadOut) ctx.getOutput();
1114 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1115 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1116 * local authority. The parent context was created for the authority (parent) because the sync started there.
1117 * @param existingCtx
1118 * @param parentIdentifier
1119 * @param itemIdentifier
1123 public PoxPayloadOut synchronizeItemWithExistingContext(
1124 ServiceContext existingCtx,
1125 String parentIdentifier,
1126 String itemIdentifier
1127 ) throws Exception {
1128 PoxPayloadOut result = null;
1130 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1131 existingCtx.getResourceMap(),
1132 existingCtx.getUriInfo());
1133 if (existingCtx.getCurrentRepositorySession() != null) {
1134 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1136 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1142 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1144 * @param specifier either CSIDs and/or one of the urn forms
1146 * @return the authority item if it was synchronized with SAS
1149 @Path("{csid}/items/{itemcsid}/sync")
1150 public byte[] synchronizeItem(
1151 @Context ResourceMap resourceMap,
1152 @Context UriInfo uriInfo,
1153 @PathParam("csid") String parentIdentifier,
1154 @PathParam("itemcsid") String itemIdentifier) {
1156 boolean neededSync = false;
1157 PoxPayloadOut payloadOut = null;
1160 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1161 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier);
1162 if (payloadOut != null) {
1165 } catch (Exception e) {
1166 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1170 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1172 if (neededSync == true) {
1173 result = payloadOut.getBytes();
1175 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1176 itemIdentifier).getBytes();
1177 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1178 throw new CSWebApplicationException(response);
1185 * Update authorityItem.
1187 * @param parentspecifier either a CSID or one of the urn forms
1188 * @param itemspecifier either a CSID or one of the urn forms
1190 * @return the multipart output
1193 @Path("{csid}/items/{itemcsid}")
1194 public byte[] updateAuthorityItem(
1195 @Context ResourceMap resourceMap,
1196 @Context UriInfo uriInfo,
1197 @PathParam("csid") String parentSpecifier,
1198 @PathParam("itemcsid") String itemSpecifier,
1199 String xmlPayload) {
1200 PoxPayloadOut result = null;
1203 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1204 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1205 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1206 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1207 } catch (Exception e) {
1208 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1211 return result.getBytes();
1214 public PoxPayloadOut updateAuthorityItem(
1215 ServiceContext itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
1216 ResourceMap resourceMap,
1218 String parentspecifier,
1219 String itemspecifier,
1220 PoxPayloadIn theUpdate,
1221 boolean shouldUpdateRevNumber,
1222 Boolean isProposed) throws Exception {
1223 PoxPayloadOut result = null;
1225 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
1226 String parentcsid = csidAndShortId.CSID;
1227 String parentShortId = csidAndShortId.shortIdentifier;
1229 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
1231 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
1233 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
1235 ctx.setInput(theUpdate); // the update payload
1238 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
1240 // We omit the parentShortId, only needed when doing a create...
1241 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
1242 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1243 if (isProposed != null) {
1244 handler.setIsProposed(isProposed);
1246 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
1247 result = ctx.getOutput();
1253 * Delete authorityItem.
1255 * @param parentcsid the parentcsid
1256 * @param itemcsid the itemcsid
1258 * @return the response
1261 @Path("{csid}/items/{itemcsid}")
1262 public Response deleteAuthorityItem(
1263 @PathParam("csid") String parentcsid,
1264 @PathParam("itemcsid") String itemcsid) {
1265 Response result = null;
1267 if (logger.isDebugEnabled()) {
1268 logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
1272 deleteAuthorityItem(null, parentcsid, itemcsid);
1273 result = Response.status(HttpResponseCodes.SC_OK).build();
1274 } catch (Exception e) {
1275 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
1277 //Laramie, removing this catch, since it will surely fail below, since itemcsid or parentcsid will be null.
1280 // }catch (Throwable t){
1281 public void deleteAuthorityItem(ServiceContext existingCtx,
1283 String itemcsid) throws Exception {
1284 Response result = null;
1285 // System.out.println("ERROR in setting up DELETE: "+t);
1286 ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1287 ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1289 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
1290 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1291 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists
1292 ctx.setProperties(existingCtx.getProperties());
1294 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
1295 getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
1299 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1300 @Produces("application/xml")
1301 public String getHierarchy(@PathParam("csid") String csid,
1302 @PathParam("itemcsid") String itemcsid,
1303 @Context UriInfo ui) throws Exception {
1305 // 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...?
1306 String calledUri = ui.getPath();
1307 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1308 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), ui);
1310 String direction = ui.getQueryParameters().getFirst(Hierarchy.directionQP);
1311 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1312 return Hierarchy.surface(ctx, itemcsid, uri);
1314 return Hierarchy.dive(ctx, itemcsid, uri);
1316 } catch (Exception e) {
1317 throw bigReThrow(e, "Error showing hierarchy", itemcsid);
1321 protected String getItemDocType(String tenantId) {
1322 return getDocType(tenantId, getItemServiceName());
1326 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1327 * for the current resource, for all tenants
1329 * @return a map of URI templates for the current resource, for all tenants
1332 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1333 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1334 super.getUriRegistryEntries();
1335 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1336 for (String tenantId : tenantIds) {
1337 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1339 return uriRegistryEntriesMap;