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.Response.ResponseBuilder;
42 import javax.ws.rs.core.UriBuilder;
43 import javax.ws.rs.core.UriInfo;
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.UriTemplateRegistryKey;
61 import org.collectionspace.services.common.api.RefName;
62 import org.collectionspace.services.common.api.RefNameUtils;
63 import org.collectionspace.services.common.api.RefNameUtils.AuthorityTermInfo;
64 import org.collectionspace.services.common.api.Tools;
65 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
66 import org.collectionspace.services.common.authorityref.AuthorityRefList;
67 import org.collectionspace.services.common.context.JaxRsContext;
68 import org.collectionspace.services.common.context.MultipartServiceContext;
69 import org.collectionspace.services.common.context.RemoteServiceContext;
70 import org.collectionspace.services.common.context.ServiceBindingUtils;
71 import org.collectionspace.services.common.context.ServiceContext;
72 import org.collectionspace.services.common.document.DocumentException;
73 import org.collectionspace.services.common.document.DocumentFilter;
74 import org.collectionspace.services.common.document.DocumentHandler;
75 import org.collectionspace.services.common.document.DocumentNotFoundException;
76 import org.collectionspace.services.common.document.DocumentReferenceException;
77 import org.collectionspace.services.common.document.DocumentWrapper;
78 import org.collectionspace.services.common.document.Hierarchy;
79 import org.collectionspace.services.common.query.QueryManager;
80 import org.collectionspace.services.common.repository.RepositoryClient;
81 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
82 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
83 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
84 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
85 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
86 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
87 import org.collectionspace.services.config.ClientType;
88 import org.collectionspace.services.config.service.ServiceBindingType;
89 import org.collectionspace.services.description.ServiceDescription;
90 import org.collectionspace.services.jaxb.AbstractCommonList;
91 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
92 import org.collectionspace.services.lifecycle.TransitionDef;
93 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
94 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
95 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
96 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
97 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
98 import org.collectionspace.services.workflow.WorkflowCommon;
99 import org.jboss.resteasy.util.HttpResponseCodes;
100 import org.nuxeo.ecm.core.api.DocumentModel;
101 import org.nuxeo.ecm.core.api.DocumentModelList;
102 import org.slf4j.Logger;
103 import org.slf4j.LoggerFactory;
104 import org.w3c.dom.Element;
107 * The Class AuthorityResource.
110 @SuppressWarnings({"rawtypes", "unchecked"})
111 @Consumes("application/xml")
112 @Produces("application/xml")
113 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
114 extends NuxeoBasedResource {
116 final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
118 final static String SEARCH_TYPE_TERMSTATUS = "ts";
119 public final static String hierarchy = "hierarchy";
121 private static final Integer PAGE_NUM_FROM_QUERYPARAMS = null;
122 private static final Integer PAGE_SIZE_FROM_QUERYPARAMS = null;
124 protected Class<AuthCommon> authCommonClass;
125 protected Class<?> resourceClass;
126 protected String authorityCommonSchemaName;
127 protected String authorityItemCommonSchemaName;
128 final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed? I see no references to it.
130 final static String FETCH_SHORT_ID = "_fetch_";
131 public final static String PARENT_WILDCARD = "_ALL_";
132 protected static final boolean DONT_INCLUDE_ITEMS = false;
133 protected static final boolean INCLUDE_ITEMS = true;
136 * Instantiates a new Authority resource.
138 public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
139 String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
140 this.authCommonClass = authCommonClass;
141 this.resourceClass = resourceClass;
142 this.authorityCommonSchemaName = authorityCommonSchemaName;
143 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
146 public abstract String getItemServiceName();
148 public abstract String getItemTermInfoGroupXPathBase();
151 protected String getVersionString() {
152 return "$LastChangedRevision: 2617 $";
156 public Class<AuthCommon> getCommonPartClass() {
157 return authCommonClass;
161 * Creates the item document handler.
164 * @param inAuthority the in vocabulary
166 * @return the document handler
168 * @throws Exception the exception
170 protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
171 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
172 String inAuthority, String containerShortIdentifier)
174 String authorityRefNameBase;
175 AuthorityItemDocumentModelHandler<?> docHandler;
177 if (containerShortIdentifier == null) {
178 authorityRefNameBase = null;
180 ServiceContext<PoxPayloadIn, PoxPayloadOut> containerCtx = createServiceContext(getServiceName());
181 if (containerShortIdentifier.equals(FETCH_SHORT_ID)) { // We need to fetch this from the repo
182 if (ctx.getCurrentRepositorySession() != null) {
183 containerCtx.setCurrentRepositorySession(ctx.getCurrentRepositorySession()); // We need to use the current repo session if one exists
185 // Get from parent document
186 containerShortIdentifier = getAuthShortIdentifier(containerCtx, inAuthority);
188 authorityRefNameBase = buildAuthorityRefNameBase(containerCtx, containerShortIdentifier);
191 docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
192 ctx.getCommonPartLabel(getItemServiceName()),
194 // FIXME - Richard and Aron think the following three lines should
195 // be in the constructor for the AuthorityItemDocumentModelHandler
196 // because all three are required fields.
197 docHandler.setInAuthority(inAuthority);
198 docHandler.setAuthorityRefNameBase(authorityRefNameBase);
199 docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
203 public String getAuthShortIdentifier(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
204 throws DocumentNotFoundException, DocumentException {
205 String shortIdentifier = null;
208 AuthorityDocumentModelHandler<?> handler = (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
209 shortIdentifier = handler.getShortIdentifier(ctx, authCSID, authorityCommonSchemaName);
210 } catch (Exception e) {
211 if (logger.isDebugEnabled()) {
212 logger.debug("Caught exception ", e);
214 throw new DocumentException(e);
217 return shortIdentifier;
220 protected String buildAuthorityRefNameBase(
221 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
222 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
223 ctx.getServiceName(),
224 null, // Only use shortId form!!!
225 shortIdentifier, null);
226 return authority.toString();
229 public static class CsidAndShortIdentifier {
231 String shortIdentifier;
234 protected String lookupParentCSID(String parentspecifier, String method,
235 String op, UriInfo uriInfo) throws Exception {
236 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(NULL_CONTEXT,
237 parentspecifier, method, op, uriInfo);
238 return tempResult.CSID;
241 protected String lookupParentCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentspecifier, String method,
242 String op, UriInfo uriInfo) throws Exception {
243 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(ctx,
244 parentspecifier, method, op, uriInfo);
245 return tempResult.CSID;
249 private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
250 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx, // Ok to be null
251 String parentIdentifier,
256 CsidAndShortIdentifier result = new CsidAndShortIdentifier();
257 Specifier parentSpec = Specifier.getSpecifier(parentIdentifier, method, op);
260 String parentShortIdentifier;
261 if (parentSpec.form == SpecifierForm.CSID) {
262 parentShortIdentifier = null;
263 parentcsid = parentSpec.value;
264 // Uncomment when app layer is ready to integrate
265 // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
266 parentShortIdentifier = FETCH_SHORT_ID;
268 parentShortIdentifier = parentSpec.value;
269 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentShortIdentifier);
270 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
271 CoreSessionInterface repoSession = null;
272 if (existingCtx != null) {
273 repoSession = (CoreSessionInterface) existingCtx.getCurrentRepositorySession(); // We want to use the thread's current repo session
275 parentcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
278 result.CSID = parentcsid;
279 result.shortIdentifier = parentShortIdentifier;
284 public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext, String itemSpecifier, String parentCsid, String method, String op)
287 Specifier itemSpec = Specifier.getSpecifier(itemSpecifier, method, op);
289 if (itemSpec.form == SpecifierForm.CSID) {
290 itemCsid = itemSpec.value;
292 CoreSessionInterface repoSession = null;
293 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(getItemServiceName());
295 if (existingContext != null) {
296 repoSession = (CoreSessionInterface) existingContext.getCurrentRepositorySession(); // We want to use the thread's current repo session
299 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentCsid);
300 itemCsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
307 * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
308 * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
309 * Resource. They then call this method on that resource.
312 public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
313 throws Exception, DocumentNotFoundException {
317 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
318 // Ensure we have the right context.
319 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
321 // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
322 NuxeoRepositoryClientImpl client = (NuxeoRepositoryClientImpl)getRepositoryClient(ctx);
323 String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
325 String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
326 ctx = createServiceContext(getItemServiceName());
327 DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
328 DocumentModel docModel = docWrapper.getWrappedObject();
334 public Response createAuthority(
335 @Context ResourceMap resourceMap,
336 @Context UriInfo uriInfo,
339 // 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
340 // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
341 // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
342 // the code that creates new authorities. The authority document model handler will first check for authorities with the same short id before
343 // trying to create a new authority.
345 synchronized(AuthorityResource.class) {
347 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
348 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
349 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
351 String csid = getRepositoryClient(ctx).create(ctx, handler);
352 UriBuilder path = UriBuilder.fromResource(resourceClass);
353 path.path("" + csid);
354 Response response = Response.created(path.build()).build();
356 } catch (Exception e) {
357 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
362 protected boolean supportsReplicating(String tenantId, String serviceName) {
363 boolean result = false;
365 ServiceBindingType sb = getTenantBindingsReader().getServiceBinding(tenantId, getServiceName());
366 result = sb.isSupportsReplicating();
372 * Synchronizes the authority and its items/terms with a Shared Authority Server.
374 * @param specifier either a CSID or one of the urn forms
376 * @return the authority
380 public byte[] synchronize(
381 @Context Request request,
382 @Context UriInfo uriInfo,
383 @PathParam("csid") String identifier) {
384 uriInfo = new UriInfoWrapper(uriInfo);
386 boolean neededSync = false;
387 PoxPayloadOut payloadOut = null;
391 // Prevent multiple SAS synchronizations from occurring simultaneously by synchronizing this method.
393 synchronized(AuthorityResource.class) {
395 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
397 * Make sure this authority service supports synchronization
399 if (supportsReplicating(ctx.getTenantId(), ctx.getServiceName()) == false) {
400 throw new DocumentException(Response.Status.FORBIDDEN.getStatusCode());
402 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
403 specifier = Specifier.getSpecifier(identifier, "getAuthority", "GET");
404 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
405 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
406 payloadOut = ctx.getOutput();
407 } catch (Exception e) {
408 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, identifier);
412 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
414 if (neededSync == true) {
415 result = payloadOut.getBytes();
417 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
418 specifier.value).getBytes();
419 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
420 throw new CSWebApplicationException(response);
428 * Builds a cached JAX-RS response.
430 protected Response buildResponse(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, PoxPayloadOut payloadOut) {
431 Response result = null;
433 ResponseBuilder responseBuilder = Response.ok(payloadOut.getBytes());
434 this.setCacheControl(ctx, responseBuilder);
435 result = responseBuilder.build();
441 * Gets the authority.
443 * @param specifier either a CSID or one of the urn forms
445 * @return the authority
451 @Context Request request,
452 @Context ResourceMap resourceMap,
453 @Context UriInfo uriInfo,
454 @PathParam("csid") String specifier) {
455 Response result = null;
456 uriInfo = new UriInfoWrapper(uriInfo);
457 PoxPayloadOut payloadout = null;
461 // If the specifier is a fully qualified authority term refname, then return the term payload in the response
463 if (RefNameUtils.isTermRefname(specifier)) {
464 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(specifier);
465 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
466 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
467 result = this.getAuthorityItemResponse(request, uriInfo, resourceMap, parentIdentifier, itemIdentifier);
469 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(request, uriInfo);
470 payloadout = getAuthority(ctx, request, uriInfo, specifier, DONT_INCLUDE_ITEMS);
471 result = buildResponse(ctx, payloadout);
473 } catch (Exception e) {
474 throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
477 if (result == null) {
478 Response response = Response.status(Response.Status.NOT_FOUND).entity(
479 "GET request failed. The requested Authority specifier:" + specifier + ": was not found.").type(
480 "text/plain").build();
481 throw new CSWebApplicationException(response);
487 protected PoxPayloadOut getAuthority(
488 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
492 boolean includeItems) throws Exception {
493 uriInfo = new UriInfoWrapper(uriInfo);
494 PoxPayloadOut payloadout = null;
496 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> docHandler = createDocumentHandler(ctx);
497 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
498 if (spec.form == SpecifierForm.CSID) {
499 if (logger.isDebugEnabled()) {
500 logger.debug("getAuthority with csid=" + spec.value);
502 getRepositoryClient(ctx).get(ctx, spec.value, docHandler);
504 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
505 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
506 docHandler.setDocumentFilter(myFilter);
507 getRepositoryClient(ctx).get(ctx, docHandler);
510 payloadout = ctx.getOutput();
511 if (includeItems == true) {
512 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
513 payloadout.addPart(PoxPayload.ABSTRACT_COMMON_LIST_ROOT_ELEMENT_LABEL, itemsList);
520 * Finds and populates the authority list.
524 * @return the authority list
527 @Produces("application/xml")
528 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.
529 uriInfo = new UriInfoWrapper(uriInfo);
530 return this.getAuthorityList(null, uriInfo);
533 public AbstractCommonList getAuthorityList(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx, @Context UriInfo uriInfo) {
534 uriInfo = new UriInfoWrapper(uriInfo);
535 AbstractCommonList result = null;
538 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
539 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
540 if (parentCtx != null && parentCtx.getCurrentRepositorySession() != null) {
541 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
543 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
544 DocumentFilter myFilter = handler.getDocumentFilter();
545 // Need to make the default sort order for authority items
546 // be on the displayName field
547 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
548 if (orderBy == null || orderBy.isEmpty()) {
549 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
550 + AuthorityItemJAXBSchema.DISPLAY_NAME;
551 myFilter.setOrderByClause(qualifiedDisplayNameField);
553 String nameQ = queryParams.getFirst("refName");
555 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
557 //getRepositoryClient(ctx).getFiltered(ctx, handler); # Something here?
558 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
559 result = search(ctx, handler, uriInfo, orderBy, null, advancedSearch, null);
560 result = handler.getCommonPartList();
561 } catch (Exception e) {
562 throw bigReThrow(e, ServiceMessages.GET_FAILED);
569 * Overriding this methods to see if we should update the revision number during the update. We don't
570 * want to update the rev number of synchronization operations.
573 protected PoxPayloadOut update(String csid,
574 PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
575 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
577 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
578 Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
579 if (shouldUpdateRev != null) {
580 handler.setShouldUpdateRevNumber(shouldUpdateRev);
582 getRepositoryClient(ctx).update(ctx, csid, handler);
583 return ctx.getOutput();
589 * @param specifier the csid or id
591 * @return the multipart output
595 public byte[] updateAuthority(
596 @Context Request request,
597 @Context ResourceMap resourceMap,
598 @Context UriInfo uriInfo,
599 @PathParam("csid") String specifier,
601 PoxPayloadOut result = null;
603 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
604 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
605 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
606 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
607 String csid = getCsid(ctx, spec);
608 getRepositoryClient(ctx).update(ctx, csid, handler);
609 result = ctx.getOutput();
610 } catch (Exception e) {
611 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
613 return result.getBytes();
617 * Delete all the items in an authority list.
624 @Path("{csid}/items")
625 public Response deleteAuthorityItemList(@PathParam("csid") String specifier,
626 @Context UriInfo uriInfo) {
627 uriInfo = new UriInfoWrapper(uriInfo);
630 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
631 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
633 CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
635 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
637 // Delete all the items one by one
639 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
640 for (ListItem item : itemsList.getListItem()) {
641 deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
643 } catch (Throwable t) {
644 repoSession.setTransactionRollbackOnly();
647 repoClient.releaseRepositorySession(ctx, repoSession);
650 return Response.status(HttpResponseCodes.SC_OK).build();
651 } catch (Exception e) {
652 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
659 * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
661 * @return the response
665 public Response deleteAuthority( // # Delete this authority and all of it's items.
666 @Context Request request,
667 @Context UriInfo uriInfo,
668 @PathParam("csid") String specifier) {
669 uriInfo = new UriInfoWrapper(uriInfo);
671 if (logger.isDebugEnabled()) {
672 logger.debug("deleteAuthority with specifier=" + specifier);
676 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
677 Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
678 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
680 CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
682 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
684 // First try to delete all the items
686 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
687 for (ListItem item : itemsList.getListItem()) {
688 deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
692 // Lastly, delete the parent/container
694 if (spec.form == SpecifierForm.CSID) {
695 if (logger.isDebugEnabled()) {
696 logger.debug("deleteAuthority with csid=" + spec.value);
698 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
699 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
701 if (logger.isDebugEnabled()) {
702 logger.debug("deleteAuthority with specifier=" + spec.value);
704 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
705 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
707 } catch (Throwable t) {
708 repoSession.setTransactionRollbackOnly();
711 repoClient.releaseRepositorySession(ctx, repoSession);
714 return Response.status(HttpResponseCodes.SC_OK).build();
715 } catch (Exception e) {
716 throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
720 protected String getCsid(ListItem item) {
721 String result = null;
723 for (Element ele : item.getAny()) {
724 String elementName = ele.getTagName().toLowerCase();
725 if (elementName.equals("csid")) {
726 result = ele.getTextContent();
737 * @param parentspecifier - ID of the container. Can be URN or CSID form
738 * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
739 * @param isProposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
743 protected Response createAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentIdentifier,
744 boolean shouldUpdateRevNumber,
746 boolean isSasItem) throws Exception {
747 Response result = null;
749 // Note: must have the parentShortId, to do the create.
750 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
751 AuthorityItemDocumentModelHandler handler =
752 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
753 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
754 handler.setIsProposed(isProposed);
755 handler.setIsSASItem(isSasItem);
756 // Make the client call
757 String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
759 // Build the JAX-RS response
760 UriBuilder path = UriBuilder.fromResource(resourceClass);
761 path.path(parent.CSID + "/items/" + itemcsid);
762 result = Response.created(path.build()).build();
767 public PoxPayloadOut updateAuthorityItem(
768 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
769 ResourceMap resourceMap,
771 String parentspecifier,
772 String itemspecifier,
773 PoxPayloadIn theUpdate,
774 boolean shouldUpdateRevNumber,
778 return updateAuthorityItem(null, itemServiceCtx, resourceMap, uriInfo, parentspecifier, itemspecifier, theUpdate, shouldUpdateRevNumber, isProposed, isSASItem);
781 public PoxPayloadOut updateAuthorityItem(
782 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
783 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemServiceCtx, // Ok to be null. Will be null on PUT calls, but not on sync calls
784 ResourceMap resourceMap,
786 String parentspecifier,
787 String itemspecifier,
788 PoxPayloadIn theUpdate,
789 boolean shouldUpdateRevNumber,
793 PoxPayloadOut result = null;
795 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
796 String parentcsid = csidAndShortId.CSID;
797 String parentShortId = csidAndShortId.shortIdentifier;
799 // If the itemServiceCtx context is not null, use it. Otherwise, create a new context
801 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
803 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
804 if (parentCtx != null && parentCtx.getCurrentRepositorySession() != null) {
805 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
808 ctx.setInput(theUpdate); // the update payload
811 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
813 // We omit the parentShortId, only needed when doing a create...
814 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
815 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
817 // Update the SAS fields if either value is non-null
819 boolean updateSASFields = isProposed != null || isSASItem != null;
820 handler.setshouldUpdateSASFields(updateSASFields);
821 if (updateSASFields == true) {
822 handler.setshouldUpdateSASFields(true);
823 if (isProposed != null) {
824 handler.setIsProposed(isProposed);
826 if (isSASItem != null) {
827 handler.setIsSASItem(isSASItem);
831 getRepositoryClient(ctx).update(ctx, itemcsid, handler);
832 result = ctx.getOutput();
838 * Called with an existing context.
840 * @param parentIdentifier
845 public Response createAuthorityItemWithParentContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
846 String parentIdentifier,
848 boolean shouldUpdateRevNumber,
850 boolean isSASItem) throws Exception {
851 Response result = null;
853 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
854 parentCtx.getResourceMap(), parentCtx.getUriInfo());
855 if (parentCtx.getCurrentRepositorySession() != null) {
856 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
858 result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem);
863 /*************************************************************************
864 * Create an AuthorityItem - this is a sub-resource of Authority
865 * @param specifier either a CSID or one of the urn forms
866 * @return Authority item response
867 *************************************************************************/
869 @Path("{csid}/items")
870 public Response createAuthorityItem(
871 @Context ResourceMap resourceMap,
872 @Context UriInfo uriInfo,
873 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
875 uriInfo = new UriInfoWrapper(uriInfo);
876 Response result = null;
879 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
880 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
881 result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
882 AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM);
883 } catch (Exception e) {
884 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
891 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
892 public byte[] getItemWorkflow(
893 @PathParam("csid") String csid,
894 @PathParam("itemcsid") String itemcsid) {
895 PoxPayloadOut result = null;
898 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
899 String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
901 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
902 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
903 ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
904 getRepositoryClient(ctx).get(ctx, itemcsid, handler);
905 result = ctx.getOutput();
906 } catch (Exception e) {
907 throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
909 return result.getBytes();
913 * We should consider changing this code. The RepositoryClient (from call to getRepositoryClient) could support a call doWorkflowTransition() instead?
917 @Path("{csid}" + WorkflowClient.SERVICE_PATH + "/" + "{transition}")
918 public byte[] updateWorkflowWithTransition(
919 @Context UriInfo uriInfo,
920 @PathParam("csid") String specifier,
921 @PathParam("transition") String transition) {
922 PoxPayloadOut result = null;
924 Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
927 csid = getCsid(null, spec);
928 result = updateWorkflowWithTransition(NULL_CONTEXT, uriInfo, csid, transition);
929 } catch (Exception e) {
930 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
933 return result.getBytes();
937 @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
938 public byte[] updateItemWorkflowWithTransition(
939 @Context UriInfo uriInfo,
940 @PathParam("csid") String parentIdentifier,
941 @PathParam("itemcsid") String itemIdentifier,
942 @PathParam("transition") String transition) {
943 uriInfo = new UriInfoWrapper(uriInfo);
944 return updateItemWorkflowWithTransition(null, uriInfo, parentIdentifier, itemIdentifier, transition);
947 public byte[] updateItemWorkflowWithTransition(
948 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
950 String parentIdentifier,
951 String itemIdentifier,
953 uriInfo = new UriInfoWrapper(uriInfo);
954 PoxPayloadOut result = null;
957 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
958 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
959 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
961 result = updateItemWorkflowWithTransition(ctx,
962 parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
963 } catch (Exception e) {
964 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
967 return result.getBytes();
970 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
971 String parentIdentifier,
972 String itemIdentifier,
974 boolean updateRevNumber) throws DocumentReferenceException {
975 return updateItemWorkflowWithTransition(existingContext, parentIdentifier, itemIdentifier, transition, updateRevNumber, true);
979 * Update an authority item's workflow state.
980 * @param existingContext
985 * @throws DocumentReferenceException
987 public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
988 String parentIdentifier,
989 String itemIdentifier,
991 boolean updateRevNumber,
992 boolean rollbackOnException) throws DocumentReferenceException {
993 PoxPayloadOut result = null;
997 // We need CSIDs for both the parent authority and the authority item
999 CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
1000 String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
1003 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
1005 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
1006 WorkflowClient.SERVICE_COMMONPART_NAME);
1007 MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
1008 ctx.setRollbackOnException(rollbackOnException);
1009 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1010 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
1013 // Create a service context and document handler for the target resource -not the workflow resource itself.
1015 ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
1016 AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
1017 targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
1018 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
1020 // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
1022 String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
1023 ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
1025 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
1026 TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
1027 if (transitionDef == null) {
1028 throw new DocumentException(String.format("The document with ID='%s' does not support the workflow transition '%s'.",
1029 itemIdentifier, transition));
1031 ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
1033 WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
1034 getRepositoryClient(ctx).update(ctx, itemCsid, handler);
1035 result = ctx.getOutput();
1036 } catch (DocumentReferenceException de) {
1038 } catch (Exception e) {
1039 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
1045 protected PoxPayloadOut getAuthorityItem(
1046 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1047 String parentIdentifier,
1048 String itemIdentifier) throws Exception {
1049 PoxPayloadOut result = null;
1051 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
1052 // We omit the parentShortId, only needed when doing a create...
1053 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
1055 Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
1056 if (itemSpec.form == SpecifierForm.CSID) {
1057 // TODO should we assert that the item is in the passed vocab?
1058 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
1060 String itemWhereClause =
1061 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
1062 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
1063 handler.setDocumentFilter(myFilter);
1064 getRepositoryClient(ctx).get(ctx, handler);
1067 result = (PoxPayloadOut) ctx.getOutput();
1068 if (result != null) {
1069 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
1070 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
1071 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
1072 itemSpec.value, inAuthority, parentcsid));
1079 public PoxPayloadOut getAuthorityItemWithExistingContext(
1080 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1081 String parentIdentifier,
1082 String itemIdentifier) throws Exception {
1083 return getAuthorityItemWithExistingContext(existingCtx, existingCtx.getUriInfo(), existingCtx.getResourceMap(), parentIdentifier, itemIdentifier);
1086 public PoxPayloadOut getAuthorityItemWithExistingContext(
1087 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1089 ResourceMap resourceMap,
1090 String parentIdentifier,
1091 String itemIdentifier) throws Exception {
1092 PoxPayloadOut result = null;
1094 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1095 if (existingCtx.getCurrentRepositorySession() != null) {
1096 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
1097 ctx.setProperties(existingCtx.getProperties());
1099 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1105 * Gets the authority item.
1107 * @param parentspecifier either a CSID or one of the urn forms
1108 * @param itemspecifier either a CSID or one of the urn forms
1110 * @return the authority item
1113 @Path("{csid}/items/{itemcsid}")
1114 public byte[] getAuthorityItem(
1115 @Context Request request,
1116 @Context UriInfo uriInfo,
1117 @Context ResourceMap resourceMap,
1118 @PathParam("csid") String parentIdentifier,
1119 @PathParam("itemcsid") String itemIdentifier) {
1120 uriInfo = new UriInfoWrapper(uriInfo);
1121 PoxPayloadOut result = null;
1123 result = this.getAuthorityItemPayload(request, uriInfo, resourceMap, parentIdentifier, itemIdentifier);
1125 return result.getBytes();
1129 public PoxPayloadOut getAuthorityItemPayload(
1130 @Context Request request,
1131 @Context UriInfo uriInfo,
1132 @Context ResourceMap resourceMap,
1133 @PathParam("csid") String parentIdentifier,
1134 @PathParam("itemcsid") String itemIdentifier) {
1135 uriInfo = new UriInfoWrapper(uriInfo);
1136 PoxPayloadOut result = null;
1138 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
1139 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1141 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
1142 ctx.setJaxRsContext(jaxRsContext);
1144 result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1145 } catch (DocumentNotFoundException dnf) {
1146 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
1147 } catch (Exception e) {
1148 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1154 public Response getAuthorityItemResponse(
1155 @Context Request request,
1156 @Context UriInfo uriInfo,
1157 @Context ResourceMap resourceMap,
1158 @PathParam("csid") String parentIdentifier,
1159 @PathParam("itemcsid") String itemIdentifier) {
1160 uriInfo = new UriInfoWrapper(uriInfo);
1161 PoxPayloadOut payloadout = null;
1162 RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
1165 ctx = (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1167 JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
1168 ctx.setJaxRsContext(jaxRsContext);
1170 payloadout = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1171 } catch (DocumentNotFoundException dnf) {
1172 throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
1173 } catch (Exception e) {
1174 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1177 return buildResponse(ctx, payloadout);
1182 * Most of the authority child classes will/should use this implementation. However, the Vocabulary service's item schema is
1183 * different enough that it will have to override this method in it's resource class.
1186 protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1187 String result = null;
1189 result = NuxeoUtils.getPrimaryElPathPropertyName(
1190 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1191 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1197 protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1198 String result = null;
1200 result = NuxeoUtils.getMultiElPathPropertyName(
1201 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1202 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1208 * Gets the authorityItem list for the specified authority
1209 * If partialPerm is specified, keywords will be ignored.
1211 * @param authorityIdentifier either a CSID or one of the urn forms
1212 * @param partialTerm if non-null, matches partial terms
1213 * @param keywords if non-null, matches terms in the keyword index for items
1214 * @param ui passed to include additional parameters, like pagination controls
1217 public AbstractCommonList getAuthorityItemList(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1218 String authorityIdentifier,
1219 UriInfo uriInfo) throws Exception {
1220 AbstractCommonList result = null;
1222 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1223 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1224 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
1225 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
1226 ctx.setProperties(existingContext.getProperties());
1229 String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
1230 String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
1231 String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
1232 String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
1233 String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
1235 // For the wildcard case, parentcsid is null, but docHandler will deal with this.
1236 // We omit the parentShortId, only needed when doing a create...
1237 String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null :
1238 lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo);
1239 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
1240 createItemDocumentHandler(ctx, parentcsid, null);
1242 DocumentFilter myFilter = handler.getDocumentFilter();
1243 // If we are not wildcarding the parent, add a restriction
1244 if (parentcsid != null) {
1245 myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
1246 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
1247 + "'" + parentcsid + "'",
1248 IQueryManager.SEARCH_QUALIFIER_AND);
1251 if (Tools.notBlank(termStatus)) {
1252 // Start with the qualified termStatus field
1253 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
1254 + AuthorityItemJAXBSchema.TERM_STATUS;
1255 String[] filterTerms = termStatus.trim().split("\\|");
1256 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
1257 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
1260 result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
1266 * Gets the authorityItem list for the specified authority
1267 * If partialPerm is specified, keywords will be ignored.
1269 * @param authorityIdentifier either a CSID or one of the urn forms
1270 * @param partialTerm if non-null, matches partial terms
1271 * @param keywords if non-null, matches terms in the keyword index for items
1272 * @param ui passed to include additional parameters, like pagination controls
1274 * @return the authorityItem list
1277 @Path("{csid}/items")
1278 @Produces("application/xml")
1279 public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier,
1280 @Context UriInfo uriInfo) {
1281 uriInfo = new UriInfoWrapper(uriInfo);
1282 AbstractCommonList result = null;
1285 result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo);
1286 } catch (Exception e) {
1287 throw bigReThrow(e, ServiceMessages.LIST_FAILED);
1294 * @return the name of the property used to specify references for items in this type of
1295 * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
1296 * Some types (like Vocabulary) use a separate property.
1298 protected String getRefPropName() {
1299 return ServiceBindingUtils.AUTH_REF_PROP;
1303 * Gets the entities referencing this Authority item instance. The service type
1304 * can be passed as a query param "type", and must match a configured type
1305 * for the service bindings. If not set, the type defaults to
1306 * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
1308 * @param parentspecifier either a CSID or one of the urn forms
1309 * @param itemspecifier either a CSID or one of the urn forms
1312 * @return the info for the referencing objects
1315 @Path("{csid}/items/{itemcsid}/refObjs")
1316 @Produces("application/xml")
1317 public AuthorityRefDocList getReferencingObjects(
1318 @PathParam("csid") String parentSpecifier,
1319 @PathParam("itemcsid") String itemSpecifier,
1320 @Context UriInfo uriInfo) {
1321 uriInfo = new UriInfoWrapper(uriInfo);
1322 AuthorityRefDocList authRefDocList = null;
1324 authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriInfo, PAGE_NUM_FROM_QUERYPARAMS, PAGE_SIZE_FROM_QUERYPARAMS, true, true);
1325 } catch (Exception e) {
1326 throw bigReThrow(e, ServiceMessages.GET_FAILED);
1329 if (authRefDocList == null) {
1330 Response response = Response.status(Response.Status.NOT_FOUND).entity(
1331 "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1332 "text/plain").build();
1333 throw new CSWebApplicationException(response);
1335 return authRefDocList;
1338 public AuthorityRefDocList getReferencingObjects(
1339 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1340 String parentspecifier,
1341 String itemspecifier,
1345 boolean useDefaultOrderByClause,
1346 boolean computeTotal) throws Exception {
1347 AuthorityRefDocList authRefDocList = null;
1349 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1350 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1352 // Merge parts of existing context with our new context
1354 if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1355 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If one exists, use the existing repo session
1356 ctx.setProperties(existingContext.getProperties());
1359 String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1360 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1362 // Remove the "type" property from the query params
1363 List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1364 if (serviceTypes == null || serviceTypes.isEmpty()) {
1365 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1368 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1369 authRefDocList = handler.getReferencingObjects(ctx, serviceTypes, getRefPropName(), itemcsid, pageNum, pageSize, useDefaultOrderByClause, computeTotal);
1371 return authRefDocList;
1375 * Gets the authority terms used in the indicated Authority item.
1377 * @param parentspecifier either a CSID or one of the urn forms
1378 * @param itemspecifier either a CSID or one of the urn forms
1379 * @param ui passed to include additional parameters, like pagination controls
1381 * @return the authority refs for the Authority item.
1384 @Path("{csid}/items/{itemcsid}/authorityrefs")
1385 @Produces("application/xml")
1386 public AuthorityRefList getAuthorityItemAuthorityRefs(
1387 @PathParam("csid") String parentspecifier,
1388 @PathParam("itemcsid") String itemspecifier,
1389 @Context UriInfo uriInfo) {
1390 uriInfo = new UriInfoWrapper(uriInfo);
1391 AuthorityRefList authRefList = null;
1394 // Note that we have to create the service context for the Items, not the main service
1395 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1396 String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1397 // We omit the parentShortId, only needed when doing a create...
1398 DocumentModelHandler<?, AbstractCommonList> handler =
1399 (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1401 String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1403 List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1404 authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1405 } catch (Exception e) {
1406 throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1413 * Synchronizes a local authority item with a share authority server (SAS) item.
1415 * @param parentIdentifier
1416 * @param itemIdentifier
1420 private PoxPayloadOut synchronizeItem(
1421 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1422 String parentIdentifier,
1423 String itemIdentifier,
1424 boolean syncHierarchicalRelationships) throws Exception {
1425 PoxPayloadOut result = null;
1426 AuthorityItemSpecifier specifier;
1427 boolean neededSync = false;
1429 CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1430 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1431 handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1432 handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1433 handler.setShouldSyncHierarchicalRelationships(syncHierarchicalRelationships);
1434 // Create an authority item specifier
1435 Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1436 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1437 specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1439 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1440 if (neededSync == true) {
1441 result = (PoxPayloadOut) ctx.getOutput();
1448 * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1449 * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1450 * local authority. The parent context was created for the authority (parent) because the sync started there.
1451 * @param existingCtx
1452 * @param parentIdentifier
1453 * @param itemIdentifier
1457 public PoxPayloadOut synchronizeItemWithExistingContext(
1458 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1459 String parentIdentifier,
1460 String itemIdentifier,
1461 boolean syncHierarchicalRelationships
1462 ) throws Exception {
1463 PoxPayloadOut result = null;
1465 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1466 existingCtx.getResourceMap(),
1467 existingCtx.getUriInfo());
1468 if (existingCtx.getCurrentRepositorySession() != null) {
1469 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1472 result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
1478 * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1480 * @param specifier either CSIDs and/or one of the urn forms
1482 * @return the authority item if it was updated/synchronized with SAS item; otherwise empty
1485 @Path("{csid}/items/{itemcsid}/sync")
1486 public byte[] synchronizeItem(
1487 @Context ResourceMap resourceMap,
1488 @Context UriInfo uriInfo,
1489 @PathParam("csid") String parentIdentifier,
1490 @PathParam("itemcsid") String itemIdentifier) {
1491 uriInfo = new UriInfoWrapper(uriInfo);
1493 boolean neededSync = false;
1494 PoxPayloadOut payloadOut = null;
1497 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1498 payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier, true);
1499 if (payloadOut != null) {
1502 } catch (Exception e) {
1503 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1507 // If a sync was needed and was successful, return a copy of the updated resource. Acts like an UPDATE.
1509 if (neededSync == true) {
1510 result = payloadOut.getBytes();
1512 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1513 itemIdentifier).getBytes();
1514 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1515 throw new CSWebApplicationException(response);
1522 * Update authorityItem.
1524 * @param parentspecifier either a CSID or one of the urn forms
1525 * @param itemspecifier either a CSID or one of the urn forms
1527 * @return the multipart output
1530 @Path("{csid}/items/{itemcsid}")
1531 public byte[] updateAuthorityItem(
1532 @Context ResourceMap resourceMap,
1533 @Context UriInfo uriInfo,
1534 @PathParam("csid") String parentSpecifier,
1535 @PathParam("itemcsid") String itemSpecifier,
1536 String xmlPayload) {
1537 return updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, xmlPayload);
1540 public byte[] updateAuthorityItem(
1541 ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
1542 ResourceMap resourceMap,
1544 String parentSpecifier,
1545 String itemSpecifier,
1546 String xmlPayload) {
1547 uriInfo = new UriInfoWrapper(uriInfo);
1548 PoxPayloadOut result = null;
1551 PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1552 result = updateAuthorityItem(parentCtx, null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1553 AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing
1554 AuthorityServiceUtils.NO_CHANGE, // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1555 AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1556 } catch (Exception e) {
1557 throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1560 return result.getBytes();
1564 * Delete authorityItem.
1566 * @param parentIdentifier the parentcsid
1567 * @param itemIdentifier the itemcsid
1569 * @return the response
1572 @Path("{csid}/items/{itemcsid}")
1573 public Response deleteAuthorityItem(
1574 @Context UriInfo uriInfo,
1575 @PathParam("csid") String parentIdentifier,
1576 @PathParam("itemcsid") String itemIdentifier) {
1577 uriInfo = new UriInfoWrapper(uriInfo);
1578 Response result = null;
1580 ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1581 ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1582 if (logger.isDebugEnabled()) {
1583 logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1587 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1588 deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1589 result = Response.status(HttpResponseCodes.SC_OK).build();
1590 } catch (Exception e) {
1591 throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1597 public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1598 String parentIdentifier,
1599 String itemIdentifier,
1600 boolean shouldUpdateRevNumber) throws Exception {
1601 return deleteAuthorityItem(existingCtx, parentIdentifier, itemIdentifier, shouldUpdateRevNumber, true);
1606 * @param existingCtx
1607 * @param parentIdentifier
1608 * @param itemIdentifier
1611 public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1612 String parentIdentifier,
1613 String itemIdentifier,
1614 boolean shouldUpdateRevNumber,
1615 boolean rollbackOnException
1616 ) throws Exception {
1617 boolean result = true;
1619 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1620 ctx.setRollbackOnException(rollbackOnException);
1621 if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1622 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1623 ctx.setProperties(existingCtx.getProperties());
1626 String parentcsid = null;
1628 parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1629 } catch (DocumentNotFoundException de) {
1630 String msg = String.format("Could not find parent with ID='%s' when trying to delete item ID='%s'",
1631 parentIdentifier, itemIdentifier);
1635 String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1637 AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
1638 handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1639 result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1645 @Path("{csid}/items/{itemcsid}/" + hierarchy)
1646 @Produces("application/xml")
1647 public String getHierarchy(
1648 @PathParam("csid") String parentIdentifier,
1649 @PathParam("itemcsid") String itemIdentifier,
1650 @Context UriInfo uriInfo) throws Exception {
1651 uriInfo = new UriInfoWrapper(uriInfo);
1652 String result = null;
1656 // 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...?
1658 String calledUri = uriInfo.getPath();
1659 String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1660 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1662 String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1663 String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1665 String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1666 if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1667 result = Hierarchy.surface(ctx, itemcsid, uri);
1669 result = Hierarchy.dive(ctx, itemcsid, uri);
1671 } catch (Exception e) {
1672 throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1683 public String getItemDocType(String tenantId) {
1684 return getDocType(tenantId, getItemServiceName());
1688 * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1689 * for the current resource, for all tenants
1691 * @return a map of URI templates for the current resource, for all tenants
1694 public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1695 Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1696 super.getUriRegistryEntries();
1697 List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1698 for (String tenantId : tenantIds) {
1699 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1701 return uriRegistryEntriesMap;
1708 public ServiceDescription getDescription(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1709 ServiceDescription result = super.getDescription(ctx);
1710 result.setSubresourceDocumentType(this.getItemDocType(ctx.getTenantId()));
1714 public Response createAuthority(String xmlPayload) {
1715 return this.createAuthority(null, null, xmlPayload);
1718 protected String getCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, Specifier specifier) throws Exception {
1722 ctx = createServiceContext(getServiceName());
1725 if (specifier.form == SpecifierForm.CSID) {
1726 csid = specifier.value;
1728 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, specifier.value);
1729 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);