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.Response;
32 import org.collectionspace.services.client.AbstractCommonListUtils;
33 import org.collectionspace.services.client.AuthorityClient;
34 import org.collectionspace.services.client.CollectionSpaceClient;
35 import org.collectionspace.services.client.PayloadInputPart;
36 import org.collectionspace.services.client.VocabularyClient;
37 import org.collectionspace.services.client.PoxPayloadIn;
38 import org.collectionspace.services.client.PoxPayloadOut;
39 import org.collectionspace.services.client.XmlTools;
40 import org.collectionspace.services.client.workflow.WorkflowClient;
41 import org.collectionspace.services.common.ResourceMap;
42 import org.collectionspace.services.common.api.RefName;
43 import org.collectionspace.services.common.api.RefName.Authority;
44 import org.collectionspace.services.common.api.RefNameUtils;
45 import org.collectionspace.services.common.api.RefNameUtils.AuthorityInfo;
46 import org.collectionspace.services.common.api.RefNameUtils.AuthorityTermInfo;
47 import org.collectionspace.services.common.api.Tools;
48 import org.collectionspace.services.common.context.ServiceContext;
49 import org.collectionspace.services.common.document.DocumentException;
50 import org.collectionspace.services.common.document.DocumentHandler;
51 import org.collectionspace.services.common.document.DocumentNotFoundException;
52 import org.collectionspace.services.common.document.DocumentReferenceException;
53 import org.collectionspace.services.common.document.DocumentWrapper;
54 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
55 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
56 import org.collectionspace.services.common.vocabulary.AuthorityResource;
57 import org.collectionspace.services.common.vocabulary.AuthorityServiceUtils;
58 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
59 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
60 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
61 import org.collectionspace.services.config.service.ObjectPartType;
62 import org.collectionspace.services.jaxb.AbstractCommonList;
63 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
64 import org.collectionspace.services.lifecycle.TransitionDef;
65 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
66 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
67 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
68 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
69 import org.dom4j.Document;
70 import org.dom4j.Element;
71 import org.nuxeo.ecm.core.api.ClientException;
72 import org.nuxeo.ecm.core.api.DocumentModel;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
77 * AuthorityDocumentModelHandler
79 * $LastChangedRevision: $
82 public abstract class AuthorityDocumentModelHandler<AuthCommon>
83 extends NuxeoDocumentModelHandler<AuthCommon> {
85 private final Logger logger = LoggerFactory.getLogger(AuthorityDocumentModelHandler.class);
87 protected String authorityCommonSchemaName;
88 protected String authorityItemCommonSchemaName;
89 protected boolean shouldUpdateRevNumber = true; // default to updating the revision number
91 public AuthorityDocumentModelHandler(String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
92 this.authorityCommonSchemaName = authorityCommonSchemaName;
93 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
96 public void setShouldUpdateRevNumber(boolean flag) {
97 this.shouldUpdateRevNumber = flag;
100 public boolean getShouldUpdateRevNumber() {
101 return this.shouldUpdateRevNumber;
105 * The entity type expected from the JAX-RS Response object
107 public Class<String> getEntityResponseType() {
112 public void prepareSync() throws Exception {
113 this.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev nums on sync operations
116 protected PayloadInputPart extractPart(Response res, String partLabel)
118 PoxPayloadIn input = new PoxPayloadIn((String)res.readEntity(getEntityResponseType()));
119 PayloadInputPart payloadInputPart = input.getPart(partLabel);
120 if (payloadInputPart == null) {
121 logger.error("Part " + partLabel + " was unexpectedly null.");
123 return payloadInputPart;
127 public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
128 boolean result = false;
129 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
130 Specifier specifier = (Specifier) wrapDoc.getWrappedObject();
132 // Get the rev number of the authority so we can compare with rev number of shared authority
134 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, specifier);
135 Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
136 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
138 // Using the short ID of the local authority, create a URN specifier to retrieve the SAS authority
140 Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, shortId);
141 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(ctx, sasSpecifier, getEntityResponseType());
143 // If the authority on the SAS is newer, synch all the items and then the authority record as well
146 Long sasRev = getRevision(sasPayloadIn);
147 if (sasRev > localRev) {
149 // First, sync all the authority items
151 syncAllItems(ctx, sasSpecifier);
153 // Next, sync the authority resource/record itself
155 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
156 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
157 PoxPayloadOut payloadOut = authorityResource.update(ctx, ctx.getResourceMap(), ctx.getUriInfo(), docModel.getName(),
159 if (payloadOut != null) {
160 ctx.setOutput(payloadOut);
169 * Get the list of authority items from the remote shared authority server (SAS) and try
170 * to synchronize them with the local items. If items exist on the remote but not the local, we'll create them.
172 protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
176 int alreadySynched = 0;
178 int totalItemsProcessed = 0;
179 ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
181 // Iterate over the list of items/terms in the remote authority
183 PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
184 List<Element> itemList = getItemList(sasPayloadInItemList);
185 if (itemList != null) {
186 for (Element e:itemList) {
187 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
188 itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
189 long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
192 } else if (status == 0) {
197 totalItemsProcessed++;
201 // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
202 // locally. Subtract (remove) the list of remote items from the list of local items to determine which
203 // of the remote items have been hard deleted.
205 ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
206 itemsInLocalAuthority.removeAll(itemsInRemoteAuthority);
207 if (itemsInLocalAuthority.size() > 0) {
208 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)
210 // We now need to either hard-deleted or deprecate the remaining authorities
212 long processed = deleteOrDeprecateItems(ctx, remainingItems);
213 if (processed != remainingItems.size()) {
214 throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
218 // We need to synchronize the hierarchy relationships
220 itemList = getItemList(sasPayloadInItemList); // Really need to re-request the sasPayload? I don't think so.
221 if (itemList != null) {
222 for (Element e:itemList) {
223 String remoteRefName = XmlTools.getElementValue(e, "refName");
224 itemsInRemoteAuthority.add(remoteRefName);
225 long status = syncRemoteItemRelationshipsWithLocalItem(ctx, remoteRefName);
228 } else if (status == 0) {
233 totalItemsProcessed++;
237 logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
238 logger.info(String.format("Number of items synchronized: %d", synched));
239 logger.info(String.format("Number of items created during sync: %d", created));
240 logger.info(String.format("Number not needing synchronization: %d", alreadySynched));
246 * This method should only be used as part of a SAS synch operation.
252 private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList<String> refNameList) throws Exception {
255 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
256 for (String itemRefName:refNameList) {
257 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
258 AuthorityItemSpecifier authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityTermInfo.inAuthority.name,
259 authorityTermInfo.name);
261 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
263 authorityResource.deleteAuthorityItem(ctx,
264 Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name),
265 Specifier.createShortIdURNValue(authorityTermInfo.name),
266 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)
268 } catch (DocumentReferenceException de) {
269 logger.info(String.format("Authority item '%s' has existing references and cannot be removed during sync.",
271 boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
272 authorityItemSpecificer);
273 if (marked == true) {
276 } catch (Exception e) {
277 logger.warn(String.format("Unable to delete authority item '%s'", itemRefName), e);
282 if (logger.isWarnEnabled() == true) {
283 if (result != refNameList.size()) {
284 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.",
285 result, refNameList.size()));
293 * Gets the list of SAS related items in the local authority. We exlude items with the "proposed" flags because
294 * we want a list with only SAS created items.
296 * We need to add pagination support to this call!!!
299 * @param authoritySpecifier
303 private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception {
304 ArrayList<String> result = new ArrayList<String>();
306 ResourceMap resourceMap = ctx.getResourceMap();
307 String resourceName = ctx.getClient().getServiceName();
308 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
309 AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), ctx.getUriInfo());
311 List<ListItem> listItemList = acl.getListItem();
312 for (ListItem listItem:listItemList) {
313 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
314 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
315 result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
322 private Boolean getBooleanValue(ListItem listItem, String name) {
323 Boolean result = null;
325 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
327 result = Boolean.valueOf(value);
333 private String getStringValue(ListItem listItem, String name) {
334 return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
338 * This method should only be used during a SAS synchronization request.
341 * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
342 * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
345 protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier) throws Exception {
347 // Create a URN short ID specifier for the getting a copy of the remote authority item
349 Specifier authoritySpecifier = Specifier.getSpecifier(parentIdentifier);
350 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
351 AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(authoritySpecifier, itemSpecifier);
353 // Get the remote payload
355 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
356 ctx.getServiceName(), getEntityResponseType());
357 sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
359 // Using the payload from the remote server, create a local copy of the item
361 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
362 Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(),
363 sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM);
365 // Check the response for successful POST result
367 if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
368 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
369 itemIdentifier, parentIdentifier));
372 // Since we're creating an item that was sourced from the SAS, we need to lock it.
374 authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier,
375 WorkflowClient.WORKFLOWTRANSITION_LOCK, AuthorityServiceUtils.DONT_UPDATE_REV);
379 * Try to synchronize a remote item (using its refName) with a local item. If the local doesn't yet
380 * exist, we'll create it.
382 * -1 = sync not needed; i.e., already in sync
384 * 1 = local item was missing so we created it
390 protected long syncRemoteItemWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
393 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
395 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
396 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
397 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
399 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
401 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
402 PoxPayloadOut localItemPayloadOut;
404 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
405 } catch (DocumentNotFoundException dnf) {
407 // Document not found, means we need to create an item/term that exists only on the SAS
409 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
410 createLocalItem(ctx, parentIdentifier, itemIdentifier);
411 return 1; // exit with status of 1 means we created a new authority item
414 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
418 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
419 if (theUpdate != null) {
420 result = 0; // means we needed to sync this item with SAS
421 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
422 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
424 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
426 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
430 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
434 * Ensure the local items relationships look the same as the remote items' by synchronizing the hierarchy relationship records
435 * of the SAS item with the local item.
442 protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
445 // WARNING: THIS CODE IS NOT IMPLEMENTED YET
449 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
453 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
454 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
455 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
457 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
459 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
460 PoxPayloadOut localItemPayloadOut;
462 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
463 } catch (DocumentNotFoundException dnf) {
465 // Document not found, means we need to create an item/term that exists only on the SAS
467 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
468 createLocalItem(ctx, parentIdentifier, itemIdentifier);
469 return 1; // exit with status of 1 means we created a new authority item
472 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
476 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
477 if (theUpdate != null) {
478 result = 0; // means we needed to sync this item with SAS
479 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
480 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
482 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
484 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
488 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
494 * Request an authority item list payload from the SAS server.
501 private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
502 PoxPayloadIn result = null;
504 AuthorityClient client = (AuthorityClient) ctx.getClient();
505 Response res = client.readItemList(specifier.getURNValue(),
506 null, // partial term string
507 null // keyword string
510 int statusCode = res.getStatus();
512 // Check the status code of the response: does it match
513 // the expected response(s)?
514 if (logger.isDebugEnabled()) {
515 logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
518 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!
528 * Non standard injection of CSID into common part, since caller may access through
529 * shortId, and not know the CSID.
530 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
533 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
535 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
537 // Add the CSID to the common part
538 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
539 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
540 unQObjectProperties.put("csid", csid);
543 return unQObjectProperties;
546 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
547 super.fillAllParts(wrapDoc, action);
549 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
551 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
552 updateRevNumbers(wrapDoc);
556 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
557 DocumentModel documentModel = wrapDoc.getWrappedObject();
558 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
564 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
568 * We consider workflow state changes as changes that should bump the revision number
570 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
573 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
574 // Update the revision number
575 updateRevNumbers(wrapDoc);
579 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
580 super.handleCreate(wrapDoc);
582 // Uncomment once debugged and App layer is read to integrate
583 // Experimenting with this uncommented now ...
584 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
585 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
588 protected String buildWhereForShortId(String name) {
589 return authorityCommonSchemaName
590 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
594 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
598 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
599 boolean result = true;
601 ServiceContext ctx = this.getServiceContext();
602 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
603 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
605 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
606 if (searchResultWrapper != null) {
608 if (logger.isInfoEnabled() == true) {
609 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
610 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'",
611 shortIdentifier, searchResult.getName());
612 logger.trace(debugMsg);
615 } catch (DocumentNotFoundException e) {
616 // Not a problem, just means we couldn't find another authority with that short ID
623 * If no short identifier was provided in the input payload,
624 * generate a short identifier from the display name. Either way though,
625 * the short identifier needs to be unique.
627 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
628 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
629 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
630 String shortDisplayName = "";
631 String generateShortIdentifier = null;
632 if (Tools.isEmpty(shortIdentifier)) {
633 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
634 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
637 if (isUnique(docModel, schemaName) == false) {
638 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
639 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
640 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
641 errMsgVerb, shortId);
642 throw new DocumentException(errMsg);
647 * Generate a refName for the authority from the short identifier
650 * All refNames for authorities are generated. If a client supplies
651 * a refName, it will be overwritten during create (per this method)
652 * or discarded during update (per filterReadOnlyPropertiesForPart).
654 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
657 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
658 DocumentModel docModel = wrapDoc.getWrappedObject();
659 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
660 String refName = authority.toString();
661 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
665 public RefName.RefNameInterface getRefName(ServiceContext ctx,
666 DocumentModel docModel) {
667 RefName.RefNameInterface refname = null;
670 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
671 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
672 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
673 ctx.getServiceName(),
674 null, // Only use shortId form!!!
678 } catch (Exception e) {
679 logger.error(e.getMessage(), e);
686 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
687 String result = null;
689 DocumentModel docModel = docWrapper.getWrappedObject();
690 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
691 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
692 result = refname.getDisplayName();
697 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
698 String shortIdentifier = null;
699 CoreSessionInterface repoSession = null;
700 boolean releaseSession = false;
702 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
704 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
705 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
706 DocumentModel docModel = wrapDoc.getWrappedObject();
707 if (docModel == null) {
708 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
710 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
711 } catch (ClientException ce) {
712 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
714 if (repoSession != null) {
715 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
719 return shortIdentifier;
723 * Filters out selected values supplied in an update request.
725 * @param objectProps the properties filtered out from the update payload
726 * @param partMeta metadata for the object to fill
729 public void filterReadOnlyPropertiesForPart(
730 Map<String, Object> objectProps, ObjectPartType partMeta) {
731 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
732 String commonPartLabel = getServiceContext().getCommonPartLabel();
733 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
734 objectProps.remove(AuthorityJAXBSchema.CSID);
735 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
736 objectProps.remove(AuthorityJAXBSchema.REF_NAME);