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 if (docModel != null) {
138 Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
139 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
141 // Using the short ID of the local authority, create a URN specifier to retrieve the SAS authority
143 Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, shortId);
144 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(ctx, sasSpecifier, getEntityResponseType());
146 // If the authority on the SAS is newer, synch all the items and then the authority record as well
149 Long sasRev = getRevision(sasPayloadIn);
150 if (sasRev > localRev) {
152 // First, sync all the authority items
154 syncAllItems(ctx, sasSpecifier);
156 // Next, sync the authority resource/record itself
158 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
159 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
160 PoxPayloadOut payloadOut = authorityResource.update(ctx, ctx.getResourceMap(), ctx.getUriInfo(), docModel.getName(),
162 if (payloadOut != null) {
163 ctx.setOutput(payloadOut);
167 // We may need to transition the authority into a replicated state the first time we sync it.
169 String workflowState = docModel.getCurrentLifeCycleState();
170 if (workflowState.contains(WorkflowClient.WORKFLOWSTATE_REPLICATED) == false) {
171 String authorityCsid = docModel.getName();
172 authorityResource.updateWorkflowWithTransition(ctx, ctx.getUriInfo(), authorityCsid, WorkflowClient.WORKFLOWTRANSITION_REPLICATE);
176 String errMsg = String.format("Authority of type '%s' with identifier '%s' does not exist.",
177 getServiceContext().getServiceName(), specifier.getURNValue());
178 logger.debug(errMsg);
179 throw new DocumentException(errMsg);
186 * Get the list of authority items from the remote shared authority server (SAS) and try
187 * to synchronize them with the local items. If items exist on the remote but not the local, we'll create them.
189 protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
193 int alreadySynched = 0;
195 int totalItemsProcessed = 0;
196 ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
198 // Iterate over the list of items/terms in the remote authority
200 PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
201 List<Element> itemList = getItemList(sasPayloadInItemList);
202 if (itemList != null) {
203 for (Element e:itemList) {
204 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
205 itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
206 long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
209 } else if (status == 0) {
214 totalItemsProcessed++;
218 // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
219 // locally. Subtract (remove) the list of remote items from the list of local items to determine which
220 // of the remote items have been hard deleted.
222 ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
223 itemsInLocalAuthority.removeAll(itemsInRemoteAuthority);
224 if (itemsInLocalAuthority.size() > 0) {
225 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)
227 // We now need to either hard-delete or deprecate the remaining authorities
229 long processed = deleteOrDeprecateItems(ctx, sasAuthoritySpecifier, remainingItems);
230 if (processed != remainingItems.size()) {
231 throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
235 // Now that we've sync'd all the items, we need to synchronize the hierarchy relationships
237 for (String itemShortId:itemsInRemoteAuthority) {
238 long status = syncRemoteItemRelationshipsWithLocalItem(ctx, sasAuthoritySpecifier, itemShortId);
241 } else if (status == 0) {
246 totalItemsProcessed++;
249 logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
250 logger.info(String.format("Number of items synchronized: %d", synched));
251 logger.info(String.format("Number of items created during sync: %d", created));
252 logger.info(String.format("Number not needing synchronization: %d", alreadySynched));
258 * This method should only be used as part of a SAS synch operation.
264 @SuppressWarnings("rawtypes")
265 private long deleteOrDeprecateItems(ServiceContext ctx, Specifier authoritySpecifier, ArrayList<String> itemShortIdList) throws Exception {
267 AuthorityItemSpecifier authorityItemSpecificer = null;
269 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
270 for (String itemShortId:itemShortIdList) {
271 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
273 authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authoritySpecifier.value,
275 authorityResource.deleteAuthorityItem(ctx,
276 authorityItemSpecificer.getParentSpecifier().getURNValue(),
277 authorityItemSpecificer.getItemSpecifier().getURNValue(),
278 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)
280 } catch (DocumentReferenceException de) {
281 logger.info(String.format("Authority item with '%s' has existing references and cannot be removed during sync.",
282 authorityItemSpecificer), de);
283 boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
284 authorityItemSpecificer);
285 if (marked == true) {
288 } catch (Exception e) {
289 logger.warn(String.format("Unable to delete authority item '%s'", authorityItemSpecificer), e);
294 if (logger.isWarnEnabled() == true) {
295 if (result != itemShortIdList.size()) {
296 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.",
297 result, itemShortIdList.size()));
305 * Gets the list of SAS related items in the local authority. We exlude items with the "proposed" flags because
306 * we want a list with only SAS created items.
308 * We need to add pagination support to this call!!!
311 * @param authoritySpecifier
315 private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception {
316 ArrayList<String> result = new ArrayList<String>();
318 ResourceMap resourceMap = ctx.getResourceMap();
319 String resourceName = ctx.getClient().getServiceName();
320 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
321 AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), ctx.getUriInfo());
323 List<ListItem> listItemList = acl.getListItem();
324 for (ListItem listItem:listItemList) {
325 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
326 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
327 result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
334 private Boolean getBooleanValue(ListItem listItem, String name) {
335 Boolean result = null;
337 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
339 result = Boolean.valueOf(value);
345 private String getStringValue(ListItem listItem, String name) {
346 return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
350 * This method should only be used during a SAS synchronization request.
353 * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
354 * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
357 protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier, Boolean syncHierarchicalRelationships) throws Exception {
359 // Create a URN short ID specifier for the getting a copy of the remote authority item
361 Specifier authoritySpecifier = Specifier.getSpecifier(parentIdentifier);
362 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
363 AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(authoritySpecifier, itemSpecifier);
365 // Get the remote payload
367 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
368 ctx.getServiceName(), getEntityResponseType(), syncHierarchicalRelationships);
369 sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
371 // Using the payload from the remote server, create a local copy of the item
373 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
374 Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(),
375 sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM);
377 // Check the response for successful POST result
379 if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
380 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
381 itemIdentifier, parentIdentifier));
384 // Since we're creating an item that was sourced from the replication server, we need to replicate it locally.
386 authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier,
387 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)
391 * Try to synchronize a remote item (using its refName) with a local item. If the local doesn't yet
392 * exist, we'll create it.
394 * -1 = sync not needed; i.e., already in sync
396 * 1 = local item was missing so we created it
402 protected long syncRemoteItemWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
405 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
407 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
408 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
409 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
411 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
413 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
414 PoxPayloadOut localItemPayloadOut;
416 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
417 } catch (DocumentNotFoundException dnf) {
419 // Document not found, means we need to create an item/term that exists only on the SAS
421 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
422 createLocalItem(ctx, parentIdentifier, itemIdentifier, AuthorityClient.DONT_INCLUDE_RELATIONS);
423 return 1; // exit with status of 1 means we created a new authority item
426 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
430 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, false);
431 if (theUpdate != null) {
432 result = 0; // means we needed to sync this item with SAS
433 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
434 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
436 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
438 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
442 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
446 * Ensure the local items relationships look the same as the remote items' by synchronizing the hierarchy relationship records
447 * of the SAS item with the local item.
454 protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, Specifier authoritySpecifier, String itemShortId) throws Exception {
457 String parentIdentifier = authoritySpecifier.getURNValue();
458 String itemIdentifier = Specifier.createShortIdURNValue(itemShortId);
460 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
462 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
463 PoxPayloadOut localItemPayloadOut;
465 MultivaluedMap queryParams = ctx.getQueryParams();
466 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
467 } catch (DocumentNotFoundException dnf) {
469 // Document not found, means we need to create an item/term that exists only on the SAS
471 logger.info(String.format("Remote item with short ID ='%s' doesn't exist locally, so we can't synchronize its relationships.", itemShortId));
475 // If we get here, we know the item exists both locally and remotely, so we need to synchronize the hierarchy relationships.
479 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, AuthorityClient.INCLUDE_RELATIONS);
480 if (theUpdate != null) {
481 result = 0; // means we needed to sync this item with SAS
482 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
483 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
485 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
487 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
491 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
497 * Request an authority item list payload from the SAS server.
504 private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
505 PoxPayloadIn result = null;
507 AuthorityClient client = (AuthorityClient) ctx.getClient();
508 Response res = client.readItemList(specifier.getURNValue(),
509 null, // partial term string
510 null // keyword string
513 int statusCode = res.getStatus();
515 // Check the status code of the response: does it match
516 // the expected response(s)?
517 if (logger.isDebugEnabled()) {
518 logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
521 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!
531 * Non standard injection of CSID into common part, since caller may access through
532 * shortId, and not know the CSID.
533 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
536 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
538 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
540 // Add the CSID to the common part
541 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
542 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
543 unQObjectProperties.put("csid", csid);
546 return unQObjectProperties;
549 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
550 super.fillAllParts(wrapDoc, action);
552 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
554 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
555 updateRevNumbers(wrapDoc);
559 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
560 DocumentModel documentModel = wrapDoc.getWrappedObject();
561 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
567 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
571 * We consider workflow state changes as changes that should bump the revision number
573 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
576 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
577 boolean updateRevNumber = this.getShouldUpdateRevNumber();
578 Boolean contextProperty = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
579 if (contextProperty != null) {
580 updateRevNumber = contextProperty;
583 if (updateRevNumber == true) { // We don't update the rev number of synchronization requests
584 updateRevNumbers(wrapDoc);
589 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
590 super.handleCreate(wrapDoc);
592 // Uncomment once debugged and App layer is read to integrate
593 // Experimenting with this uncommented now ...
594 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
595 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
598 protected String buildWhereForShortId(String name) {
599 return authorityCommonSchemaName
600 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
604 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
608 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
609 boolean result = true;
611 ServiceContext ctx = this.getServiceContext();
612 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
613 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
615 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
616 if (searchResultWrapper != null) {
618 if (logger.isInfoEnabled() == true) {
619 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
620 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'",
621 shortIdentifier, searchResult.getName());
622 logger.trace(debugMsg);
625 } catch (DocumentNotFoundException e) {
626 // Not a problem, just means we couldn't find another authority with that short ID
633 * If no short identifier was provided in the input payload,
634 * generate a short identifier from the display name. Either way though,
635 * the short identifier needs to be unique.
637 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
638 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
639 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
640 String shortDisplayName = "";
641 String generateShortIdentifier = null;
642 if (Tools.isEmpty(shortIdentifier)) {
643 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
644 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
647 if (isUnique(docModel, schemaName) == false) {
648 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
649 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
650 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
651 errMsgVerb, shortId);
652 throw new DocumentException(errMsg);
657 * Generate a refName for the authority from the short identifier
660 * All refNames for authorities are generated. If a client supplies
661 * a refName, it will be overwritten during create (per this method)
662 * or discarded during update (per filterReadOnlyPropertiesForPart).
664 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
667 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
668 DocumentModel docModel = wrapDoc.getWrappedObject();
669 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
670 String refName = authority.toString();
671 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
675 public RefName.RefNameInterface getRefName(ServiceContext ctx,
676 DocumentModel docModel) {
677 RefName.RefNameInterface refname = null;
680 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
681 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
682 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
683 ctx.getServiceName(),
684 null, // Only use shortId form!!!
688 } catch (Exception e) {
689 logger.error(e.getMessage(), e);
696 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
697 String result = null;
699 DocumentModel docModel = docWrapper.getWrappedObject();
700 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
701 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
702 result = refname.getDisplayName();
707 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
708 String shortIdentifier = null;
709 CoreSessionInterface repoSession = null;
710 boolean releaseSession = false;
712 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
714 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
715 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
716 DocumentModel docModel = wrapDoc.getWrappedObject();
717 if (docModel == null) {
718 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
720 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
721 } catch (ClientException ce) {
722 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
724 if (repoSession != null) {
725 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
729 return shortIdentifier;
733 * Filters out selected values supplied in an update request.
735 * @param objectProps the properties filtered out from the update payload
736 * @param partMeta metadata for the object to fill
739 public void filterReadOnlyPropertiesForPart(
740 Map<String, Object> objectProps, ObjectPartType partMeta) {
741 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
742 String commonPartLabel = getServiceContext().getCommonPartLabel();
743 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
744 objectProps.remove(AuthorityJAXBSchema.CSID);
745 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
746 objectProps.remove(AuthorityJAXBSchema.REF_NAME);