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.nuxeo;
26 import java.util.ArrayList;
27 import java.util.List;
30 import javax.ws.rs.core.MultivaluedMap;
31 import javax.ws.rs.core.Response;
33 import org.collectionspace.services.client.AbstractCommonListUtils;
34 import org.collectionspace.services.client.AuthorityClient;
35 import org.collectionspace.services.client.CollectionSpaceClient;
36 import org.collectionspace.services.client.PayloadInputPart;
37 import org.collectionspace.services.client.VocabularyClient;
38 import org.collectionspace.services.client.PoxPayloadIn;
39 import org.collectionspace.services.client.PoxPayloadOut;
40 import org.collectionspace.services.client.XmlTools;
41 import org.collectionspace.services.client.workflow.WorkflowClient;
42 import org.collectionspace.services.common.ResourceMap;
43 import org.collectionspace.services.common.api.CommonAPI;
44 import org.collectionspace.services.common.api.RefName;
45 import org.collectionspace.services.common.api.RefName.Authority;
46 import org.collectionspace.services.common.api.RefNameUtils;
47 import org.collectionspace.services.common.api.RefNameUtils.AuthorityInfo;
48 import org.collectionspace.services.common.api.RefNameUtils.AuthorityTermInfo;
49 import org.collectionspace.services.common.api.Tools;
50 import org.collectionspace.services.common.context.ServiceContext;
51 import org.collectionspace.services.common.document.DocumentException;
52 import org.collectionspace.services.common.document.DocumentHandler;
53 import org.collectionspace.services.common.document.DocumentNotFoundException;
54 import org.collectionspace.services.common.document.DocumentReferenceException;
55 import org.collectionspace.services.common.document.DocumentWrapper;
56 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
57 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
58 import org.collectionspace.services.common.vocabulary.AuthorityResource;
59 import org.collectionspace.services.common.vocabulary.AuthorityServiceUtils;
60 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
61 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
62 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
63 import org.collectionspace.services.config.service.ObjectPartType;
64 import org.collectionspace.services.jaxb.AbstractCommonList;
65 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
66 import org.collectionspace.services.lifecycle.TransitionDef;
67 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
68 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
69 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
70 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
71 import org.dom4j.Document;
72 import org.dom4j.Element;
73 import org.nuxeo.ecm.core.api.ClientException;
74 import org.nuxeo.ecm.core.api.DocumentModel;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
79 * AuthorityDocumentModelHandler
81 * $LastChangedRevision: $
84 public abstract class AuthorityDocumentModelHandler<AuthCommon>
85 extends NuxeoDocumentModelHandler<AuthCommon> {
87 private final Logger logger = LoggerFactory.getLogger(AuthorityDocumentModelHandler.class);
89 protected String authorityCommonSchemaName;
90 protected String authorityItemCommonSchemaName;
91 protected boolean shouldUpdateRevNumber = true; // default to updating the revision number
93 public AuthorityDocumentModelHandler(String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
94 this.authorityCommonSchemaName = authorityCommonSchemaName;
95 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
98 public void setShouldUpdateRevNumber(boolean flag) {
99 this.shouldUpdateRevNumber = flag;
102 public boolean getShouldUpdateRevNumber() {
103 return this.shouldUpdateRevNumber;
107 * The entity type expected from the JAX-RS Response object
109 public Class<String> getEntityResponseType() {
114 public void prepareSync() throws Exception {
115 this.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev nums on sync operations
118 protected PayloadInputPart extractPart(Response res, String partLabel)
120 PoxPayloadIn input = new PoxPayloadIn((String)res.readEntity(getEntityResponseType()));
121 PayloadInputPart payloadInputPart = input.getPart(partLabel);
122 if (payloadInputPart == null) {
123 logger.error("Part " + partLabel + " was unexpectedly null.");
125 return payloadInputPart;
129 public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
130 boolean result = false;
131 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
132 Specifier specifier = (Specifier) wrapDoc.getWrappedObject();
134 // Get the rev number of the authority so we can compare with rev number of shared authority
136 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, specifier);
137 Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
138 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
140 // Using the short ID of the local authority, create a URN specifier to retrieve the SAS authority
142 Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, shortId);
143 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(ctx, sasSpecifier, getEntityResponseType());
145 // If the authority on the SAS is newer, synch all the items and then the authority record as well
148 Long sasRev = getRevision(sasPayloadIn);
149 if (sasRev > localRev) {
151 // First, sync all the authority items
153 syncAllItems(ctx, sasSpecifier);
155 // Next, sync the authority resource/record itself
157 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
158 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, AuthorityServiceUtils.DONT_UPDATE_REV); // Don't update the rev number, use the rev number for the SAS instance instead
159 PoxPayloadOut payloadOut = authorityResource.update(ctx, ctx.getResourceMap(), ctx.getUriInfo(), docModel.getName(),
161 if (payloadOut != null) {
162 ctx.setOutput(payloadOut);
166 // We may need to transition the authority into a replicated state the first time we sync it.
168 String workflowState = docModel.getCurrentLifeCycleState();
169 if (workflowState.contains(WorkflowClient.WORKFLOWSTATE_REPLICATED) == false) {
170 String authorityCsid = docModel.getName();
171 authorityResource.updateWorkflowWithTransition(ctx, ctx.getUriInfo(), authorityCsid, WorkflowClient.WORKFLOWTRANSITION_REPLICATE);
179 * Get the list of authority items from the remote shared authority server (SAS) and try
180 * to synchronize them with the local items. If items exist on the remote but not the local, we'll create them.
182 protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
186 int alreadySynched = 0;
188 int totalItemsProcessed = 0;
189 ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
191 // Iterate over the list of items/terms in the remote authority
193 PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
194 List<Element> itemList = getItemList(sasPayloadInItemList);
195 if (itemList != null) {
196 for (Element e:itemList) {
197 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
198 itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
199 long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
202 } else if (status == 0) {
207 totalItemsProcessed++;
211 // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
212 // locally. Subtract (remove) the list of remote items from the list of local items to determine which
213 // of the remote items have been hard deleted.
215 ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
216 itemsInLocalAuthority.removeAll(itemsInRemoteAuthority);
217 if (itemsInLocalAuthority.size() > 0) {
218 ArrayList<String> remainingItems = itemsInLocalAuthority; // now a subset of local items that no longer exist on the SAS, so we need to try to delete them (or mark them as deprecated if they still have records referencing them)
220 // We now need to either hard-delete or deprecate the remaining authorities
222 long processed = deleteOrDeprecateItems(ctx, sasAuthoritySpecifier, remainingItems);
223 if (processed != remainingItems.size()) {
224 throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
228 // Now that we've sync'd all the items, we need to synchronize the hierarchy relationships
230 for (String itemShortId:itemsInRemoteAuthority) {
231 long status = syncRemoteItemRelationshipsWithLocalItem(ctx, sasAuthoritySpecifier, itemShortId);
234 } else if (status == 0) {
239 totalItemsProcessed++;
242 logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
243 logger.info(String.format("Number of items synchronized: %d", synched));
244 logger.info(String.format("Number of items created during sync: %d", created));
245 logger.info(String.format("Number not needing synchronization: %d", alreadySynched));
251 * This method should only be used as part of a SAS synch operation.
257 @SuppressWarnings("rawtypes")
258 private long deleteOrDeprecateItems(ServiceContext ctx, Specifier authoritySpecifier, ArrayList<String> itemShortIdList) throws Exception {
260 AuthorityItemSpecifier authorityItemSpecificer = null;
262 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
263 for (String itemShortId:itemShortIdList) {
264 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
266 authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authoritySpecifier.value,
268 authorityResource.deleteAuthorityItem(ctx,
269 authorityItemSpecificer.getParentSpecifier().getURNValue(),
270 authorityItemSpecificer.getItemSpecifier().getURNValue(),
271 AuthorityServiceUtils.DONT_UPDATE_REV); // Since we're sync'ing, we shouldn't update the revision number (obviously this only applies to soft-deletes since hard-deletes destroy the record)
273 } catch (DocumentReferenceException de) {
274 logger.info(String.format("Authority item with '%s' has existing references and cannot be removed during sync.",
275 authorityItemSpecificer), de);
276 boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
277 authorityItemSpecificer);
278 if (marked == true) {
281 } catch (Exception e) {
282 logger.warn(String.format("Unable to delete authority item '%s'", authorityItemSpecificer), e);
287 if (logger.isWarnEnabled() == true) {
288 if (result != itemShortIdList.size()) {
289 logger.warn(String.format("Unable to delete or deprecate some authority items during synchronization with SAS. Deleted or deprecated %d of %d. See the services log file for details.",
290 result, itemShortIdList.size()));
298 * Gets the list of SAS related items in the local authority. We exlude items with the "proposed" flags because
299 * we want a list with only SAS created items.
301 * We need to add pagination support to this call!!!
304 * @param authoritySpecifier
308 private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception {
309 ArrayList<String> result = new ArrayList<String>();
311 ResourceMap resourceMap = ctx.getResourceMap();
312 String resourceName = ctx.getClient().getServiceName();
313 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
314 AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), ctx.getUriInfo());
316 List<ListItem> listItemList = acl.getListItem();
317 for (ListItem listItem:listItemList) {
318 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
319 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
320 result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
327 private Boolean getBooleanValue(ListItem listItem, String name) {
328 Boolean result = null;
330 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
332 result = Boolean.valueOf(value);
338 private String getStringValue(ListItem listItem, String name) {
339 return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
343 * This method should only be used during a SAS synchronization request.
346 * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
347 * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
350 protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier, Boolean syncHierarchicalRelationships) throws Exception {
352 // Create a URN short ID specifier for the getting a copy of the remote authority item
354 Specifier authoritySpecifier = Specifier.getSpecifier(parentIdentifier);
355 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
356 AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(authoritySpecifier, itemSpecifier);
358 // Get the remote payload
360 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
361 ctx.getServiceName(), getEntityResponseType(), syncHierarchicalRelationships);
362 sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
364 // Using the payload from the remote server, create a local copy of the item
366 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
367 Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(),
368 sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM);
370 // Check the response for successful POST result
372 if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
373 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
374 itemIdentifier, parentIdentifier));
377 // Since we're creating an item that was sourced from the replication server, we need to replicate it locally.
379 authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier,
380 WorkflowClient.WORKFLOWTRANSITION_REPLICATE, AuthorityServiceUtils.DONT_UPDATE_REV); // don't update the rev number of the new replicated item (use the rev number of the sourced item)
384 * Try to synchronize a remote item (using its refName) with a local item. If the local doesn't yet
385 * exist, we'll create it.
387 * -1 = sync not needed; i.e., already in sync
389 * 1 = local item was missing so we created it
395 protected long syncRemoteItemWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
398 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
400 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
401 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
402 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
404 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
406 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
407 PoxPayloadOut localItemPayloadOut;
409 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
410 } catch (DocumentNotFoundException dnf) {
412 // Document not found, means we need to create an item/term that exists only on the SAS
414 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
415 createLocalItem(ctx, parentIdentifier, itemIdentifier, AuthorityClient.DONT_INCLUDE_RELATIONS);
416 return 1; // exit with status of 1 means we created a new authority item
419 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
423 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, false);
424 if (theUpdate != null) {
425 result = 0; // means we needed to sync this item with SAS
426 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
427 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
429 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
431 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
435 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
439 * Ensure the local items relationships look the same as the remote items' by synchronizing the hierarchy relationship records
440 * of the SAS item with the local item.
447 protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, Specifier authoritySpecifier, String itemShortId) throws Exception {
450 String parentIdentifier = authoritySpecifier.getURNValue();
451 String itemIdentifier = Specifier.createShortIdURNValue(itemShortId);
453 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
455 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
456 PoxPayloadOut localItemPayloadOut;
458 MultivaluedMap queryParams = ctx.getQueryParams();
459 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
460 } catch (DocumentNotFoundException dnf) {
462 // Document not found, means we need to create an item/term that exists only on the SAS
464 logger.info(String.format("Remote item with short ID ='%s' doesn't exist locally, so we can't synchronize its relationships.", itemShortId));
468 // If we get here, we know the item exists both locally and remotely, so we need to synchronize the hierarchy relationships.
472 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, AuthorityClient.INCLUDE_RELATIONS);
473 if (theUpdate != null) {
474 result = 0; // means we needed to sync this item with SAS
475 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
476 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
478 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
480 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
484 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
490 * Request an authority item list payload from the SAS server.
497 private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
498 PoxPayloadIn result = null;
500 AuthorityClient client = (AuthorityClient) ctx.getClient();
501 Response res = client.readItemList(specifier.getURNValue(),
502 null, // partial term string
503 null // keyword string
506 int statusCode = res.getStatus();
508 // Check the status code of the response: does it match
509 // the expected response(s)?
510 if (logger.isDebugEnabled()) {
511 logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
514 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!
524 * Non standard injection of CSID into common part, since caller may access through
525 * shortId, and not know the CSID.
526 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
529 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
531 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
533 // Add the CSID to the common part
534 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
535 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
536 unQObjectProperties.put("csid", csid);
539 return unQObjectProperties;
542 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
543 super.fillAllParts(wrapDoc, action);
545 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
547 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
548 updateRevNumbers(wrapDoc);
552 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
553 DocumentModel documentModel = wrapDoc.getWrappedObject();
554 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
560 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
564 * We consider workflow state changes as changes that should bump the revision number
566 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
569 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
570 boolean updateRevNumber = this.getShouldUpdateRevNumber();
571 Boolean contextProperty = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
572 if (contextProperty != null) {
573 updateRevNumber = contextProperty;
576 if (updateRevNumber == true) { // We don't update the rev number of synchronization requests
577 updateRevNumbers(wrapDoc);
582 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
583 super.handleCreate(wrapDoc);
585 // Uncomment once debugged and App layer is read to integrate
586 // Experimenting with this uncommented now ...
587 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
588 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
591 protected String buildWhereForShortId(String name) {
592 return authorityCommonSchemaName
593 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
597 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
601 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
602 boolean result = true;
604 ServiceContext ctx = this.getServiceContext();
605 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
606 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
608 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
609 if (searchResultWrapper != null) {
611 if (logger.isInfoEnabled() == true) {
612 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
613 String debugMsg = String.format("Could not create a new authority with a short identifier of '%s', because one already exists with the same short identifer: CSID = '%s'",
614 shortIdentifier, searchResult.getName());
615 logger.trace(debugMsg);
618 } catch (DocumentNotFoundException e) {
619 // Not a problem, just means we couldn't find another authority with that short ID
626 * If no short identifier was provided in the input payload,
627 * generate a short identifier from the display name. Either way though,
628 * the short identifier needs to be unique.
630 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
631 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
632 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
633 String shortDisplayName = "";
634 String generateShortIdentifier = null;
635 if (Tools.isEmpty(shortIdentifier)) {
636 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
637 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
640 if (isUnique(docModel, schemaName) == false) {
641 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
642 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
643 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
644 errMsgVerb, shortId);
645 throw new DocumentException(errMsg);
650 * Generate a refName for the authority from the short identifier
653 * All refNames for authorities are generated. If a client supplies
654 * a refName, it will be overwritten during create (per this method)
655 * or discarded during update (per filterReadOnlyPropertiesForPart).
657 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
660 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
661 DocumentModel docModel = wrapDoc.getWrappedObject();
662 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
663 String refName = authority.toString();
664 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
668 public RefName.RefNameInterface getRefName(ServiceContext ctx,
669 DocumentModel docModel) {
670 RefName.RefNameInterface refname = null;
673 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
674 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
675 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
676 ctx.getServiceName(),
677 null, // Only use shortId form!!!
681 } catch (Exception e) {
682 logger.error(e.getMessage(), e);
689 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
690 String result = null;
692 DocumentModel docModel = docWrapper.getWrappedObject();
693 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
694 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
695 result = refname.getDisplayName();
700 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
701 String shortIdentifier = null;
702 CoreSessionInterface repoSession = null;
703 boolean releaseSession = false;
705 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
707 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
708 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
709 DocumentModel docModel = wrapDoc.getWrappedObject();
710 if (docModel == null) {
711 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
713 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
714 } catch (ClientException ce) {
715 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
717 if (repoSession != null) {
718 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
722 return shortIdentifier;
726 * Filters out selected values supplied in an update request.
728 * @param objectProps the properties filtered out from the update payload
729 * @param partMeta metadata for the object to fill
732 public void filterReadOnlyPropertiesForPart(
733 Map<String, Object> objectProps, ObjectPartType partMeta) {
734 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
735 String commonPartLabel = getServiceContext().getCommonPartLabel();
736 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
737 objectProps.remove(AuthorityJAXBSchema.CSID);
738 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
739 objectProps.remove(AuthorityJAXBSchema.REF_NAME);