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);
164 // We may need to transition the authority into a replicated state the first time we sync it.
166 String workflowState = docModel.getCurrentLifeCycleState();
167 if (workflowState.contains(WorkflowClient.WORKFLOWSTATE_REPLICATED) == false) {
168 String authorityCsid = docModel.getName();
169 authorityResource.updateWorkflowWithTransition(ctx, ctx.getUriInfo(), authorityCsid, WorkflowClient.WORKFLOWTRANSITION_REPLICATE);
177 * Get the list of authority items from the remote shared authority server (SAS) and try
178 * to synchronize them with the local items. If items exist on the remote but not the local, we'll create them.
180 protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
184 int alreadySynched = 0;
186 int totalItemsProcessed = 0;
187 ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
189 // Iterate over the list of items/terms in the remote authority
191 PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
192 List<Element> itemList = getItemList(sasPayloadInItemList);
193 if (itemList != null) {
194 for (Element e:itemList) {
195 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
196 itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
197 long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
200 } else if (status == 0) {
205 totalItemsProcessed++;
209 // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
210 // locally. Subtract (remove) the list of remote items from the list of local items to determine which
211 // of the remote items have been hard deleted.
213 ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
214 itemsInLocalAuthority.removeAll(itemsInRemoteAuthority);
215 if (itemsInLocalAuthority.size() > 0) {
216 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)
218 // We now need to either hard-deleted or deprecate the remaining authorities
220 long processed = deleteOrDeprecateItems(ctx, remainingItems);
221 if (processed != remainingItems.size()) {
222 throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
226 // We need to synchronize the hierarchy relationships
228 itemList = getItemList(sasPayloadInItemList); // Really need to re-request the sasPayload? I don't think so.
229 if (itemList != null) {
230 for (Element e:itemList) {
231 String remoteRefName = XmlTools.getElementValue(e, "refName");
232 itemsInRemoteAuthority.add(remoteRefName);
233 long status = syncRemoteItemRelationshipsWithLocalItem(ctx, remoteRefName);
236 } else if (status == 0) {
241 totalItemsProcessed++;
245 logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
246 logger.info(String.format("Number of items synchronized: %d", synched));
247 logger.info(String.format("Number of items created during sync: %d", created));
248 logger.info(String.format("Number not needing synchronization: %d", alreadySynched));
254 * This method should only be used as part of a SAS synch operation.
260 private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList<String> refNameList) throws Exception {
263 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
264 for (String itemRefName:refNameList) {
265 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
266 AuthorityItemSpecifier authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityTermInfo.inAuthority.name,
267 authorityTermInfo.name);
269 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
271 authorityResource.deleteAuthorityItem(ctx,
272 Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name),
273 Specifier.createShortIdURNValue(authorityTermInfo.name),
274 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)
276 } catch (DocumentReferenceException de) {
277 logger.info(String.format("Authority item '%s' has existing references and cannot be removed during sync.",
279 boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
280 authorityItemSpecificer);
281 if (marked == true) {
284 } catch (Exception e) {
285 logger.warn(String.format("Unable to delete authority item '%s'", itemRefName), e);
290 if (logger.isWarnEnabled() == true) {
291 if (result != refNameList.size()) {
292 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.",
293 result, refNameList.size()));
301 * Gets the list of SAS related items in the local authority. We exlude items with the "proposed" flags because
302 * we want a list with only SAS created items.
304 * We need to add pagination support to this call!!!
307 * @param authoritySpecifier
311 private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception {
312 ArrayList<String> result = new ArrayList<String>();
314 ResourceMap resourceMap = ctx.getResourceMap();
315 String resourceName = ctx.getClient().getServiceName();
316 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
317 AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), ctx.getUriInfo());
319 List<ListItem> listItemList = acl.getListItem();
320 for (ListItem listItem:listItemList) {
321 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
322 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
323 result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
330 private Boolean getBooleanValue(ListItem listItem, String name) {
331 Boolean result = null;
333 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
335 result = Boolean.valueOf(value);
341 private String getStringValue(ListItem listItem, String name) {
342 return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
346 * This method should only be used during a SAS synchronization request.
349 * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
350 * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
353 protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier) throws Exception {
355 // Create a URN short ID specifier for the getting a copy of the remote authority item
357 Specifier authoritySpecifier = Specifier.getSpecifier(parentIdentifier);
358 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
359 AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(authoritySpecifier, itemSpecifier);
361 // Get the remote payload
363 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
364 ctx.getServiceName(), getEntityResponseType());
365 sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
367 // Using the payload from the remote server, create a local copy of the item
369 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
370 Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(),
371 sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM);
373 // Check the response for successful POST result
375 if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
376 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
377 itemIdentifier, parentIdentifier));
380 // Since we're creating an item that was sourced from the replication server, we need to replicate it locally.
382 authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier,
383 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)
387 * Try to synchronize a remote item (using its refName) with a local item. If the local doesn't yet
388 * exist, we'll create it.
390 * -1 = sync not needed; i.e., already in sync
392 * 1 = local item was missing so we created it
398 protected long syncRemoteItemWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
401 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
403 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
404 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
405 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
407 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
409 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
410 PoxPayloadOut localItemPayloadOut;
412 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
413 } catch (DocumentNotFoundException dnf) {
415 // Document not found, means we need to create an item/term that exists only on the SAS
417 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
418 createLocalItem(ctx, parentIdentifier, itemIdentifier);
419 return 1; // exit with status of 1 means we created a new authority item
422 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
426 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
427 if (theUpdate != null) {
428 result = 0; // means we needed to sync this item with SAS
429 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
430 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
432 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
434 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
438 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
442 * Ensure the local items relationships look the same as the remote items' by synchronizing the hierarchy relationship records
443 * of the SAS item with the local item.
450 protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
453 // WARNING: THIS CODE IS NOT IMPLEMENTED YET
457 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
461 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
462 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
463 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
465 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
467 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
468 PoxPayloadOut localItemPayloadOut;
470 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
471 } catch (DocumentNotFoundException dnf) {
473 // Document not found, means we need to create an item/term that exists only on the SAS
475 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
476 createLocalItem(ctx, parentIdentifier, itemIdentifier);
477 return 1; // exit with status of 1 means we created a new authority item
480 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
484 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
485 if (theUpdate != null) {
486 result = 0; // means we needed to sync this item with SAS
487 logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
488 parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
490 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
492 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
496 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
502 * Request an authority item list payload from the SAS server.
509 private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
510 PoxPayloadIn result = null;
512 AuthorityClient client = (AuthorityClient) ctx.getClient();
513 Response res = client.readItemList(specifier.getURNValue(),
514 null, // partial term string
515 null // keyword string
518 int statusCode = res.getStatus();
520 // Check the status code of the response: does it match
521 // the expected response(s)?
522 if (logger.isDebugEnabled()) {
523 logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
526 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!
536 * Non standard injection of CSID into common part, since caller may access through
537 * shortId, and not know the CSID.
538 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
541 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
543 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
545 // Add the CSID to the common part
546 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
547 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
548 unQObjectProperties.put("csid", csid);
551 return unQObjectProperties;
554 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
555 super.fillAllParts(wrapDoc, action);
557 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
559 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
560 updateRevNumbers(wrapDoc);
564 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
565 DocumentModel documentModel = wrapDoc.getWrappedObject();
566 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
572 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
576 * We consider workflow state changes as changes that should bump the revision number
578 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
581 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
582 boolean updateRevNumber = this.getShouldUpdateRevNumber();
583 Boolean contextProperty = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
584 if (contextProperty != null) {
585 updateRevNumber = contextProperty;
588 if (updateRevNumber == true) { // We don't update the rev number of synchronization requests
589 updateRevNumbers(wrapDoc);
594 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
595 super.handleCreate(wrapDoc);
597 // Uncomment once debugged and App layer is read to integrate
598 // Experimenting with this uncommented now ...
599 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
600 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
603 protected String buildWhereForShortId(String name) {
604 return authorityCommonSchemaName
605 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
609 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
613 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
614 boolean result = true;
616 ServiceContext ctx = this.getServiceContext();
617 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
618 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
620 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
621 if (searchResultWrapper != null) {
623 if (logger.isInfoEnabled() == true) {
624 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
625 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'",
626 shortIdentifier, searchResult.getName());
627 logger.trace(debugMsg);
630 } catch (DocumentNotFoundException e) {
631 // Not a problem, just means we couldn't find another authority with that short ID
638 * If no short identifier was provided in the input payload,
639 * generate a short identifier from the display name. Either way though,
640 * the short identifier needs to be unique.
642 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
643 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
644 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
645 String shortDisplayName = "";
646 String generateShortIdentifier = null;
647 if (Tools.isEmpty(shortIdentifier)) {
648 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
649 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
652 if (isUnique(docModel, schemaName) == false) {
653 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
654 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
655 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
656 errMsgVerb, shortId);
657 throw new DocumentException(errMsg);
662 * Generate a refName for the authority from the short identifier
665 * All refNames for authorities are generated. If a client supplies
666 * a refName, it will be overwritten during create (per this method)
667 * or discarded during update (per filterReadOnlyPropertiesForPart).
669 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
672 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
673 DocumentModel docModel = wrapDoc.getWrappedObject();
674 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
675 String refName = authority.toString();
676 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
680 public RefName.RefNameInterface getRefName(ServiceContext ctx,
681 DocumentModel docModel) {
682 RefName.RefNameInterface refname = null;
685 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
686 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
687 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
688 ctx.getServiceName(),
689 null, // Only use shortId form!!!
693 } catch (Exception e) {
694 logger.error(e.getMessage(), e);
701 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
702 String result = null;
704 DocumentModel docModel = docWrapper.getWrappedObject();
705 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
706 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
707 result = refname.getDisplayName();
712 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
713 String shortIdentifier = null;
714 CoreSessionInterface repoSession = null;
715 boolean releaseSession = false;
717 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
719 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
720 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
721 DocumentModel docModel = wrapDoc.getWrappedObject();
722 if (docModel == null) {
723 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
725 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
726 } catch (ClientException ce) {
727 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
729 if (repoSession != null) {
730 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
734 return shortIdentifier;
738 * Filters out selected values supplied in an update request.
740 * @param objectProps the properties filtered out from the update payload
741 * @param partMeta metadata for the object to fill
744 public void filterReadOnlyPropertiesForPart(
745 Map<String, Object> objectProps, ObjectPartType partMeta) {
746 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
747 String commonPartLabel = getServiceContext().getCommonPartLabel();
748 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
749 objectProps.remove(AuthorityJAXBSchema.CSID);
750 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
751 objectProps.remove(AuthorityJAXBSchema.REF_NAME);