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;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
33 import javax.ws.rs.core.MultivaluedMap;
34 import javax.ws.rs.core.PathSegment;
35 import javax.ws.rs.core.Response;
36 import javax.ws.rs.core.UriInfo;
38 import org.apache.commons.httpclient.HttpStatus;
39 import org.collectionspace.services.client.AbstractCommonListUtils;
40 import org.collectionspace.services.client.AuthorityClient;
41 import org.collectionspace.services.client.PayloadInputPart;
42 import org.collectionspace.services.client.PoxPayloadIn;
43 import org.collectionspace.services.client.PoxPayloadOut;
44 import org.collectionspace.services.client.RelationClient;
45 import org.collectionspace.services.client.XmlTools;
46 import org.collectionspace.services.client.workflow.WorkflowClient;
47 import org.collectionspace.services.common.ResourceMap;
48 import org.collectionspace.services.common.api.RefName;
49 import org.collectionspace.services.common.api.RefName.Authority;
50 import org.collectionspace.services.common.api.RefNameUtils;
51 import org.collectionspace.services.common.api.RefNameUtils.AuthorityTermInfo;
52 import org.collectionspace.services.common.api.Tools;
53 import org.collectionspace.services.common.context.ServiceContext;
54 import org.collectionspace.services.common.document.DocumentException;
55 import org.collectionspace.services.common.document.DocumentNotFoundException;
56 import org.collectionspace.services.common.document.DocumentReferenceException;
57 import org.collectionspace.services.common.document.DocumentWrapper;
58 import org.collectionspace.services.common.query.UriInfoImpl;
59 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
60 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
61 import org.collectionspace.services.common.vocabulary.AuthorityResource;
62 import org.collectionspace.services.common.vocabulary.AuthorityServiceUtils;
63 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
64 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
65 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
66 import org.collectionspace.services.config.service.ListResultField;
67 import org.collectionspace.services.config.service.ObjectPartType;
68 import org.collectionspace.services.jaxb.AbstractCommonList;
69 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
70 import org.collectionspace.services.lifecycle.TransitionDef;
71 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
72 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
73 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
74 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
75 import org.collectionspace.services.relation.RelationsCommonList;
76 import org.dom4j.Element;
77 import org.nuxeo.ecm.core.api.ClientException;
78 import org.nuxeo.ecm.core.api.DocumentModel;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
83 * AuthorityDocumentModelHandler
85 * $LastChangedRevision: $
88 @SuppressWarnings("rawtypes")
89 public abstract class AuthorityDocumentModelHandler<AuthCommon> extends NuxeoDocumentModelHandler<AuthCommon> {
90 private static final long SAS_SYNC_PAGE_SIZE = 500;
92 private final Logger logger = LoggerFactory.getLogger(AuthorityDocumentModelHandler.class);
94 protected String authorityCommonSchemaName;
95 protected String authorityItemCommonSchemaName;
96 protected boolean shouldUpdateRevNumber = true; // default to updating the revision number
98 public AuthorityDocumentModelHandler(String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
99 this.authorityCommonSchemaName = authorityCommonSchemaName;
100 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
103 public void setShouldUpdateRevNumber(boolean flag) {
104 this.shouldUpdateRevNumber = flag;
107 public boolean getShouldUpdateRevNumber() {
108 return this.shouldUpdateRevNumber;
112 * The entity type expected from the JAX-RS Response object
114 public Class<String> getEntityResponseType() {
119 public void prepareSync() throws Exception {
120 this.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev nums on sync operations
123 protected PayloadInputPart extractPart(Response res, String partLabel) throws Exception {
124 PoxPayloadIn input = new PoxPayloadIn((String) res.readEntity(getEntityResponseType()));
125 PayloadInputPart payloadInputPart = input.getPart(partLabel);
126 if (payloadInputPart == null) {
127 logger.error("Part " + partLabel + " was unexpectedly null.");
129 return payloadInputPart;
133 public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
134 boolean result = false;
135 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
136 Specifier specifier = (Specifier) wrapDoc.getWrappedObject();
138 // Get the rev number of the authority so we can compare with rev number of
141 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName,
143 if (docModel != null) {
144 String authorityCsid = docModel.getName();
145 Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
146 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
147 String remoteClientConfigName = (String) NuxeoUtils.getProperyValue(docModel,
148 // If set, contains the name of the remote client configuration (remoteClientConfigName) from the tenant bindings
149 AuthorityJAXBSchema.REMOTECLIENT_CONFIG_NAME);
151 // Using the short ID of the local authority, create a URN specifier to retrieve
154 Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, shortId);
155 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadInFromRemoteServer(ctx, remoteClientConfigName,
156 sasSpecifier, getEntityResponseType());
158 // If the authority on the SAS is newer, synch all the items and then the
159 // authority record as well
162 Long sasRev = getRevision(sasPayloadIn);
163 // FIXME: Along with the revision number, we need to use other meta information
164 // to determine if a sync should happen -for now, always sync
165 if (sasRev > localRev || true) {
167 // First, sync all the authority items
169 syncAllItems(ctx, authorityCsid, sasSpecifier);
171 // Next, sync the authority resource/record itself
173 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
174 // Don't update the rev number, use the rev number for the SAS instance instead
175 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, AuthorityServiceUtils.DONT_UPDATE_REV);
176 PoxPayloadOut payloadOut = authorityResource.update(ctx, ctx.getResourceMap(), ctx.getUriInfo(),
177 docModel.getName(), sasPayloadIn);
178 if (payloadOut != null) {
179 ctx.setOutput(payloadOut);
183 // We may need to transition the authority into a replicated state the first
186 String workflowState = docModel.getCurrentLifeCycleState();
187 if (workflowState.contains(WorkflowClient.WORKFLOWSTATE_REPLICATED) == false) {
188 authorityResource.updateWorkflowWithTransition(ctx, ctx.getUriInfo(), authorityCsid,
189 WorkflowClient.WORKFLOWTRANSITION_REPLICATE);
193 String errMsg = String.format("Authority of type '%s' with identifier '%s' does not exist.",
194 getServiceContext().getServiceName(), specifier.getURNValue());
195 logger.debug(errMsg);
196 throw new DocumentException(errMsg);
203 * Get the list of authority items from the remote shared authority server (SAS)
204 * and synchronize them with the local authority items. If items exist on the
205 * remote but not the local, create them.
207 protected void syncAllItems(ServiceContext ctx, String parentCsid, Specifier sasAuthoritySpecifier) throws Exception {
208 int createdCount = 0;
210 int alreadySyncedCount = 0;
211 int deletedCount = 0;
212 int totalProcessedCount = 0;
214 Set<String> remoteShortIds = new HashSet<String>();
216 // Iterate over the list of items in the remote authority.
219 long pageSize = SAS_SYNC_PAGE_SIZE;
221 List<Element> itemElements;
224 if (logger.isDebugEnabled()) {
225 logger.debug(String.format("Reading remote items in %s: page size %d, page num %d", sasAuthoritySpecifier.value, pageSize, pageNum));
228 PoxPayloadIn itemListPayload = requestItemList(ctx, sasAuthoritySpecifier, pageSize, pageNum);
230 itemElements = getItemList(itemListPayload);
232 if (itemElements == null) {
233 itemElements = Collections.EMPTY_LIST;
236 if (logger.isDebugEnabled()) {
237 logger.debug(String.format("Found %d items", itemElements.size()));
240 for (Element e : itemElements) {
241 String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME);
242 String remoteShortId = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
244 remoteShortIds.add(remoteShortId);
246 long status = syncRemoteItem(ctx, parentCsid, remoteRefName);
250 } else if (status == 0) {
253 alreadySyncedCount++;
256 totalProcessedCount++;
259 pageNum = pageNum + 1;
260 } while (itemElements.size() > 0 && itemElements.size() == SAS_SYNC_PAGE_SIZE);
262 // Deprecate or delete items that have been hard-deleted from the SAS but still
264 // Subtract (remove) the set of remote items from the set of local items to
266 // of the remote items have been hard deleted.
268 Set<String> localShortIds = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
270 localShortIds.removeAll(remoteShortIds);
272 if (localShortIds.size() > 0) {
273 // Delete the remaining items (or mark them as deprecated if they still have
274 // records referencing them).
276 deletedCount = deleteOrDeprecateItems(ctx, sasAuthoritySpecifier, localShortIds);
278 if (deletedCount != localShortIds.size()) {
279 throw new Exception("Error deleting or deprecating authority items during synchronization.");
283 logger.info(String.format("Total number of items processed during sync: %d", totalProcessedCount));
284 logger.info(String.format("Number of items synchronized: %d", syncedCount));
285 logger.info(String.format("Number of items created during sync: %d", createdCount));
286 logger.info(String.format("Number of items not needing synchronization: %d", alreadySyncedCount));
287 logger.info(String.format("Number of items hard deleted on remote: %d", deletedCount));
291 * This method should ***only*** be used as part of a SAS synch operation.
298 private int deleteOrDeprecateItems(ServiceContext ctx, Specifier authoritySpecifier, Set<String> itemShortIds)
301 AuthorityItemSpecifier authorityItemSpecificer = null;
303 // Don't update the revision number when we delete or deprecate the item
304 ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false);
306 for (String itemShortId : itemShortIds) {
307 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
309 authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authoritySpecifier.value,
311 // 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)
312 authorityResource.deleteAuthorityItem(ctx, authorityItemSpecificer.getParentSpecifier().getURNValue(),
313 authorityItemSpecificer.getItemSpecifier().getURNValue(), AuthorityServiceUtils.DONT_UPDATE_REV);
315 } catch (DocumentReferenceException de) {
316 logger.info(String.format("Authority item with '%s' has existing references and cannot be removed during sync.",
317 authorityItemSpecificer), de);
318 boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
319 authorityItemSpecificer);
320 if (marked == true) {
323 } catch (Exception e) {
324 logger.warn(String.format("Unable to delete authority item '%s'", authorityItemSpecificer), e);
329 if (logger.isWarnEnabled() == true) {
330 if (result != itemShortIds.size()) {
331 logger.warn(String.format(
332 "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.",
333 result, itemShortIds.size()));
341 * Gets the list of SAS related items in the local authority. Exludes items with
342 * the "proposed" flag to include only SAS created items.
345 * @param authoritySpecifier
349 private Set<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception {
350 Set<String> itemShortIds = new HashSet<String>();
352 ResourceMap resourceMap = ctx.getResourceMap();
353 String resourceName = ctx.getClient().getServiceName();
354 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
357 long pageSize = SAS_SYNC_PAGE_SIZE;
359 List<ListItem> listItems;
362 if (logger.isDebugEnabled()) {
363 logger.debug(String.format("Reading local items in %s: page size %d, page num %d", authoritySpecifier.value,
367 // Construct a UriInfo to retrieve one page of results.
369 UriInfo uriInfo = new UriInfoImpl(
373 "pgSz=" + pageSize + "&pgNum=" + pageNum,
374 Collections.<PathSegment> emptyList()
377 AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), uriInfo);
379 listItems = acl.getListItem();
381 if (logger.isDebugEnabled()) {
382 logger.debug(String.format("Found %d items", listItems.size()));
385 for (ListItem listItem : listItems) {
386 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
388 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
389 itemShortIds.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER));
393 pageNum = pageNum + 1;
394 } while (listItems.size() > 0 && listItems.size() == SAS_SYNC_PAGE_SIZE);
399 private Boolean getBooleanValue(ListItem listItem, String name) {
400 Boolean result = null;
402 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
404 result = Boolean.valueOf(value);
410 private String getStringValue(ListItem listItem, String name) {
411 return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
415 * This method should only be used during a SAS synchronization request.
418 * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
419 * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
422 protected void createLocalItem(ServiceContext ctx, String parentCsid, String parentIdentifier, String itemIdentifier, Boolean syncHierarchicalRelationships) throws Exception {
424 // Create a URN short ID specifier for the getting a copy of the remote authority item
426 Specifier parentSpecifier = Specifier.getSpecifier(parentIdentifier);
427 Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
428 AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
430 // Get the remote client configuration name
432 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, parentSpecifier);
433 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
435 // Get the remote payload
437 PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadInFromRemoteServer(sasAuthorityItemSpecifier, remoteClientConfigName,
438 ctx.getServiceName(), getEntityResponseType(), syncHierarchicalRelationships);
440 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
442 // Remove remote uris and csids from relations, and remove relations to items that don't exist locally.
443 sasPayloadIn = AuthorityServiceUtils.localizeRelations(ctx, authorityResource, parentCsid, itemSpecifier, sasPayloadIn);
445 // Localize domain name parts of refnames in the payload.
446 sasPayloadIn = AuthorityServiceUtils.localizeRefNameDomains(ctx, sasPayloadIn);
449 // Using the payload from the remote server, create a local copy of the item
451 Response response = authorityResource.createAuthorityItemWithParentContext(ctx, parentSpecifier.getURNValue(),
452 sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM);
454 // Check the response for successful POST result
456 if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
457 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
458 itemIdentifier, parentIdentifier));
461 // Since we're creating an item that was sourced from the replication server, we need to replicate it locally.
463 authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier,
464 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)
468 * Synchronize a remote item (using its refName) with a local item. If the local doesn't yet
471 * -1 = sync not needed; i.e., already in sync
473 * 1 = local item was missing so we created it
479 protected long syncRemoteItem(ServiceContext ctx, String parentCsid, String itemRefName) throws Exception {
480 if (logger.isInfoEnabled()) {
481 logger.info(String.format("Syncing remote item %s", itemRefName));
484 // Create specifiers to find the local item corresponding to the remote refname.
486 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
487 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
488 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
490 // Use the Authority JAX-RS resource to peform sync operations (creates and updates).
492 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
493 PoxPayloadOut localItemPayload = null;
495 // Find the local item.
498 localItemPayload = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
499 } catch (DocumentNotFoundException dnf) {
500 localItemPayload = null;
503 // If no local item exists, create one.
505 if (localItemPayload == null) {
506 createLocalItem(ctx, parentCsid, parentIdentifier, itemIdentifier, AuthorityClient.INCLUDE_RELATIONS);
511 // Sync the local item with the remote item.
513 PoxPayloadOut updatePayload = null;
516 updatePayload = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, AuthorityClient.INCLUDE_RELATIONS);
517 } catch (DocumentReferenceException de) {
518 logger.error(String.format("Could not sync item %s because it is referenced by other records", itemIdentifier));
521 if (updatePayload != null) {
522 logger.info(String.format("Synced item %s in authority %s", itemIdentifier, parentIdentifier));
530 private void assertStatusCode(Response res, Specifier specifier, AuthorityClient client) throws Exception {
531 int statusCode = res.getStatus();
533 if (statusCode != HttpStatus.SC_OK) {
534 String errMsg = String.format("Could not retrieve authority information for '%s' on remote server '%s'. Server returned status code %d",
535 specifier.getURNValue(), client.getBaseURL(), statusCode);
536 throw new DocumentException(statusCode, errMsg);
541 * Request an authority item list payload from the SAS server.
548 private PoxPayloadIn requestItemList(ServiceContext ctx, Specifier specifier, long pageSize, long pageNum) throws Exception {
549 PoxPayloadIn result = null;
550 AuthorityClient client = (AuthorityClient) ctx.getClient();
552 Response res = client.readItemList(
553 specifier.getURNValue(),
554 null, // partial term string
555 null, // keyword string
560 assertStatusCode(res, specifier, client);
563 result = new PoxPayloadIn((String) res.readEntity(getEntityResponseType())); // Get the entire response.
572 * Non standard injection of CSID into common part, since caller may access through
573 * shortId, and not know the CSID.
574 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
577 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
579 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
581 // Add the CSID to the common part
582 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
583 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
584 unQObjectProperties.put("csid", csid);
587 return unQObjectProperties;
590 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
591 super.fillAllParts(wrapDoc, action);
593 // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
595 if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
596 updateRevNumbers(wrapDoc);
600 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
601 DocumentModel documentModel = wrapDoc.getWrappedObject();
602 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
608 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
612 * We consider workflow state changes as changes that should bump the revision number
614 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
617 public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
618 boolean updateRevNumber = this.getShouldUpdateRevNumber();
619 Boolean contextProperty = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
620 if (contextProperty != null) {
621 updateRevNumber = contextProperty;
624 if (updateRevNumber == true) { // We don't update the rev number of synchronization requests
625 updateRevNumbers(wrapDoc);
630 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
631 super.handleCreate(wrapDoc);
633 // Uncomment once debugged and App layer is read to integrate
634 // Experimenting with this uncommented now ...
635 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
636 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
639 protected String buildWhereForShortId(String name) {
640 return authorityCommonSchemaName
641 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
645 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
649 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
650 boolean result = true;
652 ServiceContext ctx = this.getServiceContext();
653 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
654 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
656 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
657 if (searchResultWrapper != null) {
659 if (logger.isInfoEnabled() == true) {
660 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
661 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'",
662 shortIdentifier, searchResult.getName());
663 logger.trace(debugMsg);
666 } catch (DocumentNotFoundException e) {
667 // Not a problem, just means we couldn't find another authority with that short ID
674 * If no short identifier was provided in the input payload,
675 * generate a short identifier from the display name. Either way though,
676 * the short identifier needs to be unique.
678 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
679 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
680 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
681 String shortDisplayName = "";
682 String generateShortIdentifier = null;
683 if (Tools.isEmpty(shortIdentifier)) {
684 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
685 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
688 if (isUnique(docModel, schemaName) == false) {
689 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
690 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
691 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
692 errMsgVerb, shortId);
693 throw new DocumentException(errMsg);
698 * Generate a refName for the authority from the short identifier
701 * All refNames for authorities are generated. If a client supplies
702 * a refName, it will be overwritten during create (per this method)
703 * or discarded during update (per filterReadOnlyPropertiesForPart).
705 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
708 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
709 DocumentModel docModel = wrapDoc.getWrappedObject();
710 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
711 String refName = authority.toString();
712 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
716 public RefName.RefNameInterface getRefName(ServiceContext ctx,
717 DocumentModel docModel) {
718 RefName.RefNameInterface refname = null;
721 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
722 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
723 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
724 ctx.getServiceName(),
725 null, // Only use shortId form!!!
729 } catch (Exception e) {
730 logger.error(e.getMessage(), e);
737 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
738 String result = null;
740 DocumentModel docModel = docWrapper.getWrappedObject();
741 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
742 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
743 result = refname.getDisplayName();
748 public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
749 String shortIdentifier = null;
750 CoreSessionInterface repoSession = null;
751 boolean releaseSession = false;
753 NuxeoRepositoryClientImpl nuxeoRepoClient = (NuxeoRepositoryClientImpl)this.getRepositoryClient(ctx);
755 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
756 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
757 DocumentModel docModel = wrapDoc.getWrappedObject();
758 if (docModel == null) {
759 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
761 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
762 } catch (ClientException ce) {
763 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
765 if (repoSession != null) {
766 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
770 return shortIdentifier;
774 * Filters out selected values supplied in an update request.
776 * @param objectProps the properties filtered out from the update payload
777 * @param partMeta metadata for the object to fill
780 public void filterReadOnlyPropertiesForPart(
781 Map<String, Object> objectProps, ObjectPartType partMeta) {
782 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
783 String commonPartLabel = getServiceContext().getCommonPartLabel();
784 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
785 objectProps.remove(AuthorityJAXBSchema.CSID);
786 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
787 objectProps.remove(AuthorityJAXBSchema.REF_NAME);
792 protected Object getListResultValue(DocumentModel docModel, // REM - CSPACE-5133
793 String schema, ListResultField field) throws DocumentException {
794 Object result = null;
796 result = super.getListResultValue(docModel, schema, field);