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 String authorityCsid = docModel.getName();
136 Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
137 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
139 // Using the short ID of the local authority, create a URN specifier to retrieve the SAS authority
141 Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, shortId);
142 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(ctx, sasSpecifier, getEntityResponseType());
144 // If the authority on the SAS is newer, synch all the items and then the authority record as well
147 Long sasRev = getRevision(sasPayloadIn);
148 if (sasRev > localRev) {
150 // First, sync all the authority items
152 syncAllItems(ctx, sasSpecifier);
154 // Next, sync the authority resource/record itself
156 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
157 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
158 PoxPayloadOut payloadOut = authorityResource.update(ctx, ctx.getResourceMap(), ctx.getUriInfo(), docModel.getName(),
160 if (payloadOut != null) {
161 ctx.setOutput(payloadOut);
165 // We need to transition the authority into a replicated state now that we've sync'd it.
167 authorityResource.updateWorkflowWithTransition(ctx, authorityCsid, WorkflowClient.WORKFLOWTRANSITION_REPLICATE);
174 * Get the list of authority items from the remote shared authority server (SAS) and try
175 * to synchronize them with the local items. If items exist on the remote but not the local, we'll create them.
177 protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
181 int alreadySynched = 0;
183 int totalItemsProcessed = 0;
184 ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
186 // Iterate over the list of items/terms in the remote authority
188 PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
189 List<Element> itemList = getItemList(sasPayloadInItemList);
190 if (itemList != null) {
191 for (Element e:itemList) {
192 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
193 itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
194 long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
197 } else if (status == 0) {
202 totalItemsProcessed++;
206 // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
207 // locally. Subtract (remove) the list of remote items from the list of local items to determine which
208 // of the remote items have been hard deleted.
210 ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
211 itemsInLocalAuthority.removeAll(itemsInRemoteAuthority);
212 if (itemsInLocalAuthority.size() > 0) {
213 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)
215 // We now need to either hard-deleted or deprecate the remaining authorities
217 long processed = deleteOrDeprecateItems(ctx, remainingItems);
218 if (processed != remainingItems.size()) {
219 throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
223 // We need to synchronize the hierarchy relationships
225 itemList = getItemList(sasPayloadInItemList); // Really need to re-request the sasPayload? I don't think so.
226 if (itemList != null) {
227 for (Element e:itemList) {
228 String remoteRefName = XmlTools.getElementValue(e, "refName");
229 itemsInRemoteAuthority.add(remoteRefName);
230 long status = syncRemoteItemRelationshipsWithLocalItem(ctx, remoteRefName);
233 } else if (status == 0) {
238 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 private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList<String> refNameList) throws Exception {
260 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
261 for (String itemRefName:refNameList) {
262 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
263 AuthorityItemSpecifier authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityTermInfo.inAuthority.name,
264 authorityTermInfo.name);
266 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
268 authorityResource.deleteAuthorityItem(ctx,
269 Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name),
270 Specifier.createShortIdURNValue(authorityTermInfo.name),
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 '%s' has existing references and cannot be removed during sync.",
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'", itemRefName), e);
287 if (logger.isWarnEnabled() == true) {
288 if (result != refNameList.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, refNameList.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) 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());
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);
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);
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, String itemRefName) throws Exception {
450 // WARNING: THIS CODE IS NOT IMPLEMENTED YET
454 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
458 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
459 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
460 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
462 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
464 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
465 PoxPayloadOut localItemPayloadOut;
467 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
468 } catch (DocumentNotFoundException dnf) {
470 // Document not found, means we need to create an item/term that exists only on the SAS
472 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
473 createLocalItem(ctx, parentIdentifier, itemIdentifier);
474 return 1; // exit with status of 1 means we created a new authority item
477 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
481 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
482 if (theUpdate != null) {
483 result = 0; // means we needed to sync this item with SAS
484 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
485 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
487 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
489 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
493 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
499 * Request an authority item list payload from the SAS server.
506 private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
507 PoxPayloadIn result = null;
509 AuthorityClient client = (AuthorityClient) ctx.getClient();
510 Response res = client.readItemList(specifier.getURNValue(),
511 null, // partial term string
512 null // keyword string
515 int statusCode = res.getStatus();
517 // Check the status code of the response: does it match
518 // the expected response(s)?
519 if (logger.isDebugEnabled()) {
520 logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
523 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!
533 * Non standard injection of CSID into common part, since caller may access through
534 * shortId, and not know the CSID.
535 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
538 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
540 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
542 // Add the CSID to the common part
543 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
544 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
545 unQObjectProperties.put("csid", csid);
548 return unQObjectProperties;
551 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
552 super.fillAllParts(wrapDoc, action);
554 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
556 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
557 updateRevNumbers(wrapDoc);
561 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
562 DocumentModel documentModel = wrapDoc.getWrappedObject();
563 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
569 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
573 * We consider workflow state changes as changes that should bump the revision number
575 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
578 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
579 if (this.getShouldUpdateRevNumber() == true) { // We don't update the rev number of synchronization requests
580 updateRevNumbers(wrapDoc);
585 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
586 super.handleCreate(wrapDoc);
588 // Uncomment once debugged and App layer is read to integrate
589 // Experimenting with this uncommented now ...
590 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
591 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
594 protected String buildWhereForShortId(String name) {
595 return authorityCommonSchemaName
596 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
600 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
604 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
605 boolean result = true;
607 ServiceContext ctx = this.getServiceContext();
608 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
609 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
611 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
612 if (searchResultWrapper != null) {
614 if (logger.isInfoEnabled() == true) {
615 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
616 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'",
617 shortIdentifier, searchResult.getName());
618 logger.trace(debugMsg);
621 } catch (DocumentNotFoundException e) {
622 // Not a problem, just means we couldn't find another authority with that short ID
629 * If no short identifier was provided in the input payload,
630 * generate a short identifier from the display name. Either way though,
631 * the short identifier needs to be unique.
633 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
634 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
635 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
636 String shortDisplayName = "";
637 String generateShortIdentifier = null;
638 if (Tools.isEmpty(shortIdentifier)) {
639 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
640 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
643 if (isUnique(docModel, schemaName) == false) {
644 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
645 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
646 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
647 errMsgVerb, shortId);
648 throw new DocumentException(errMsg);
653 * Generate a refName for the authority from the short identifier
656 * All refNames for authorities are generated. If a client supplies
657 * a refName, it will be overwritten during create (per this method)
658 * or discarded during update (per filterReadOnlyPropertiesForPart).
660 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
663 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
664 DocumentModel docModel = wrapDoc.getWrappedObject();
665 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
666 String refName = authority.toString();
667 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
671 public RefName.RefNameInterface getRefName(ServiceContext ctx,
672 DocumentModel docModel) {
673 RefName.RefNameInterface refname = null;
676 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
677 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
678 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
679 ctx.getServiceName(),
680 null, // Only use shortId form!!!
684 } catch (Exception e) {
685 logger.error(e.getMessage(), e);
692 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
693 String result = null;
695 DocumentModel docModel = docWrapper.getWrappedObject();
696 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
697 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
698 result = refname.getDisplayName();
703 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
704 String shortIdentifier = null;
705 CoreSessionInterface repoSession = null;
706 boolean releaseSession = false;
708 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
710 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
711 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
712 DocumentModel docModel = wrapDoc.getWrappedObject();
713 if (docModel == null) {
714 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
716 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
717 } catch (ClientException ce) {
718 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
720 if (repoSession != null) {
721 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
725 return shortIdentifier;
729 * Filters out selected values supplied in an update request.
731 * @param objectProps the properties filtered out from the update payload
732 * @param partMeta metadata for the object to fill
735 public void filterReadOnlyPropertiesForPart(
736 Map<String, Object> objectProps, ObjectPartType partMeta) {
737 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
738 String commonPartLabel = getServiceContext().getCommonPartLabel();
739 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
740 objectProps.remove(AuthorityJAXBSchema.CSID);
741 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
742 objectProps.remove(AuthorityJAXBSchema.REF_NAME);