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.apache.commons.httpclient.HttpStatus;
34 import org.collectionspace.services.client.AbstractCommonListUtils;
35 import org.collectionspace.services.client.AuthorityClient;
36 import org.collectionspace.services.client.PayloadInputPart;
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.AuthorityTermInfo;
46 import org.collectionspace.services.common.api.Tools;
47 import org.collectionspace.services.common.context.ServiceContext;
48 import org.collectionspace.services.common.document.DocumentException;
49 import org.collectionspace.services.common.document.DocumentNotFoundException;
50 import org.collectionspace.services.common.document.DocumentReferenceException;
51 import org.collectionspace.services.common.document.DocumentWrapper;
52 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
53 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
54 import org.collectionspace.services.common.vocabulary.AuthorityResource;
55 import org.collectionspace.services.common.vocabulary.AuthorityServiceUtils;
56 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
57 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
58 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
59 import org.collectionspace.services.config.service.ListResultField;
60 import org.collectionspace.services.config.service.ObjectPartType;
61 import org.collectionspace.services.jaxb.AbstractCommonList;
62 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
63 import org.collectionspace.services.lifecycle.TransitionDef;
64 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
65 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
66 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
67 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
68 import org.dom4j.Element;
69 import org.nuxeo.ecm.core.api.ClientException;
70 import org.nuxeo.ecm.core.api.DocumentModel;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
75 * AuthorityDocumentModelHandler
77 * $LastChangedRevision: $
80 @SuppressWarnings("rawtypes")
81 public abstract class AuthorityDocumentModelHandler<AuthCommon>
82 extends NuxeoDocumentModelHandler<AuthCommon> {
84 private final Logger logger = LoggerFactory.getLogger(AuthorityDocumentModelHandler.class);
86 protected String authorityCommonSchemaName;
87 protected String authorityItemCommonSchemaName;
88 protected boolean shouldUpdateRevNumber = true; // default to updating the revision number
90 public AuthorityDocumentModelHandler(String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
91 this.authorityCommonSchemaName = authorityCommonSchemaName;
92 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
95 public void setShouldUpdateRevNumber(boolean flag) {
96 this.shouldUpdateRevNumber = flag;
99 public boolean getShouldUpdateRevNumber() {
100 return this.shouldUpdateRevNumber;
104 * The entity type expected from the JAX-RS Response object
106 public Class<String> getEntityResponseType() {
111 public void prepareSync() throws Exception {
112 this.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev nums on sync operations
115 protected PayloadInputPart extractPart(Response res, String partLabel)
117 PoxPayloadIn input = new PoxPayloadIn((String)res.readEntity(getEntityResponseType()));
118 PayloadInputPart payloadInputPart = input.getPart(partLabel);
119 if (payloadInputPart == null) {
120 logger.error("Part " + partLabel + " was unexpectedly null.");
122 return payloadInputPart;
126 public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
127 boolean result = false;
128 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
129 Specifier specifier = (Specifier) wrapDoc.getWrappedObject();
131 // Get the rev number of the authority so we can compare with rev number of shared authority
133 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, specifier);
134 if (docModel != null) {
135 Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
136 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
137 String remoteClientConfigName = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REMOTECLIENT_CONFIG_NAME); // If set, contains the name of the remote client configuration (remoteClientConfigName) from the tenant bindings
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.requestPayloadInFromRemoteServer(ctx, remoteClientConfigName, 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 || true) { // FIXME: Along with the revision number, we need to use other meta information to determine if a sync should happen -for now, alway sync
150 // First, sync all the authority items
152 syncAllItems(ctx, sasSpecifier); // FIXME: We probably want to consider "paging" this instead of handling the entire set of items.
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 may need to transition the authority into a replicated state the first time we sync it.
167 String workflowState = docModel.getCurrentLifeCycleState();
168 if (workflowState.contains(WorkflowClient.WORKFLOWSTATE_REPLICATED) == false) {
169 String authorityCsid = docModel.getName();
170 authorityResource.updateWorkflowWithTransition(ctx, ctx.getUriInfo(), authorityCsid, WorkflowClient.WORKFLOWTRANSITION_REPLICATE);
174 String errMsg = String.format("Authority of type '%s' with identifier '%s' does not exist.",
175 getServiceContext().getServiceName(), specifier.getURNValue());
176 logger.debug(errMsg);
177 throw new DocumentException(errMsg);
184 * Get the list of authority items from the remote shared authority server (SAS) and try
185 * to synchronize them with the local items. If items exist on the remote but not the local, we'll create them.
187 protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
191 int alreadySynched = 0;
193 int totalItemsProcessed = 0;
194 ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
196 // Iterate over the list of items/terms in the remote authority
198 PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
199 List<Element> itemList = getItemList(sasPayloadInItemList);
200 if (itemList != null) {
201 for (Element e:itemList) {
202 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
203 itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
204 long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
207 } else if (status == 0) {
212 totalItemsProcessed++;
216 // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
217 // locally. Subtract (remove) the list of remote items from the list of local items to determine which
218 // of the remote items have been hard deleted.
220 ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
221 itemsInLocalAuthority.removeAll(itemsInRemoteAuthority);
222 if (itemsInLocalAuthority.size() > 0) {
223 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)
225 // We now need to either hard-delete or deprecate the remaining authorities
227 long processed = deleteOrDeprecateItems(ctx, sasAuthoritySpecifier, remainingItems);
228 if (processed != remainingItems.size()) {
229 throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
233 // Now that we've sync'd all the items, we need to synchronize the hierarchy relationships
235 for (String itemShortId:itemsInRemoteAuthority) {
236 long status = syncRemoteItemRelationshipsWithLocalItem(ctx, sasAuthoritySpecifier, itemShortId);
239 } else if (status == 0) {
244 totalItemsProcessed++;
247 logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
248 logger.info(String.format("Number of items synchronized: %d", synched));
249 logger.info(String.format("Number of items created during sync: %d", created));
250 logger.info(String.format("Number not needing synchronization: %d", alreadySynched));
256 * This method should ***only*** be used as part of a SAS synch operation.
263 private long deleteOrDeprecateItems(ServiceContext ctx, Specifier authoritySpecifier, ArrayList<String> itemShortIdList) throws Exception {
265 AuthorityItemSpecifier authorityItemSpecificer = null;
267 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
268 for (String itemShortId:itemShortIdList) {
269 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
271 authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authoritySpecifier.value,
273 authorityResource.deleteAuthorityItem(ctx,
274 authorityItemSpecificer.getParentSpecifier().getURNValue(),
275 authorityItemSpecificer.getItemSpecifier().getURNValue(),
276 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)
278 } catch (DocumentReferenceException de) {
279 logger.info(String.format("Authority item with '%s' has existing references and cannot be removed during sync.",
280 authorityItemSpecificer), de);
281 boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
282 authorityItemSpecificer);
283 if (marked == true) {
286 } catch (Exception e) {
287 logger.warn(String.format("Unable to delete authority item '%s'", authorityItemSpecificer), e);
292 if (logger.isWarnEnabled() == true) {
293 if (result != itemShortIdList.size()) {
294 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.",
295 result, itemShortIdList.size()));
303 * Gets the list of SAS related items in the local authority. We exlude items with the "proposed" flags because
304 * we want a list with only SAS created items.
306 * We need to add pagination support to this call!!!
309 * @param authoritySpecifier
313 private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception {
314 ArrayList<String> result = new ArrayList<String>();
316 ResourceMap resourceMap = ctx.getResourceMap();
317 String resourceName = ctx.getClient().getServiceName();
318 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
319 AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), ctx.getUriInfo());
321 List<ListItem> listItemList = acl.getListItem();
322 for (ListItem listItem:listItemList) {
323 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
324 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
325 result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
332 private Boolean getBooleanValue(ListItem listItem, String name) {
333 Boolean result = null;
335 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
337 result = Boolean.valueOf(value);
343 private String getStringValue(ListItem listItem, String name) {
344 return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
348 * This method should only be used during a SAS synchronization request.
351 * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
352 * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
355 protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier, Boolean syncHierarchicalRelationships) throws Exception {
357 // Create a URN short ID specifier for the getting a copy of the remote authority item
359 Specifier authoritySpecifier = Specifier.getSpecifier(parentIdentifier);
360 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
361 AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(authoritySpecifier, itemSpecifier);
363 // Get the remote client configuration name
365 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, authoritySpecifier);
366 String remoteClientConfigName = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REMOTECLIENT_CONFIG_NAME); // If set, contains the name of the remote client configuration (remoteClientConfigName) from the tenant bindings
368 // Get the remote payload
370 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadInFromRemoteServer(sasAuthorityItemSpecifier, remoteClientConfigName,
371 ctx.getServiceName(), getEntityResponseType(), syncHierarchicalRelationships);
372 sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
374 // Using the payload from the remote server, create a local copy of the item
376 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
377 Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(),
378 sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM);
380 // Check the response for successful POST result
382 if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
383 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
384 itemIdentifier, parentIdentifier));
387 // Since we're creating an item that was sourced from the replication server, we need to replicate it locally.
389 authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier,
390 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)
394 * Try to synchronize a remote item (using its refName) with a local item. If the local doesn't yet
395 * exist, we'll create it.
397 * -1 = sync not needed; i.e., already in sync
399 * 1 = local item was missing so we created it
405 protected long syncRemoteItemWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
408 // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
410 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
411 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
412 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
414 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
416 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
417 PoxPayloadOut localItemPayloadOut;
419 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
420 } catch (DocumentNotFoundException dnf) {
422 // Document not found, means we need to create an item/term that exists only on the SAS
424 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
425 createLocalItem(ctx, parentIdentifier, itemIdentifier, AuthorityClient.DONT_INCLUDE_RELATIONS);
426 return 1; // exit with status of 1 means we created a new authority item
429 // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
433 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, false);
434 if (theUpdate != null) {
435 result = 0; // means we needed to sync this item with SAS
436 logger.debug(String.format("Synced authority item %s in authority %s",
437 itemIdentifier, parentIdentifier));
439 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
441 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
445 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
449 * Ensure the local items relationships look the same as the remote items' by synchronizing the hierarchy relationship records
450 * of the SAS item with the local item.
457 protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, Specifier authoritySpecifier, String itemShortId) throws Exception {
460 String parentIdentifier = authoritySpecifier.getURNValue();
461 String itemIdentifier = Specifier.createShortIdURNValue(itemShortId);
463 // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
465 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
466 PoxPayloadOut localItemPayloadOut;
468 MultivaluedMap queryParams = ctx.getQueryParams();
469 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
470 } catch (DocumentNotFoundException dnf) {
472 // Document not found, means we need to create an item/term that exists only on the SAS
474 logger.info(String.format("Remote item with short ID ='%s' doesn't exist locally, so we can't synchronize its relationships.", itemShortId));
478 // If we get here, we know the item exists both locally and remotely, so we need to synchronize the hierarchy relationships.
482 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, AuthorityClient.INCLUDE_RELATIONS);
483 if (theUpdate != null) {
484 result = 0; // means we needed to sync this item with SAS
485 logger.debug(String.format("Synced authority item %s in authority %s",
486 itemIdentifier, parentIdentifier));
488 } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
490 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
494 return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
499 private void assertStatusCode(Response res, Specifier specifier, AuthorityClient client) throws Exception {
500 int statusCode = res.getStatus();
502 if (statusCode != HttpStatus.SC_OK) {
503 String errMsg = String.format("Could not retrieve authority information for '%s' on remote server '%s'. Server returned status code %d",
504 specifier.getURNValue(), client.getBaseURL(), statusCode);
505 throw new DocumentException(statusCode, errMsg);
510 * Request an authority item list payload from the SAS server. This is a non-paging solution. If the authority
511 * has a very large number of items/terms, we might not be able to handle them all.
518 private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
519 PoxPayloadIn result = null;
520 AuthorityClient client = (AuthorityClient) ctx.getClient();
523 // First find out how many items exist
524 Response res = client.readItemList(specifier.getURNValue(),
525 null, // partial term string
526 null, // keyword string
530 assertStatusCode(res, specifier, client);
531 AbstractCommonList commonList;
533 commonList = res.readEntity(AbstractCommonList.class);
537 long numOfItems = commonList.getTotalItems();
540 // Next, request a payload list with all the items
541 res = client.readItemList(specifier.getURNValue(),
542 null, // partial term string
543 null, // keyword string
544 numOfItems, // page size
547 assertStatusCode(res, specifier, client);
549 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response.
559 * Non standard injection of CSID into common part, since caller may access through
560 * shortId, and not know the CSID.
561 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
564 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
566 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
568 // Add the CSID to the common part
569 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
570 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
571 unQObjectProperties.put("csid", csid);
574 return unQObjectProperties;
577 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
578 super.fillAllParts(wrapDoc, action);
580 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
582 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
583 updateRevNumbers(wrapDoc);
587 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
588 DocumentModel documentModel = wrapDoc.getWrappedObject();
589 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
595 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
599 * We consider workflow state changes as changes that should bump the revision number
601 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
604 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
605 boolean updateRevNumber = this.getShouldUpdateRevNumber();
606 Boolean contextProperty = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
607 if (contextProperty != null) {
608 updateRevNumber = contextProperty;
611 if (updateRevNumber == true) { // We don't update the rev number of synchronization requests
612 updateRevNumbers(wrapDoc);
617 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
618 super.handleCreate(wrapDoc);
620 // Uncomment once debugged and App layer is read to integrate
621 // Experimenting with this uncommented now ...
622 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
623 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
626 protected String buildWhereForShortId(String name) {
627 return authorityCommonSchemaName
628 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
632 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
636 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
637 boolean result = true;
639 ServiceContext ctx = this.getServiceContext();
640 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
641 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
643 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
644 if (searchResultWrapper != null) {
646 if (logger.isInfoEnabled() == true) {
647 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
648 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'",
649 shortIdentifier, searchResult.getName());
650 logger.trace(debugMsg);
653 } catch (DocumentNotFoundException e) {
654 // Not a problem, just means we couldn't find another authority with that short ID
661 * If no short identifier was provided in the input payload,
662 * generate a short identifier from the display name. Either way though,
663 * the short identifier needs to be unique.
665 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
666 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
667 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
668 String shortDisplayName = "";
669 String generateShortIdentifier = null;
670 if (Tools.isEmpty(shortIdentifier)) {
671 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
672 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
675 if (isUnique(docModel, schemaName) == false) {
676 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
677 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
678 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
679 errMsgVerb, shortId);
680 throw new DocumentException(errMsg);
685 * Generate a refName for the authority from the short identifier
688 * All refNames for authorities are generated. If a client supplies
689 * a refName, it will be overwritten during create (per this method)
690 * or discarded during update (per filterReadOnlyPropertiesForPart).
692 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
695 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
696 DocumentModel docModel = wrapDoc.getWrappedObject();
697 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
698 String refName = authority.toString();
699 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
703 public RefName.RefNameInterface getRefName(ServiceContext ctx,
704 DocumentModel docModel) {
705 RefName.RefNameInterface refname = null;
708 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
709 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
710 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
711 ctx.getServiceName(),
712 null, // Only use shortId form!!!
716 } catch (Exception e) {
717 logger.error(e.getMessage(), e);
724 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
725 String result = null;
727 DocumentModel docModel = docWrapper.getWrappedObject();
728 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
729 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
730 result = refname.getDisplayName();
735 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
736 String shortIdentifier = null;
737 CoreSessionInterface repoSession = null;
738 boolean releaseSession = false;
740 NuxeoRepositoryClientImpl nuxeoRepoClient = (NuxeoRepositoryClientImpl)this.getRepositoryClient(ctx);
742 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
743 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
744 DocumentModel docModel = wrapDoc.getWrappedObject();
745 if (docModel == null) {
746 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
748 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
749 } catch (ClientException ce) {
750 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
752 if (repoSession != null) {
753 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
757 return shortIdentifier;
761 * Filters out selected values supplied in an update request.
763 * @param objectProps the properties filtered out from the update payload
764 * @param partMeta metadata for the object to fill
767 public void filterReadOnlyPropertiesForPart(
768 Map<String, Object> objectProps, ObjectPartType partMeta) {
769 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
770 String commonPartLabel = getServiceContext().getCommonPartLabel();
771 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
772 objectProps.remove(AuthorityJAXBSchema.CSID);
773 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
774 objectProps.remove(AuthorityJAXBSchema.REF_NAME);
779 protected Object getListResultValue(DocumentModel docModel, // REM - CSPACE-5133
780 String schema, ListResultField field) throws DocumentException {
781 Object result = null;
783 result = super.getListResultValue(docModel, schema, field);