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;
53 import org.collectionspace.services.common.CSWebApplicationException;
54 import org.collectionspace.services.common.NuxeoBasedResource;
55 import org.collectionspace.services.common.ResourceMap;
56 import org.collectionspace.services.common.ServiceMain;
57 import org.collectionspace.services.common.ServiceMessages;
58 import org.collectionspace.services.common.StoredValuesUriTemplate;
59 import org.collectionspace.services.common.UriInfoWrapper;
60 import org.collectionspace.services.common.UriTemplateFactory;
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.repository.RepositoryClient;
80 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
81 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
82 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
83 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
84 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
86 import org.collectionspace.services.config.ClientType;
87 import org.collectionspace.services.config.service.ServiceBindingType;
88 import org.collectionspace.services.jaxb.AbstractCommonList;
89 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
90 import org.collectionspace.services.lifecycle.TransitionDef;
91 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
92 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
93 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
94 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
95 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
96 import org.collectionspace.services.workflow.WorkflowCommon;
97 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
98 import org.collectionspace.services.description.ServiceDescription;
100 import org.jboss.resteasy.util.HttpResponseCodes;
101 import org.nuxeo.ecm.core.api.DocumentModel;
102 import org.nuxeo.ecm.core.api.DocumentModelList;
103 import org.slf4j.Logger;
104 import org.slf4j.LoggerFactory;
105 import org.w3c.dom.Element;
108 * The Class AuthorityResource.
111 @SuppressWarnings({"rawtypes", "unchecked"})
112 @Consumes("application/xml")
113 @Produces("application/xml")
114 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
115 extends NuxeoBasedResource {
117 final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
119 final static String SEARCH_TYPE_TERMSTATUS = "ts";
120 public final static String hierarchy = "hierarchy";
122 private static final Integer PAGE_NUM_FROM_QUERYPARAMS = null;
123 private static final Integer PAGE_SIZE_FROM_QUERYPARAMS = null;
125 protected Class<AuthCommon> authCommonClass;
126 protected Class<?> resourceClass;
127 protected String authorityCommonSchemaName;
128 protected String authorityItemCommonSchemaName;
129 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed? I see no references to it.
131 final static String FETCH_SHORT_ID = "_fetch_";
132 public final static String PARENT_WILDCARD = "_ALL_";
133 protected static final boolean DONT_INCLUDE_ITEMS = false;
134 protected static final boolean INCLUDE_ITEMS = true;
137 * Instantiates a new Authority resource.
139 public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
140 String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
141 this.authCommonClass = authCommonClass;
142 this.resourceClass = resourceClass;
143 this.authorityCommonSchemaName = authorityCommonSchemaName;
144 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
147 public abstract String getItemServiceName();
149 public abstract String getItemTermInfoGroupXPathBase();
152 protected String getVersionString() {
153 return "$LastChangedRevision: 2617 $";
157 public Class<AuthCommon> getCommonPartClass() {
158 return authCommonClass;
162 * Creates the item document handler.
165 * @param inAuthority the in vocabulary
167 * @return the document handler
169 * @throws Exception the exception
171 protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
172 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
173 String inAuthority, String containerShortIdentifier)
175 String authorityRefNameBase;
176 AuthorityItemDocumentModelHandler<?> docHandler;
178 if (containerShortIdentifier == null) {
179 authorityRefNameBase = null;
181 ServiceContext<PoxPayloadIn, PoxPayloadOut> containerCtx = createServiceContext(getServiceName());
182 if (containerShortIdentifier.equals(FETCH_SHORT_ID)) { // We need to fetch this from the repo
183 if (ctx.getCurrentRepositorySession() != null) {
184 containerCtx.setCurrentRepositorySession(ctx.getCurrentRepositorySession()); // We need to use the current repo session if one exists
186 // Get from parent document
187 containerShortIdentifier = getAuthShortIdentifier(containerCtx, inAuthority);
189 authorityRefNameBase = buildAuthorityRefNameBase(containerCtx, containerShortIdentifier);
192 docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
193 ctx.getCommonPartLabel(getItemServiceName()),
195 // FIXME - Richard and Aron think the following three lines should
196 // be in the constructor for the AuthorityItemDocumentModelHandler
197 // because all three are required fields.
198 docHandler.setInAuthority(inAuthority);
199 docHandler.setAuthorityRefNameBase(authorityRefNameBase);
200 docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
204 public String getAuthShortIdentifier(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
205 throws DocumentNotFoundException, DocumentException {
206 String shortIdentifier = null;
209 AuthorityDocumentModelHandler<?> handler = (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
210 shortIdentifier = handler.getShortIdentifier(ctx, authCSID, authorityCommonSchemaName);
211 } catch (Exception e) {
212 if (logger.isDebugEnabled()) {
213 logger.debug("Caught exception ", e);
215 throw new DocumentException(e);
218 return shortIdentifier;
221 protected String buildAuthorityRefNameBase(
222 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
223 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
224 ctx.getServiceName(),
225 null, // Only use shortId form!!!
226 shortIdentifier, null);
227 return authority.toString();
230 public static class CsidAndShortIdentifier {
232 String shortIdentifier;
235 protected String lookupParentCSID(String parentspecifier, String method,
236 String op, UriInfo uriInfo) throws Exception {
237 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(NULL_CONTEXT,
238 parentspecifier, method, op, uriInfo);
239 return tempResult.CSID;
242 protected String lookupParentCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentspecifier, String method,
243 String op, UriInfo uriInfo) throws Exception {
244 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(ctx,
245 parentspecifier, method, op, uriInfo);
246 return tempResult.CSID;
250 private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
251 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx, // Ok to be null
252 String parentIdentifier,
257 CsidAndShortIdentifier result = new CsidAndShortIdentifier();
258 Specifier parentSpec = Specifier.getSpecifier(parentIdentifier, method, op);
261 String parentShortIdentifier;
262 if (parentSpec.form == SpecifierForm.CSID) {
263 parentShortIdentifier = null;
264 parentcsid = parentSpec.value;
265 // Uncomment when app layer is ready to integrate
266 // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
267 parentShortIdentifier = FETCH_SHORT_ID;
269 parentShortIdentifier = parentSpec.value;
270 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentShortIdentifier);
271 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
272 CoreSessionInterface repoSession = null;
273 if (existingCtx != null) {
274 repoSession = (CoreSessionInterface) existingCtx.getCurrentRepositorySession(); // We want to use the thread's current repo session
276 parentcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
279 result.CSID = parentcsid;
280 result.shortIdentifier = parentShortIdentifier;
285 public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext, String itemspecifier, String parentcsid, String method, String op)
289 Specifier itemSpec = Specifier.getSpecifier(itemspecifier, method, op);
290 if (itemSpec.form == SpecifierForm.CSID) {
291 itemcsid = itemSpec.value;
293 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
294 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(getItemServiceName());
295 CoreSessionInterface repoSession = null;
296 if (existingContext != null) {
297 repoSession = (CoreSessionInterface) existingContext.getCurrentRepositorySession(); // We want to use the thread's current repo session
299 itemcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
306 * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
307 * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
308 * Resource. They then call this method on that resource.
311 public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
312 throws Exception, DocumentNotFoundException {
316 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
317 // Ensure we have the right context.
318 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
320 // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
321 NuxeoRepositoryClientImpl client = (NuxeoRepositoryClientImpl)getRepositoryClient(ctx);
322 String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
324 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
325 ctx = createServiceContext(getItemServiceName());
326 DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
327 DocumentModel docModel = docWrapper.getWrappedObject();
333 public Response createAuthority(
334 @Context ResourceMap resourceMap,
335 @Context UriInfo uriInfo,
338 // 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
339 // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
340 // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
341 // the code that creates new authorities. The authority document model handler will first check for authorities with the same short id before
342 // trying to create a new authority.
344 synchronized(AuthorityResource.class) {
346 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
347 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
348 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
350 String csid = getRepositoryClient(ctx).create(ctx, handler);
351 UriBuilder path = UriBuilder.fromResource(resourceClass);
352 path.path("" + csid);
353 Response response = Response.created(path.build()).build();
355 } catch (Exception e) {
356 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
361 protected boolean supportsReplicating(String tenantId, String serviceName) {
362 boolean result = false;
364 ServiceBindingType sb = getTenantBindingsReader().getServiceBinding(tenantId, getServiceName());
365 result = sb.isSupportsReplicating();
371 * Synchronizes the authority and its items/terms with a Shared Authority Server.
373 * @param specifier either a CSID or one of the urn forms
375 * @return the authority
379 public byte[] synchronize(
380 @Context Request request,
381 @Context UriInfo uriInfo,
382 @PathParam("csid") String identifier) {
383 uriInfo = new UriInfoWrapper(uriInfo);
385 boolean neededSync = false;
386 PoxPayloadOut payloadOut = null;
390 // Prevent multiple SAS synchronizations from occurring simultaneously by synchronizing this method.
392 synchronized(AuthorityResource.class) {
394 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
396 * Make sure this authority service supports synchronization
398 if (supportsReplicating(ctx.getTenantId(), ctx.getServiceName()) == false) {
399 throw new DocumentException(Response.Status.FORBIDDEN.getStatusCode());
401 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
402 specifier = Specifier.getSpecifier(identifier, "getAuthority", "GET");
403 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
404 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
405 payloadOut = ctx.getOutput();
406 } catch (Exception e) {
407 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, identifier);
411 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
413 if (neededSync == true) {
414 result = payloadOut.getBytes();
416 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
417 specifier.value).getBytes();
418 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
419 throw new CSWebApplicationException(response);
427 * Builds a cached JAX-RS response.
429 protected Response buildResponse(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, PoxPayloadOut payloadOut) {
430 Response result = null;
432 ResponseBuilder responseBuilder = Response.ok(payloadOut.getBytes());
433 this.setCacheControl(ctx, responseBuilder);
434 result = responseBuilder.build();
440 * Gets the authority.
442 * @param specifier either a CSID or one of the urn forms
444 * @return the authority
450 @Context Request request,
451 @Context UriInfo uriInfo,
452 @PathParam("csid") String specifier) {
453 Response result = null;
454 uriInfo = new UriInfoWrapper(uriInfo);
457 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(request, uriInfo);
458 PoxPayloadOut payloadout = getAuthority(ctx, request, uriInfo, specifier, DONT_INCLUDE_ITEMS);
459 result = buildResponse(ctx, payloadout);
460 } catch (Exception e) {
461 throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
464 if (result == null) {
465 Response response = Response.status(Response.Status.NOT_FOUND).entity(
466 "GET request failed. The requested Authority specifier:" + specifier + ": was not found.").type(
467 "text/plain").build();
468 throw new CSWebApplicationException(response);
474 protected PoxPayloadOut getAuthority(
475 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
479 boolean includeItems) throws Exception {
480 uriInfo = new UriInfoWrapper(uriInfo);
481 PoxPayloadOut payloadout = null;
483 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> docHandler = createDocumentHandler(ctx);
484 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
485 if (spec.form == SpecifierForm.CSID) {
486 if (logger.isDebugEnabled()) {
487 logger.debug("getAuthority with csid=" + spec.value);
489 getRepositoryClient(ctx).get(ctx, spec.value, docHandler);
491 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
492 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
493 docHandler.setDocumentFilter(myFilter);
494 getRepositoryClient(ctx).get(ctx, docHandler);
497 payloadout = ctx.getOutput();
498 if (includeItems == true) {
499 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
500 payloadout.addPart(PoxPayload.ABSTRACT_COMMON_LIST_ROOT_ELEMENT_LABEL, itemsList);
507 * Finds and populates the authority list.
511 * @return the authority list
514 @Produces("application/xml")
515 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.
516 uriInfo = new UriInfoWrapper(uriInfo);
517 AbstractCommonList result = null;
520 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
521 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
523 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
524 DocumentFilter myFilter = handler.getDocumentFilter();
525 // Need to make the default sort order for authority items
526 // be on the displayName field
527 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
528 if (orderBy == null || orderBy.isEmpty()) {
529 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
530 + AuthorityItemJAXBSchema.DISPLAY_NAME;
531 myFilter.setOrderByClause(qualifiedDisplayNameField);
533 String nameQ = queryParams.getFirst("refName");
535 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
537 //getRepositoryClient(ctx).getFiltered(ctx, handler); # Something here?
538 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
539 result = search(ctx, handler, uriInfo, orderBy, null, advancedSearch, null);
540 result = handler.getCommonPartList();
541 } catch (Exception e) {
542 throw bigReThrow(e, ServiceMessages.GET_FAILED);
549 * Overriding this methods to see if we should update the revision number during the update. We don't
550 * want to update the rev number of synchronization operations.
553 protected PoxPayloadOut update(String csid,
554 PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
555 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
557 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
558 Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
559 if (shouldUpdateRev != null) {
560 handler.setShouldUpdateRevNumber(shouldUpdateRev);
562 getRepositoryClient(ctx).update(ctx, csid, handler);
563 return ctx.getOutput();
569 * @param specifier the csid or id
571 * @return the multipart output
575 public byte[] updateAuthority(
576 @Context Request request,
577 @Context ResourceMap resourceMap,
578 @Context UriInfo uriInfo,
579 @PathParam("csid") String specifier,
581 PoxPayloadOut result = null;
583 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
584 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
585 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
586 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
587 String csid = getCsid(ctx, spec);
588 getRepositoryClient(ctx).update(ctx, csid, handler);
589 result = ctx.getOutput();
590 } catch (Exception e) {
591 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
593 return result.getBytes();
597 * Delete all the items in an authority list.
604 @Path("{csid}/items")
605 public Response deleteAuthorityItemList(@PathParam("csid") String specifier,
606 @Context UriInfo uriInfo) {
607 uriInfo = new UriInfoWrapper(uriInfo);
610 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
611 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
613 CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
615 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
617 // Delete all the items one by one
619 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
620 for (ListItem item : itemsList.getListItem()) {
621 deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
623 } catch (Throwable t) {
624 repoSession.setTransactionRollbackOnly();
627 repoClient.releaseRepositorySession(ctx, repoSession);
630 return Response.status(HttpResponseCodes.SC_OK).build();
631 } catch (Exception e) {
632 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
639 * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
641 * @return the response
645 public Response deleteAuthority( // # Delete this authority and all of it's items.
646 @Context Request request,
647 @Context UriInfo uriInfo,
648 @PathParam("csid") String specifier) {
649 uriInfo = new UriInfoWrapper(uriInfo);
651 if (logger.isDebugEnabled()) {
652 logger.debug("deleteAuthority with specifier=" + specifier);
656 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
657 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
658 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
660 CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
662 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
664 // First try to delete all the items
666 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
667 for (ListItem item : itemsList.getListItem()) {
668 deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
672 // Lastly, delete the parent/container
674 if (spec.form == SpecifierForm.CSID) {
675 if (logger.isDebugEnabled()) {
676 logger.debug("deleteAuthority with csid=" + spec.value);
678 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
679 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
681 if (logger.isDebugEnabled()) {
682 logger.debug("deleteAuthority with specifier=" + spec.value);
684 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
685 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
687 } catch (Throwable t) {
688 repoSession.setTransactionRollbackOnly();
691 repoClient.releaseRepositorySession(ctx, repoSession);
694 return Response.status(HttpResponseCodes.SC_OK).build();
695 } catch (Exception e) {
696 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
700 protected String getCsid(ListItem item) {
701 String result = null;
703 for (Element ele : item.getAny()) {
704 String elementName = ele.getTagName().toLowerCase();
705 if (elementName.equals("csid")) {
706 result = ele.getTextContent();
717 * @param parentspecifier - ID of the container. Can be URN or CSID form
718 * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
719 * @param isProposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
723 protected Response createAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentIdentifier,
724 boolean shouldUpdateRevNumber,
726 boolean isSasItem) throws Exception {
727 Response result = null;
729 // Note: must have the parentShortId, to do the create.
730 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
731 AuthorityItemDocumentModelHandler handler =
732 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
733 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
734 handler.setIsProposed(isProposed);
735 handler.setIsSASItem(isSasItem);
736 // Make the client call
737 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
739 // Build the JAX-RS response
740 UriBuilder path = UriBuilder.fromResource(resourceClass);
741 path.path(parent.CSID + "/items/" + itemcsid);
742 result = Response.created(path.build()).build();
747 public PoxPayloadOut updateAuthorityItem(
748 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
749 ResourceMap resourceMap,
751 String parentspecifier,
752 String itemspecifier,
753 PoxPayloadIn theUpdate,
754 boolean shouldUpdateRevNumber,
758 PoxPayloadOut result = null;
760 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
761 String parentcsid = csidAndShortId.CSID;
762 String parentShortId = csidAndShortId.shortIdentifier;
764 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
766 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
768 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
770 ctx.setInput(theUpdate); // the update payload
773 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
775 // We omit the parentShortId, only needed when doing a create...
776 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
777 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
779 // Update the SAS fields if either value is non-null
781 boolean updateSASFields = isProposed != null || isSASItem != null;
782 handler.setshouldUpdateSASFields(updateSASFields);
783 if (updateSASFields == true) {
784 handler.setshouldUpdateSASFields(true);
785 if (isProposed != null) {
786 handler.setIsProposed(isProposed);
788 if (isSASItem != null) {
789 handler.setIsSASItem(isSASItem);
793 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
794 result = ctx.getOutput();
800 * Called with an existing context.
802 * @param parentIdentifier
807 public Response createAuthorityItemWithParentContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
808 String parentIdentifier,
810 boolean shouldUpdateRevNumber,
812 boolean isSASItem) throws Exception {
813 Response result = null;
815 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
816 parentCtx.getResourceMap(), parentCtx.getUriInfo());
817 if (parentCtx.getCurrentRepositorySession() != null) {
818 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
820 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem);
825 /*************************************************************************
826 * Create an AuthorityItem - this is a sub-resource of Authority
827 * @param specifier either a CSID or one of the urn forms
828 * @return Authority item response
829 *************************************************************************/
831 @Path("{csid}/items")
832 public Response createAuthorityItem(
833 @Context ResourceMap resourceMap,
834 @Context UriInfo uriInfo,
835 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
837 uriInfo = new UriInfoWrapper(uriInfo);
838 Response result = null;
841 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
842 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
843 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
844 AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM);
845 } catch (Exception e) {
846 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
853 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
854 public byte[] getItemWorkflow(
855 @PathParam("csid") String csid,
856 @PathParam("itemcsid") String itemcsid) {
857 PoxPayloadOut result = null;
860 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
861 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
863 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
864 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
865 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
866 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
867 result = ctx.getOutput();
868 } catch (Exception e) {
869 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
871 return result.getBytes();
875 * We should consider changing this code. The RepositoryClient (from call to getRepositoryClient) could support a call doWorkflowTransition() instead?
879 @Path("{csid}" + WorkflowClient.SERVICE_PATH + "/" + "{transition}")
880 public byte[] updateWorkflowWithTransition(
881 @Context UriInfo uriInfo,
882 @PathParam("csid") String specifier,
883 @PathParam("transition") String transition) {
884 PoxPayloadOut result = null;
886 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
889 csid = getCsid(null, spec);
890 result = updateWorkflowWithTransition(NULL_CONTEXT, uriInfo, csid, transition);
891 } catch (Exception e) {
892 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
895 return result.getBytes();
898 //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
899 // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
901 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
902 public byte[] updateItemWorkflowWithTransition(
903 @Context UriInfo uriInfo,
904 @PathParam("csid") String parentIdentifier,
905 @PathParam("itemcsid") String itemIdentifier,
906 @PathParam("transition") String transition) {
907 uriInfo = new UriInfoWrapper(uriInfo);
908 PoxPayloadOut result = null;
911 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
912 result = updateItemWorkflowWithTransition(ctx,
913 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
914 } catch (Exception e) {
915 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
918 return result.getBytes();
922 * Update an authority item's workflow state.
923 * @param existingContext
928 * @throws DocumentReferenceException
930 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
931 String parentIdentifier,
932 String itemIdentifier,
934 boolean updateRevNumber) throws DocumentReferenceException {
935 PoxPayloadOut result = null;
939 // We need CSIDs for both the parent authority and the authority item
941 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
942 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
945 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
947 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
948 WorkflowClient.SERVICE_COMMONPART_NAME);
949 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
950 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
951 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
954 // Create a service context and document handler for the target resource -not the workflow resource itself.
956 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
957 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
958 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
959 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
961 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
963 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
964 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
966 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
967 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
968 if (transitionDef == null) {
969 throw new DocumentException(String.format("The document with ID='%s' does not support the workflow transition '%s'.",
970 itemIdentifier, transition));
972 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
974 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
975 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
976 result = ctx.getOutput();
977 } catch (DocumentReferenceException de) {
979 } catch (Exception e) {
980 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
986 protected PoxPayloadOut getAuthorityItem(
987 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
988 String parentIdentifier,
989 String itemIdentifier) throws Exception {
990 PoxPayloadOut result = null;
992 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
993 // We omit the parentShortId, only needed when doing a create...
994 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
996 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
997 if (itemSpec.form == SpecifierForm.CSID) {
998 // TODO should we assert that the item is in the passed vocab?
999 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
1001 String itemWhereClause =
1002 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
1003 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
1004 handler.setDocumentFilter(myFilter);
1005 getRepositoryClient(ctx).get(ctx, handler);
1008 result = (PoxPayloadOut) ctx.getOutput();
1009 if (result != null) {
1010 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
1011 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
1012 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
1013 itemSpec.value, inAuthority, parentcsid));
1020 public PoxPayloadOut getAuthorityItemWithExistingContext(
1021 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1022 String parentIdentifier,
1023 String itemIdentifier) throws Exception {
1024 PoxPayloadOut result = null;
1026 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
1027 if (existingCtx.getCurrentRepositorySession() != null) {
1028 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
1029 ctx.setProperties(existingCtx.getProperties());
1031 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1037 * Gets the authority item.
1039 * @param parentspecifier either a CSID or one of the urn forms
1040 * @param itemspecifier either a CSID or one of the urn forms
1042 * @return the authority item
1045 @Path("{csid}/items/{itemcsid}")
1046 public byte[] getAuthorityItem(
1047 @Context Request request,
1048 @Context UriInfo uriInfo,
1049 @Context ResourceMap resourceMap,
1050 @PathParam("csid") String parentIdentifier,
1051 @PathParam("itemcsid") String itemIdentifier) {
1052 uriInfo = new UriInfoWrapper(uriInfo);
1053 PoxPayloadOut result = null;
1055 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
1056 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1058 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
1059 ctx.setJaxRsContext(jaxRsContext);
1061 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1062 } catch (DocumentNotFoundException dnf) {
1063 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
1064 } catch (Exception e) {
1065 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1068 return result.getBytes();
1072 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
1073 * different enough that it will have to override this method in it's resource class.
1076 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1077 String result = null;
1079 result = NuxeoUtils.getPrimaryElPathPropertyName(
1080 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1081 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1087 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1088 String result = null;
1090 result = NuxeoUtils.getMultiElPathPropertyName(
1091 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1092 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1098 * Gets the authorityItem list for the specified authority
1099 * If partialPerm is specified, keywords will be ignored.
1101 * @param authorityIdentifier either a CSID or one of the urn forms
1102 * @param partialTerm if non-null, matches partial terms
1103 * @param keywords if non-null, matches terms in the keyword index for items
1104 * @param ui passed to include additional parameters, like pagination controls
1107 public AbstractCommonList getAuthorityItemList(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1108 String authorityIdentifier,
1109 UriInfo uriInfo) throws Exception {
1110 AbstractCommonList result = null;
1112 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1113 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1114 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
1115 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
1116 ctx.setProperties(existingContext.getProperties());
1119 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
1120 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
1121 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
1122 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
1123 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
1125 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
1126 // We omit the parentShortId, only needed when doing a create...
1127 String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null :
1128 lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo);
1129 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
1130 createItemDocumentHandler(ctx, parentcsid, null);
1132 DocumentFilter myFilter = handler.getDocumentFilter();
1133 // If we are not wildcarding the parent, add a restriction
1134 if (parentcsid != null) {
1135 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
1136 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
1137 + "'" + parentcsid + "'",
1138 IQueryManager.SEARCH_QUALIFIER_AND);
1141 if (Tools.notBlank(termStatus)) {
1142 // Start with the qualified termStatus field
1143 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
1144 + AuthorityItemJAXBSchema.TERM_STATUS;
1145 String[] filterTerms = termStatus.trim().split("\\|");
1146 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
1147 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
1150 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
1156 * Gets the authorityItem list for the specified authority
1157 * If partialPerm is specified, keywords will be ignored.
1159 * @param authorityIdentifier either a CSID or one of the urn forms
1160 * @param partialTerm if non-null, matches partial terms
1161 * @param keywords if non-null, matches terms in the keyword index for items
1162 * @param ui passed to include additional parameters, like pagination controls
1164 * @return the authorityItem list
1167 @Path("{csid}/items")
1168 @Produces("application/xml")
1169 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier,
1170 @Context UriInfo uriInfo) {
1171 uriInfo = new UriInfoWrapper(uriInfo);
1172 AbstractCommonList result = null;
1175 result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo);
1176 } catch (Exception e) {
1177 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
1184 * @return the name of the property used to specify references for items in this type of
1185 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
1186 * Some types (like Vocabulary) use a separate property.
1188 protected String getRefPropName() {
1189 return ServiceBindingUtils.AUTH_REF_PROP;
1193 * Gets the entities referencing this Authority item instance. The service type
1194 * can be passed as a query param "type", and must match a configured type
1195 * for the service bindings. If not set, the type defaults to
1196 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
1198 * @param parentspecifier either a CSID or one of the urn forms
1199 * @param itemspecifier either a CSID or one of the urn forms
1202 * @return the info for the referencing objects
1205 @Path("{csid}/items/{itemcsid}/refObjs")
1206 @Produces("application/xml")
1207 public AuthorityRefDocList getReferencingObjects(
1208 @PathParam("csid") String parentSpecifier,
1209 @PathParam("itemcsid") String itemSpecifier,
1210 @Context UriInfo uriInfo) {
1211 uriInfo = new UriInfoWrapper(uriInfo);
1212 AuthorityRefDocList authRefDocList = null;
1214 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriInfo, PAGE_NUM_FROM_QUERYPARAMS, PAGE_SIZE_FROM_QUERYPARAMS, true, true);
1215 } catch (Exception e) {
1216 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1219 if (authRefDocList == null) {
1220 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1221 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1222 "text/plain").build();
1223 throw new CSWebApplicationException(response);
1225 return authRefDocList;
1228 public AuthorityRefDocList getReferencingObjects(
1229 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1230 String parentspecifier,
1231 String itemspecifier,
1235 boolean useDefaultOrderByClause,
1236 boolean computeTotal) throws Exception {
1237 AuthorityRefDocList authRefDocList = null;
1239 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1240 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1242 // Merge parts of existing context with our new context
1244 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1245 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1246 ctx.setProperties(existingContext.getProperties());
1249 String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1250 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1252 // Remove the "type" property from the query params
1253 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1254 if (serviceTypes == null || serviceTypes.isEmpty()) {
1255 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1258 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1259 authRefDocList = handler.getReferencingObjects(ctx, serviceTypes, getRefPropName(), itemcsid, pageNum, pageSize, useDefaultOrderByClause, computeTotal);
1261 return authRefDocList;
1265 * Gets the authority terms used in the indicated Authority item.
1267 * @param parentspecifier either a CSID or one of the urn forms
1268 * @param itemspecifier either a CSID or one of the urn forms
1269 * @param ui passed to include additional parameters, like pagination controls
1271 * @return the authority refs for the Authority item.
1274 @Path("{csid}/items/{itemcsid}/authorityrefs")
1275 @Produces("application/xml")
1276 public AuthorityRefList getAuthorityItemAuthorityRefs(
1277 @PathParam("csid") String parentspecifier,
1278 @PathParam("itemcsid") String itemspecifier,
1279 @Context UriInfo uriInfo) {
1280 uriInfo = new UriInfoWrapper(uriInfo);
1281 AuthorityRefList authRefList = null;
1284 // Note that we have to create the service context for the Items, not the main service
1285 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1286 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1287 // We omit the parentShortId, only needed when doing a create...
1288 DocumentModelHandler<?, AbstractCommonList> handler =
1289 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1291 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1293 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1294 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1295 } catch (Exception e) {
1296 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1303 * Synchronizes a local authority item with a share authority server (SAS) item.
1305 * @param parentIdentifier
1306 * @param itemIdentifier
1310 private PoxPayloadOut synchronizeItem(
1311 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1312 String parentIdentifier,
1313 String itemIdentifier,
1314 boolean syncHierarchicalRelationships) throws Exception {
1315 PoxPayloadOut result = null;
1316 AuthorityItemSpecifier specifier;
1317 boolean neededSync = false;
1319 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1320 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1321 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1322 handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1323 handler.setShouldSyncHierarchicalRelationships(syncHierarchicalRelationships);
1324 // Create an authority item specifier
1325 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1326 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1327 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1329 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1330 if (neededSync == true) {
1331 result = (PoxPayloadOut) ctx.getOutput();
1338 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1339 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1340 * local authority. The parent context was created for the authority (parent) because the sync started there.
1341 * @param existingCtx
1342 * @param parentIdentifier
1343 * @param itemIdentifier
1347 public PoxPayloadOut synchronizeItemWithExistingContext(
1348 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1349 String parentIdentifier,
1350 String itemIdentifier,
1351 boolean syncHierarchicalRelationships
1352 ) throws Exception {
1353 PoxPayloadOut result = null;
1355 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1356 existingCtx.getResourceMap(),
1357 existingCtx.getUriInfo());
1358 if (existingCtx.getCurrentRepositorySession() != null) {
1359 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1362 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
1368 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1370 * @param specifier either CSIDs and/or one of the urn forms
1372 * @return the authority item if it was updated/synchronized with SAS item; otherwise empty
1375 @Path("{csid}/items/{itemcsid}/sync")
1376 public byte[] synchronizeItem(
1377 @Context ResourceMap resourceMap,
1378 @Context UriInfo uriInfo,
1379 @PathParam("csid") String parentIdentifier,
1380 @PathParam("itemcsid") String itemIdentifier) {
1381 uriInfo = new UriInfoWrapper(uriInfo);
1383 boolean neededSync = false;
1384 PoxPayloadOut payloadOut = null;
1387 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1388 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier, true);
1389 if (payloadOut != null) {
1392 } catch (Exception e) {
1393 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1397 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1399 if (neededSync == true) {
1400 result = payloadOut.getBytes();
1402 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1403 itemIdentifier).getBytes();
1404 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1405 throw new CSWebApplicationException(response);
1412 * Update authorityItem.
1414 * @param parentspecifier either a CSID or one of the urn forms
1415 * @param itemspecifier either a CSID or one of the urn forms
1417 * @return the multipart output
1420 @Path("{csid}/items/{itemcsid}")
1421 public byte[] updateAuthorityItem(
1422 @Context ResourceMap resourceMap,
1423 @Context UriInfo uriInfo,
1424 @PathParam("csid") String parentSpecifier,
1425 @PathParam("itemcsid") String itemSpecifier,
1426 String xmlPayload) {
1427 uriInfo = new UriInfoWrapper(uriInfo);
1428 PoxPayloadOut result = null;
1431 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1432 result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1433 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1434 AuthorityServiceUtils.NO_CHANGE, // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1435 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1436 } catch (Exception e) {
1437 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1440 return result.getBytes();
1446 * Delete authorityItem.
1448 * @param parentIdentifier the parentcsid
1449 * @param itemIdentifier the itemcsid
1451 * @return the response
1454 @Path("{csid}/items/{itemcsid}")
1455 public Response deleteAuthorityItem(
1456 @Context UriInfo uriInfo,
1457 @PathParam("csid") String parentIdentifier,
1458 @PathParam("itemcsid") String itemIdentifier) {
1459 uriInfo = new UriInfoWrapper(uriInfo);
1460 Response result = null;
1462 ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1463 ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1464 if (logger.isDebugEnabled()) {
1465 logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1469 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1470 deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1471 result = Response.status(HttpResponseCodes.SC_OK).build();
1472 } catch (Exception e) {
1473 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1481 * @param existingCtx
1482 * @param parentIdentifier
1483 * @param itemIdentifier
1486 public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1487 String parentIdentifier,
1488 String itemIdentifier,
1489 boolean shouldUpdateRevNumber
1490 ) throws Exception {
1491 boolean result = true;
1493 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1494 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1495 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1496 ctx.setProperties(existingCtx.getProperties());
1499 String parentcsid = null;
1501 parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1502 } catch (DocumentNotFoundException de) {
1503 String msg = String.format("Could not find parent with ID='%s' when trying to delete item ID='%s'",
1504 parentIdentifier, itemIdentifier);
1508 String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1510 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
1511 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1512 result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1518 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1519 @Produces("application/xml")
1520 public String getHierarchy(
1521 @PathParam("csid") String parentIdentifier,
1522 @PathParam("itemcsid") String itemIdentifier,
1523 @Context UriInfo uriInfo) throws Exception {
1524 uriInfo = new UriInfoWrapper(uriInfo);
1525 String result = null;
1529 // 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...?
1531 String calledUri = uriInfo.getPath();
1532 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1533 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1535 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1536 String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1538 String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1539 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1540 result = Hierarchy.surface(ctx, itemcsid, uri);
1542 result = Hierarchy.dive(ctx, itemcsid, uri);
1544 } catch (Exception e) {
1545 throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1556 public String getItemDocType(String tenantId) {
1557 return getDocType(tenantId, getItemServiceName());
1561 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1562 * for the current resource, for all tenants
1564 * @return a map of URI templates for the current resource, for all tenants
1567 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1568 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1569 super.getUriRegistryEntries();
1570 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1571 for (String tenantId : tenantIds) {
1572 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1574 return uriRegistryEntriesMap;
1581 public ServiceDescription getDescription(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1582 ServiceDescription result = super.getDescription(ctx);
1583 result.setSubresourceDocumentType(this.getItemDocType(ctx.getTenantId()));
1587 public Response createAuthority(String xmlPayload) {
1588 return this.createAuthority(null, null, xmlPayload);
1591 protected String getCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, Specifier specifier) throws Exception {
1595 ctx = createServiceContext(getServiceName());
1598 if (specifier.form == SpecifierForm.CSID) {
1599 csid = specifier.value;
1601 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, specifier.value);
1602 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);