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;
43 import javax.ws.rs.core.Response.ResponseBuilder;
45 import org.collectionspace.services.client.IClientQueryParams;
46 import org.collectionspace.services.client.IQueryManager;
47 import org.collectionspace.services.client.PoxPayload;
48 import org.collectionspace.services.client.PoxPayloadIn;
49 import org.collectionspace.services.client.PoxPayloadOut;
50 import org.collectionspace.services.client.XmlTools;
51 import org.collectionspace.services.client.workflow.WorkflowClient;
52 import org.collectionspace.services.common.CSWebApplicationException;
53 import org.collectionspace.services.common.NuxeoBasedResource;
54 import org.collectionspace.services.common.ResourceMap;
55 import org.collectionspace.services.common.ServiceMain;
56 import org.collectionspace.services.common.ServiceMessages;
57 import org.collectionspace.services.common.StoredValuesUriTemplate;
58 import org.collectionspace.services.common.UriInfoWrapper;
59 import org.collectionspace.services.common.UriTemplateFactory;
60 import org.collectionspace.services.common.UriTemplateRegistry;
61 import org.collectionspace.services.common.UriTemplateRegistryKey;
62 import org.collectionspace.services.common.api.RefName;
63 import org.collectionspace.services.common.api.Tools;
64 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
65 import org.collectionspace.services.common.authorityref.AuthorityRefList;
66 import org.collectionspace.services.common.context.JaxRsContext;
67 import org.collectionspace.services.common.context.MultipartServiceContext;
68 import org.collectionspace.services.common.context.RemoteServiceContext;
69 import org.collectionspace.services.common.context.ServiceBindingUtils;
70 import org.collectionspace.services.common.context.ServiceContext;
71 import org.collectionspace.services.common.document.DocumentException;
72 import org.collectionspace.services.common.document.DocumentFilter;
73 import org.collectionspace.services.common.document.DocumentHandler;
74 import org.collectionspace.services.common.document.DocumentNotFoundException;
75 import org.collectionspace.services.common.document.DocumentReferenceException;
76 import org.collectionspace.services.common.document.DocumentWrapper;
77 import org.collectionspace.services.common.document.Hierarchy;
78 import org.collectionspace.services.common.query.QueryManager;
79 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
80 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
81 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
82 import org.collectionspace.services.config.ClientType;
83 import org.collectionspace.services.config.service.ServiceBindingType;
84 import org.collectionspace.services.jaxb.AbstractCommonList;
85 import org.collectionspace.services.lifecycle.TransitionDef;
86 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
87 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
88 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
89 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
90 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
91 import org.collectionspace.services.workflow.WorkflowCommon;
92 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
93 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
94 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
95 import org.collectionspace.services.description.ServiceDescription;
96 import org.jboss.resteasy.util.HttpResponseCodes;
97 import org.nuxeo.ecm.core.api.DocumentModel;
98 import org.nuxeo.ecm.core.api.DocumentModelList;
99 import org.slf4j.Logger;
100 import org.slf4j.LoggerFactory;
103 * The Class AuthorityResource.
106 @SuppressWarnings({"rawtypes", "unchecked"})
107 @Consumes("application/xml")
108 @Produces("application/xml")
109 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
110 extends NuxeoBasedResource {
112 final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
114 final static String SEARCH_TYPE_TERMSTATUS = "ts";
115 public final static String hierarchy = "hierarchy";
117 protected Class<AuthCommon> authCommonClass;
118 protected Class<?> resourceClass;
119 protected String authorityCommonSchemaName;
120 protected String authorityItemCommonSchemaName;
121 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed? I see no references to it.
123 final static String FETCH_SHORT_ID = "_fetch_";
124 public final static String PARENT_WILDCARD = "_ALL_";
125 protected static final boolean DONT_INCLUDE_ITEMS = false;
126 protected static final boolean INCLUDE_ITEMS = true;
129 * Instantiates a new Authority resource.
131 public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
132 String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
133 this.authCommonClass = authCommonClass;
134 this.resourceClass = resourceClass;
135 this.authorityCommonSchemaName = authorityCommonSchemaName;
136 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
139 public abstract String getItemServiceName();
141 public abstract String getItemTermInfoGroupXPathBase();
144 protected String getVersionString() {
145 return "$LastChangedRevision: 2617 $";
149 public Class<AuthCommon> getCommonPartClass() {
150 return authCommonClass;
154 * Creates the item document handler.
157 * @param inAuthority the in vocabulary
159 * @return the document handler
161 * @throws Exception the exception
163 protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
164 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
165 String inAuthority, String containerShortIdentifier)
167 String authorityRefNameBase;
168 AuthorityItemDocumentModelHandler<?> docHandler;
170 if (containerShortIdentifier == null) {
171 authorityRefNameBase = null;
173 ServiceContext<PoxPayloadIn, PoxPayloadOut> containerCtx = createServiceContext(getServiceName());
174 if (containerShortIdentifier.equals(FETCH_SHORT_ID)) { // We need to fetch this from the repo
175 if (ctx.getCurrentRepositorySession() != null) {
176 containerCtx.setCurrentRepositorySession(ctx.getCurrentRepositorySession()); // We need to use the current repo session if one exists
178 // Get from parent document
179 containerShortIdentifier = getAuthShortIdentifier(containerCtx, inAuthority);
181 authorityRefNameBase = buildAuthorityRefNameBase(containerCtx, containerShortIdentifier);
184 docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
185 ctx.getCommonPartLabel(getItemServiceName()),
187 // FIXME - Richard and Aron think the following three lines should
188 // be in the constructor for the AuthorityItemDocumentModelHandler
189 // because all three are required fields.
190 docHandler.setInAuthority(inAuthority);
191 docHandler.setAuthorityRefNameBase(authorityRefNameBase);
192 docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
196 public String getAuthShortIdentifier(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
197 throws DocumentNotFoundException, DocumentException {
198 String shortIdentifier = null;
201 AuthorityDocumentModelHandler<?> handler = (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
202 shortIdentifier = handler.getShortIdentifier(ctx, authCSID, authorityCommonSchemaName);
203 } catch (Exception e) {
204 if (logger.isDebugEnabled()) {
205 logger.debug("Caught exception ", e);
207 throw new DocumentException(e);
210 return shortIdentifier;
213 protected String buildAuthorityRefNameBase(
214 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
215 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
216 ctx.getServiceName(),
217 null, // Only use shortId form!!!
218 shortIdentifier, null);
219 return authority.toString();
222 public static class CsidAndShortIdentifier {
224 String shortIdentifier;
227 protected String lookupParentCSID(String parentspecifier, String method,
228 String op, UriInfo uriInfo) throws Exception {
229 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(NULL_CONTEXT,
230 parentspecifier, method, op, uriInfo);
231 return tempResult.CSID;
234 protected String lookupParentCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentspecifier, String method,
235 String op, UriInfo uriInfo) throws Exception {
236 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(ctx,
237 parentspecifier, method, op, uriInfo);
238 return tempResult.CSID;
242 private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
243 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx, // Ok to be null
244 String parentIdentifier,
249 CsidAndShortIdentifier result = new CsidAndShortIdentifier();
250 Specifier parentSpec = Specifier.getSpecifier(parentIdentifier, method, op);
253 String parentShortIdentifier;
254 if (parentSpec.form == SpecifierForm.CSID) {
255 parentShortIdentifier = null;
256 parentcsid = parentSpec.value;
257 // Uncomment when app layer is ready to integrate
258 // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
259 parentShortIdentifier = FETCH_SHORT_ID;
261 parentShortIdentifier = parentSpec.value;
262 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentShortIdentifier);
263 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
264 CoreSessionInterface repoSession = null;
265 if (existingCtx != null) {
266 repoSession = (CoreSessionInterface) existingCtx.getCurrentRepositorySession(); // We want to use the thread's current repo session
268 parentcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
271 result.CSID = parentcsid;
272 result.shortIdentifier = parentShortIdentifier;
277 public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext, String itemspecifier, String parentcsid, String method, String op)
281 Specifier itemSpec = Specifier.getSpecifier(itemspecifier, method, op);
282 if (itemSpec.form == SpecifierForm.CSID) {
283 itemcsid = itemSpec.value;
285 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
286 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(getItemServiceName());
287 CoreSessionInterface repoSession = null;
288 if (existingContext != null) {
289 repoSession = (CoreSessionInterface) existingContext.getCurrentRepositorySession(); // We want to use the thread's current repo session
291 itemcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
298 * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
299 * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
300 * Resource. They then call this method on that resource.
303 public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
304 throws Exception, DocumentNotFoundException {
308 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
309 // Ensure we have the right context.
310 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
312 // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
313 NuxeoRepositoryClientImpl client = (NuxeoRepositoryClientImpl)getRepositoryClient(ctx);
314 String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
316 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
317 ctx = createServiceContext(getItemServiceName());
318 DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
319 DocumentModel docModel = docWrapper.getWrappedObject();
325 public Response createAuthority(
326 @Context ResourceMap resourceMap,
327 @Context UriInfo uriInfo,
330 // 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
331 // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
332 // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
333 // the code that creates new authorities. The authority document model handler will first check for authorities with the same short id before
334 // trying to create a new authority.
336 synchronized(AuthorityResource.class) {
338 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
339 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
340 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
342 String csid = getRepositoryClient(ctx).create(ctx, handler);
343 UriBuilder path = UriBuilder.fromResource(resourceClass);
344 path.path("" + csid);
345 Response response = Response.created(path.build()).build();
347 } catch (Exception e) {
348 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
353 protected boolean supportsReplicating(String tenantId, String serviceName) {
354 boolean result = false;
356 ServiceBindingType sb = getTenantBindingsReader().getServiceBinding(tenantId, getServiceName());
357 result = sb.isSupportsReplicating();
363 * Synchronizes the authority and its items/terms with a Shared Authority Server.
365 * @param specifier either a CSID or one of the urn forms
367 * @return the authority
371 public byte[] synchronize(
372 @Context Request request,
373 @Context UriInfo uriInfo,
374 @PathParam("csid") String identifier) {
375 uriInfo = new UriInfoWrapper(uriInfo);
377 boolean neededSync = false;
378 PoxPayloadOut payloadOut = null;
382 // Prevent multiple SAS synchronizations from occurring simultaneously by synchronizing this method.
384 synchronized(AuthorityResource.class) {
386 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
388 * Make sure this authority service supports synchronization
390 if (supportsReplicating(ctx.getTenantId(), ctx.getServiceName()) == false) {
391 throw new DocumentException(Response.Status.FORBIDDEN.getStatusCode());
393 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
394 specifier = Specifier.getSpecifier(identifier, "getAuthority", "GET");
395 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
396 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
397 payloadOut = ctx.getOutput();
398 } catch (Exception e) {
399 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, identifier);
403 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
405 if (neededSync == true) {
406 result = payloadOut.getBytes();
408 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
409 specifier.value).getBytes();
410 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
411 throw new CSWebApplicationException(response);
419 * Builds a cached JAX-RS response.
421 protected Response buildResponse(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, PoxPayloadOut payloadOut) {
422 Response result = null;
424 ResponseBuilder responseBuilder = Response.ok(payloadOut.getBytes());
425 this.setCacheControl(ctx, responseBuilder);
426 result = responseBuilder.build();
432 * Gets the authority.
434 * @param specifier either a CSID or one of the urn forms
436 * @return the authority
442 @Context Request request,
443 @Context UriInfo uriInfo,
444 @PathParam("csid") String specifier) {
445 Response result = null;
446 uriInfo = new UriInfoWrapper(uriInfo);
449 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(request, uriInfo);
450 PoxPayloadOut payloadout = getAuthority(ctx, request, uriInfo, specifier, DONT_INCLUDE_ITEMS);
451 result = buildResponse(ctx, payloadout);
452 } catch (Exception e) {
453 throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
456 if (result == null) {
457 Response response = Response.status(Response.Status.NOT_FOUND).entity(
458 "GET request failed. The requested Authority specifier:" + specifier + ": was not found.").type(
459 "text/plain").build();
460 throw new CSWebApplicationException(response);
466 protected PoxPayloadOut getAuthority(
467 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
471 boolean includeItems) throws Exception {
472 uriInfo = new UriInfoWrapper(uriInfo);
473 PoxPayloadOut payloadout = null;
475 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> docHandler = createDocumentHandler(ctx);
476 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
477 if (spec.form == SpecifierForm.CSID) {
478 if (logger.isDebugEnabled()) {
479 logger.debug("getAuthority with csid=" + spec.value);
481 getRepositoryClient(ctx).get(ctx, spec.value, docHandler);
483 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
484 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
485 docHandler.setDocumentFilter(myFilter);
486 getRepositoryClient(ctx).get(ctx, docHandler);
489 payloadout = ctx.getOutput();
490 if (includeItems == true) {
491 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
492 payloadout.addPart(PoxPayload.ABSTRACT_COMMON_LIST_ROOT_ELEMENT_LABEL, itemsList);
499 * Finds and populates the authority list.
503 * @return the authority list
506 @Produces("application/xml")
507 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.
508 uriInfo = new UriInfoWrapper(uriInfo);
509 AbstractCommonList result = null;
512 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
513 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
515 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
516 DocumentFilter myFilter = handler.getDocumentFilter();
517 // Need to make the default sort order for authority items
518 // be on the displayName field
519 String sortBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
520 if (sortBy == null || sortBy.isEmpty()) {
521 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
522 + AuthorityItemJAXBSchema.DISPLAY_NAME;
523 myFilter.setOrderByClause(qualifiedDisplayNameField);
525 String nameQ = queryParams.getFirst("refName");
527 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
529 getRepositoryClient(ctx).getFiltered(ctx, handler);
530 result = handler.getCommonPartList();
531 } catch (Exception e) {
532 throw bigReThrow(e, ServiceMessages.GET_FAILED);
539 * Overriding this methods to see if we should update the revision number during the update. We don't
540 * want to update the rev number of synchronization operations.
543 protected PoxPayloadOut update(String csid,
544 PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
545 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
547 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
548 Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
549 if (shouldUpdateRev != null) {
550 handler.setShouldUpdateRevNumber(shouldUpdateRev);
552 getRepositoryClient(ctx).update(ctx, csid, handler);
553 return ctx.getOutput();
559 * @param specifier the csid or id
561 * @return the multipart output
565 public byte[] updateAuthority(
566 @PathParam("csid") String specifier,
568 PoxPayloadOut result = null;
570 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
571 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
572 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
573 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
575 if (spec.form == SpecifierForm.CSID) {
578 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
579 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
581 getRepositoryClient(ctx).update(ctx, csid, handler);
582 result = ctx.getOutput();
583 } catch (Exception e) {
584 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
586 return result.getBytes();
592 * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
594 * @return the response
598 public Response deleteAuthority( // # Delete this authority and all of it's items.
599 @Context Request request,
600 @Context UriInfo uriInfo,
601 @PathParam("csid") String specifier) {
602 uriInfo = new UriInfoWrapper(uriInfo);
604 if (logger.isDebugEnabled()) {
605 logger.debug("deleteAuthority with specifier=" + specifier);
609 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
610 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
612 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
613 if (spec.form == SpecifierForm.CSID) {
614 if (logger.isDebugEnabled()) {
615 logger.debug("deleteAuthority with csid=" + spec.value);
617 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
618 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
620 if (logger.isDebugEnabled()) {
621 logger.debug("deleteAuthority with specifier=" + spec.value);
623 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
624 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
627 return Response.status(HttpResponseCodes.SC_OK).build();
628 } catch (Exception e) {
629 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
636 * @param parentspecifier - ID of the container. Can be URN or CSID form
637 * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
638 * @param isProposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
642 protected Response createAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentIdentifier,
643 boolean shouldUpdateRevNumber,
645 boolean isSasItem) throws Exception {
646 Response result = null;
648 // Note: must have the parentShortId, to do the create.
649 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
650 AuthorityItemDocumentModelHandler handler =
651 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
652 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
653 handler.setIsProposed(isProposed);
654 handler.setIsSASItem(isSasItem);
655 // Make the client call
656 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
658 // Build the JAX-RS response
659 UriBuilder path = UriBuilder.fromResource(resourceClass);
660 path.path(parent.CSID + "/items/" + itemcsid);
661 result = Response.created(path.build()).build();
667 * Called with an existing context.
669 * @param parentIdentifier
674 public Response createAuthorityItemWithParentContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
675 String parentIdentifier,
677 boolean shouldUpdateRevNumber,
679 boolean isSASItem) throws Exception {
680 Response result = null;
682 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
683 parentCtx.getResourceMap(), parentCtx.getUriInfo());
684 if (parentCtx.getCurrentRepositorySession() != null) {
685 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
687 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem);
692 /*************************************************************************
693 * Create an AuthorityItem - this is a sub-resource of Authority
694 * @param specifier either a CSID or one of the urn forms
695 * @return Authority item response
696 *************************************************************************/
698 @Path("{csid}/items")
699 public Response createAuthorityItem(
700 @Context ResourceMap resourceMap,
701 @Context UriInfo uriInfo,
702 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
704 uriInfo = new UriInfoWrapper(uriInfo);
705 Response result = null;
708 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
709 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
710 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
711 AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM);
712 } catch (Exception e) {
713 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
720 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
721 public byte[] getItemWorkflow(
722 @PathParam("csid") String csid,
723 @PathParam("itemcsid") String itemcsid) {
724 PoxPayloadOut result = null;
727 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
728 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
730 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
731 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
732 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
733 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
734 result = ctx.getOutput();
735 } catch (Exception e) {
736 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
738 return result.getBytes();
741 //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
742 // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
744 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
745 public byte[] updateItemWorkflowWithTransition(
746 @Context UriInfo uriInfo,
747 @PathParam("csid") String parentIdentifier,
748 @PathParam("itemcsid") String itemIdentifier,
749 @PathParam("transition") String transition) {
750 uriInfo = new UriInfoWrapper(uriInfo);
751 PoxPayloadOut result = null;
754 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
755 result = updateItemWorkflowWithTransition(ctx,
756 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
757 } catch (Exception e) {
758 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
761 return result.getBytes();
765 * Update an authority item's workflow state.
766 * @param existingContext
771 * @throws DocumentReferenceException
773 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
774 String parentIdentifier,
775 String itemIdentifier,
777 boolean updateRevNumber) throws DocumentReferenceException {
778 PoxPayloadOut result = null;
782 // We need CSIDs for both the parent authority and the authority item
784 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
785 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
788 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
790 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
791 WorkflowClient.SERVICE_COMMONPART_NAME);
792 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
793 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
794 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
797 // Create a service context and document handler for the target resource -not the workflow resource itself.
799 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
800 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
801 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
802 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
804 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
806 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
807 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
809 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
810 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
811 if (transitionDef == null) {
812 throw new DocumentException(String.format("The document with ID='%s' does not support the workflow transition '%s'.",
813 itemIdentifier, transition));
815 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
817 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
818 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
819 result = ctx.getOutput();
820 } catch (DocumentReferenceException de) {
822 } catch (Exception e) {
823 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
829 private PoxPayloadOut getAuthorityItem(
830 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
831 String parentIdentifier,
832 String itemIdentifier) throws Exception {
833 PoxPayloadOut result = null;
835 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
836 // We omit the parentShortId, only needed when doing a create...
837 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
839 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
840 if (itemSpec.form == SpecifierForm.CSID) {
841 // TODO should we assert that the item is in the passed vocab?
842 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
844 String itemWhereClause =
845 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
846 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
847 handler.setDocumentFilter(myFilter);
848 getRepositoryClient(ctx).get(ctx, handler);
851 result = (PoxPayloadOut) ctx.getOutput();
852 if (result != null) {
853 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
854 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
855 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
856 itemSpec.value, inAuthority, parentcsid));
863 public PoxPayloadOut getAuthorityItemWithExistingContext(
864 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
865 String parentIdentifier,
866 String itemIdentifier) throws Exception {
867 PoxPayloadOut result = null;
869 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
870 if (existingCtx.getCurrentRepositorySession() != null) {
871 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
872 ctx.setProperties(existingCtx.getProperties());
874 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
880 * Gets the authority item.
882 * @param parentspecifier either a CSID or one of the urn forms
883 * @param itemspecifier either a CSID or one of the urn forms
885 * @return the authority item
888 @Path("{csid}/items/{itemcsid}")
889 public byte[] getAuthorityItem(
890 @Context Request request,
891 @Context UriInfo uriInfo,
892 @Context ResourceMap resourceMap,
893 @PathParam("csid") String parentIdentifier,
894 @PathParam("itemcsid") String itemIdentifier) {
895 uriInfo = new UriInfoWrapper(uriInfo);
896 PoxPayloadOut result = null;
898 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
899 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
901 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
902 ctx.setJaxRsContext(jaxRsContext);
904 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
905 } catch (DocumentNotFoundException dnf) {
906 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
907 } catch (Exception e) {
908 throw bigReThrow(e, ServiceMessages.GET_FAILED);
911 return result.getBytes();
915 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
916 * different enough that it will have to override this method in it's resource class.
919 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
920 String result = null;
922 result = NuxeoUtils.getPrimaryElPathPropertyName(
923 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
924 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
930 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
931 String result = null;
933 result = NuxeoUtils.getMultiElPathPropertyName(
934 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
935 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
941 * Gets the authorityItem list for the specified authority
942 * If partialPerm is specified, keywords will be ignored.
944 * @param authorityIdentifier either a CSID or one of the urn forms
945 * @param partialTerm if non-null, matches partial terms
946 * @param keywords if non-null, matches terms in the keyword index for items
947 * @param ui passed to include additional parameters, like pagination controls
950 public AbstractCommonList getAuthorityItemList(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
951 String authorityIdentifier,
952 UriInfo uriInfo) throws Exception {
953 AbstractCommonList result = null;
955 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
956 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
957 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
958 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
959 ctx.setProperties(existingContext.getProperties());
962 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
963 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
964 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
965 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
966 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
968 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
969 // We omit the parentShortId, only needed when doing a create...
970 String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null :
971 lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo);
972 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
973 createItemDocumentHandler(ctx, parentcsid, null);
975 DocumentFilter myFilter = handler.getDocumentFilter();
976 // If we are not wildcarding the parent, add a restriction
977 if (parentcsid != null) {
978 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
979 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
980 + "'" + parentcsid + "'",
981 IQueryManager.SEARCH_QUALIFIER_AND);
984 if (Tools.notBlank(termStatus)) {
985 // Start with the qualified termStatus field
986 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
987 + AuthorityItemJAXBSchema.TERM_STATUS;
988 String[] filterTerms = termStatus.trim().split("\\|");
989 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
990 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
993 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
999 * Gets the authorityItem list for the specified authority
1000 * If partialPerm is specified, keywords will be ignored.
1002 * @param authorityIdentifier either a CSID or one of the urn forms
1003 * @param partialTerm if non-null, matches partial terms
1004 * @param keywords if non-null, matches terms in the keyword index for items
1005 * @param ui passed to include additional parameters, like pagination controls
1007 * @return the authorityItem list
1010 @Path("{csid}/items")
1011 @Produces("application/xml")
1012 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier,
1013 @Context UriInfo uriInfo) {
1014 uriInfo = new UriInfoWrapper(uriInfo);
1015 AbstractCommonList result = null;
1018 result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo);
1019 } catch (Exception e) {
1020 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
1027 * @return the name of the property used to specify references for items in this type of
1028 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
1029 * Some types (like Vocabulary) use a separate property.
1031 protected String getRefPropName() {
1032 return ServiceBindingUtils.AUTH_REF_PROP;
1036 * Gets the entities referencing this Authority item instance. The service type
1037 * can be passed as a query param "type", and must match a configured type
1038 * for the service bindings. If not set, the type defaults to
1039 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
1041 * @param parentspecifier either a CSID or one of the urn forms
1042 * @param itemspecifier either a CSID or one of the urn forms
1045 * @return the info for the referencing objects
1048 @Path("{csid}/items/{itemcsid}/refObjs")
1049 @Produces("application/xml")
1050 public AuthorityRefDocList getReferencingObjects(
1051 @PathParam("csid") String parentSpecifier,
1052 @PathParam("itemcsid") String itemSpecifier,
1053 @Context UriTemplateRegistry uriTemplateRegistry,
1054 @Context UriInfo uriInfo) {
1055 uriInfo = new UriInfoWrapper(uriInfo);
1056 AuthorityRefDocList authRefDocList = null;
1058 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
1059 } catch (Exception e) {
1060 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1063 if (authRefDocList == null) {
1064 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1065 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1066 "text/plain").build();
1067 throw new CSWebApplicationException(response);
1069 return authRefDocList;
1072 public AuthorityRefDocList getReferencingObjects(
1073 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1074 String parentspecifier,
1075 String itemspecifier,
1076 UriTemplateRegistry uriTemplateRegistry,
1077 UriInfo uriInfo) throws Exception {
1078 //uriInfo = new UriInfoWrapper(uriInfo);
1079 AuthorityRefDocList authRefDocList = null;
1081 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1082 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1084 // Merge parts of existing context with our new context
1086 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1087 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1088 ctx.setProperties(existingContext.getProperties());
1091 String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1092 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1094 // Remove the "type" property from the query params
1095 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1096 if (serviceTypes == null || serviceTypes.isEmpty()) {
1097 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1100 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1101 authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1103 return authRefDocList;
1107 * Gets the authority terms used in the indicated Authority item.
1109 * @param parentspecifier either a CSID or one of the urn forms
1110 * @param itemspecifier either a CSID or one of the urn forms
1111 * @param ui passed to include additional parameters, like pagination controls
1113 * @return the authority refs for the Authority item.
1116 @Path("{csid}/items/{itemcsid}/authorityrefs")
1117 @Produces("application/xml")
1118 public AuthorityRefList getAuthorityItemAuthorityRefs(
1119 @PathParam("csid") String parentspecifier,
1120 @PathParam("itemcsid") String itemspecifier,
1121 @Context UriInfo uriInfo) {
1122 uriInfo = new UriInfoWrapper(uriInfo);
1123 AuthorityRefList authRefList = null;
1126 // Note that we have to create the service context for the Items, not the main service
1127 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1128 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1129 // We omit the parentShortId, only needed when doing a create...
1130 DocumentModelHandler<?, AbstractCommonList> handler =
1131 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1133 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1135 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1136 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1137 } catch (Exception e) {
1138 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1145 * Synchronizes a local authority item with a share authority server (SAS) item.
1147 * @param parentIdentifier
1148 * @param itemIdentifier
1152 private PoxPayloadOut synchronizeItem(
1153 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1154 String parentIdentifier,
1155 String itemIdentifier,
1156 boolean syncHierarchicalRelationships) throws Exception {
1157 PoxPayloadOut result = null;
1158 AuthorityItemSpecifier specifier;
1159 boolean neededSync = false;
1161 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1162 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1163 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1164 handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1165 handler.setShouldSyncHierarchicalRelationships(syncHierarchicalRelationships);
1166 // Create an authority item specifier
1167 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1168 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1169 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1171 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1172 if (neededSync == true) {
1173 result = (PoxPayloadOut) ctx.getOutput();
1180 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1181 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1182 * local authority. The parent context was created for the authority (parent) because the sync started there.
1183 * @param existingCtx
1184 * @param parentIdentifier
1185 * @param itemIdentifier
1189 public PoxPayloadOut synchronizeItemWithExistingContext(
1190 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1191 String parentIdentifier,
1192 String itemIdentifier,
1193 boolean syncHierarchicalRelationships
1194 ) throws Exception {
1195 PoxPayloadOut result = null;
1197 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1198 existingCtx.getResourceMap(),
1199 existingCtx.getUriInfo());
1200 if (existingCtx.getCurrentRepositorySession() != null) {
1201 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1204 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
1210 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1212 * @param specifier either CSIDs and/or one of the urn forms
1214 * @return the authority item if it was updated/synchronized with SAS item; otherwise empty
1217 @Path("{csid}/items/{itemcsid}/sync")
1218 public byte[] synchronizeItem(
1219 @Context ResourceMap resourceMap,
1220 @Context UriInfo uriInfo,
1221 @PathParam("csid") String parentIdentifier,
1222 @PathParam("itemcsid") String itemIdentifier) {
1223 uriInfo = new UriInfoWrapper(uriInfo);
1225 boolean neededSync = false;
1226 PoxPayloadOut payloadOut = null;
1229 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1230 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier, true);
1231 if (payloadOut != null) {
1234 } catch (Exception e) {
1235 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1239 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1241 if (neededSync == true) {
1242 result = payloadOut.getBytes();
1244 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1245 itemIdentifier).getBytes();
1246 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1247 throw new CSWebApplicationException(response);
1254 * Update authorityItem.
1256 * @param parentspecifier either a CSID or one of the urn forms
1257 * @param itemspecifier either a CSID or one of the urn forms
1259 * @return the multipart output
1262 @Path("{csid}/items/{itemcsid}")
1263 public byte[] updateAuthorityItem(
1264 @Context ResourceMap resourceMap,
1265 @Context UriInfo uriInfo,
1266 @PathParam("csid") String parentSpecifier,
1267 @PathParam("itemcsid") String itemSpecifier,
1268 String xmlPayload) {
1269 uriInfo = new UriInfoWrapper(uriInfo);
1270 PoxPayloadOut result = null;
1273 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1274 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1275 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1276 AuthorityServiceUtils.NO_CHANGE, // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1277 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1278 } catch (Exception e) {
1279 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1282 return result.getBytes();
1285 public PoxPayloadOut updateAuthorityItem(
1286 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
1287 ResourceMap resourceMap,
1289 String parentspecifier,
1290 String itemspecifier,
1291 PoxPayloadIn theUpdate,
1292 boolean shouldUpdateRevNumber,
1295 ) throws Exception {
1296 PoxPayloadOut result = null;
1298 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
1299 String parentcsid = csidAndShortId.CSID;
1300 String parentShortId = csidAndShortId.shortIdentifier;
1302 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
1304 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
1306 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
1308 ctx.setInput(theUpdate); // the update payload
1311 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
1313 // We omit the parentShortId, only needed when doing a create...
1314 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
1315 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1316 if (isProposed != null) {
1317 handler.setIsProposed(isProposed);
1319 if (isSASItem != null) {
1320 handler.setIsSASItem(isSASItem);
1322 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
1323 result = ctx.getOutput();
1329 * Delete authorityItem.
1331 * @param parentIdentifier the parentcsid
1332 * @param itemIdentifier the itemcsid
1334 * @return the response
1337 @Path("{csid}/items/{itemcsid}")
1338 public Response deleteAuthorityItem(
1339 @Context UriInfo uriInfo,
1340 @PathParam("csid") String parentIdentifier,
1341 @PathParam("itemcsid") String itemIdentifier) {
1342 uriInfo = new UriInfoWrapper(uriInfo);
1343 Response result = null;
1345 ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1346 ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1347 if (logger.isDebugEnabled()) {
1348 logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1352 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1353 deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1354 result = Response.status(HttpResponseCodes.SC_OK).build();
1355 } catch (Exception e) {
1356 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1364 * @param existingCtx
1365 * @param parentIdentifier
1366 * @param itemIdentifier
1369 public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1370 String parentIdentifier,
1371 String itemIdentifier,
1372 boolean shouldUpdateRevNumber
1373 ) throws Exception {
1374 boolean result = true;
1376 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1377 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1378 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1379 ctx.setProperties(existingCtx.getProperties());
1382 String parentcsid = null;
1384 parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1385 } catch (DocumentNotFoundException de) {
1386 logger.warn(String.format("Could not find parent with ID='%s' when trying to delete item ID='%s'",
1387 parentIdentifier, itemIdentifier));
1389 String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1391 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
1392 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1393 result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1399 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1400 @Produces("application/xml")
1401 public String getHierarchy(
1402 @PathParam("csid") String parentIdentifier,
1403 @PathParam("itemcsid") String itemIdentifier,
1404 @Context UriInfo uriInfo) throws Exception {
1405 uriInfo = new UriInfoWrapper(uriInfo);
1406 String result = null;
1410 // 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...?
1412 String calledUri = uriInfo.getPath();
1413 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1414 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1416 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1417 String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1419 String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1420 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1421 result = Hierarchy.surface(ctx, itemcsid, uri);
1423 result = Hierarchy.dive(ctx, itemcsid, uri);
1425 } catch (Exception e) {
1426 throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1437 public String getItemDocType(String tenantId) {
1438 return getDocType(tenantId, getItemServiceName());
1442 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1443 * for the current resource, for all tenants
1445 * @return a map of URI templates for the current resource, for all tenants
1448 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1449 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1450 super.getUriRegistryEntries();
1451 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1452 for (String tenantId : tenantIds) {
1453 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1455 return uriRegistryEntriesMap;
1462 public ServiceDescription getDescription(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1463 ServiceDescription result = super.getDescription(ctx);
1464 result.setSubresourceDocumentType(this.getItemDocType(ctx.getTenantId()));
1468 public Response createAuthority(String xmlPayload) {
1469 return this.createAuthority(null, null, xmlPayload);