]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
c2a89e7402f02b3463ae251871bb97ac431b2e97
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.common.vocabulary.nuxeo;
25
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.ws.rs.core.Response;
31
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.workflow.WorkflowClient;
40 import org.collectionspace.services.common.ResourceMap;
41 import org.collectionspace.services.common.XmlTools;
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;
75
76 /**
77  * AuthorityDocumentModelHandler
78  *
79  * $LastChangedRevision: $
80  * $LastChangedDate: $
81  */
82 public abstract class AuthorityDocumentModelHandler<AuthCommon>
83         extends NuxeoDocumentModelHandler<AuthCommon> {
84     
85         private final Logger logger = LoggerFactory.getLogger(AuthorityDocumentModelHandler.class);     
86     
87         protected String authorityCommonSchemaName;
88     protected String authorityItemCommonSchemaName;
89     protected boolean shouldUpdateRevNumber = true; // default to updating the revision number
90
91     public AuthorityDocumentModelHandler(String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
92         this.authorityCommonSchemaName = authorityCommonSchemaName;
93         this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
94     }
95     
96     public void setShouldUpdateRevNumber(boolean flag) {
97         this.shouldUpdateRevNumber = flag;
98     }
99     
100     public boolean getShouldUpdateRevNumber() {
101         return this.shouldUpdateRevNumber;
102     }
103     
104     /**
105      * The entity type expected from the JAX-RS Response object
106      */
107     public Class<String> getEntityResponseType() {
108         return String.class;
109     }
110     
111     @Override
112     public void prepareSync() throws Exception {
113         this.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV);  // Never update rev nums on sync operations
114     }
115
116     protected PayloadInputPart extractPart(Response res, String partLabel)
117             throws Exception {
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.");
122             }
123             return payloadInputPart;
124     }
125     
126     @Override
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();
131         //
132         // Get the rev number of the authority so we can compare with rev number of shared authority
133         //
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);
137         //
138         // Using the short ID of the local authority, create a URN specifier to retrieve the SAS authority
139         //
140         Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, shortId);
141         PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(ctx, sasSpecifier, getEntityResponseType());
142         //
143         // If the authority on the SAS is newer, synch all the items and then the authority record as well
144         //
145         //
146         Long sasRev = getRevision(sasPayloadIn);
147         if (sasRev > localRev) {
148                 //
149                 // First, sync all the authority items
150                 //
151                 syncAllItems(ctx, sasSpecifier);
152                 //
153                 // Next, sync the authority resource/record itself
154                 //
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(), 
158                                 sasPayloadIn);
159                 if (payloadOut != null) {
160                         ctx.setOutput(payloadOut);
161                         result = true;
162                 }
163         }
164         
165         return result;
166     }
167     
168     /*
169      * Get the list of authority items from the remote shared authority server (SAS) and try
170      * to synchronize them with the local items.  If items exist on the remote but not the local, we'll create them.
171      */
172     protected int syncAllItems(ServiceContext ctx, Specifier sasAuthoritySpecifier) throws Exception {
173         int result = -1;
174         int created = 0;
175         int synched = 0;
176         int alreadySynched = 0;
177         int deprecated = 0;
178         int totalItemsProcessed = 0;
179         ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
180         //
181         // Iterate over the list of items/terms in the remote authority
182         //
183         PoxPayloadIn sasPayloadInItemList = requestPayloadInItemList(ctx, sasAuthoritySpecifier);
184         List<Element> itemList = getItemList(sasPayloadInItemList);
185         if (itemList != null) {
186                 for (Element e:itemList) {
187                         String remoteRefName = XmlTools.getElementValue(e, "refName");
188                         itemsInRemoteAuthority.add(remoteRefName);
189                         long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
190                         if (status == 1) {
191                                 created++;
192                         } else if (status == 0) {
193                                 synched++;
194                         } else {
195                                 alreadySynched++;
196                         }
197                         totalItemsProcessed++;
198                 }
199         }
200         //
201         // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
202         // locally.  Subtract (remove) the list of remote items from the list of local items to determine which
203         // of the remote items have been hard deleted.
204         //
205         ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier);
206         if (itemsInLocalAuthority.removeAll(itemsInRemoteAuthority) == true) {
207                 ArrayList<String> remainingItems = itemsInLocalAuthority; // now a subset of local items
208                 //
209                 // We now need to either hard-deleted or deprecate the remaining authorities
210                 //
211                 long processed = deleteOrDeprecateItems(ctx, remainingItems);
212                 if (processed != remainingItems.size()) {
213                         throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
214                 }
215         }
216
217         
218         logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
219         logger.info(String.format("Number of items synchronized: %d", synched));
220         logger.info(String.format("Number of items created during sync: %d", created));
221         logger.info(String.format("Number not needing synchronization: %d", alreadySynched));
222
223         return result;
224     }
225
226     /**
227      * 
228      * @param ctx
229      * @param refNameList
230      * @return
231      * @throws Exception
232      */
233     private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList<String> refNameList) throws Exception {
234         long result = 0;
235         
236         ArrayList<String> failureList = new ArrayList<String>();
237         ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false);
238
239         for (String refName:refNameList) {
240                 AuthorityTermInfo itemInfo = RefNameUtils.parseAuthorityTermInfo(refName);
241                 AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
242                 try {
243                         authorityResource.deleteAuthorityItem(ctx, itemInfo.inAuthority.csid, itemInfo.csid);
244                         result++;
245                 } catch (DocumentReferenceException de) {
246                         logger.info(String.format("Authority item '%s' has existing references and cannot be removed during sync.",
247                                         refName), de);
248                         boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
249                                         itemInfo.csid);
250                         if (marked == true) {
251                                 result++;
252                         }
253                 } catch (Exception e) {
254                         logger.warn(String.format("Unable to delete authority item '%s'", refName), e);
255                         throw e;
256                 }
257         }
258
259         if (logger.isWarnEnabled() == true) {
260                 if (result != refNameList.size()) {
261                         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.",
262                                         result, refNameList.size()));
263                 }
264         }
265         
266         return result;
267     }
268     
269     /**
270      * Gets the list of SAS related items in the local authority.  We exlude items with the "proposed" flags because
271      * we want a list with only SAS created items.
272      * 
273      * We need to add pagination support to this call!!!
274      * 
275      * @param ctx
276      * @param specifier
277      * @return
278      * @throws Exception
279      */
280     private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier specifier) throws Exception {
281         ArrayList<String> result = new ArrayList<String>();
282         
283         ResourceMap resourceMap = ctx.getResourceMap();
284         String resourceName = ctx.getClient().getServiceName();
285         AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
286         AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, specifier.value, ctx.getUriInfo());
287         List<ListItem> listItemList = acl.getListItem();
288         for (ListItem listItem:listItemList) {
289                 Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED);
290                 if (proposed == false) { // exclude "proposed" (i.e., local-only items)
291                         result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME));
292                 }
293         }
294         
295         return result;
296     }
297     
298     private Boolean getBooleanValue(ListItem listItem, String name) {
299         Boolean result = null;
300         
301                 String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
302                 if (value != null) {
303                         result = Boolean.valueOf(value);
304                 }
305                 
306                 return result;
307     }
308     
309     private String getStringValue(ListItem listItem, String name) {
310         return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
311     }
312     
313     /**
314      * This is a sync method.
315      * @param ctx
316      * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
317      * @param itemIdentifier   - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
318      * @throws Exception 
319      */
320     protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier) throws Exception {
321         //
322         // Create a URN short ID specifier for the getting a copy of the remote authority item
323         //
324         Specifier authoritySpecifier = Specifier.getSpecifier(parentIdentifier);
325         Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier);
326         AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(authoritySpecifier, itemSpecifier);
327         //
328         // Get the remote payload
329         //
330         PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier, 
331                         ctx.getServiceName(), getEntityResponseType());
332         sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
333         //
334         // Using the payload from the remote server, create a local copy of the item
335         //
336         AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
337         Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(),
338                         sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED);
339         //
340         // Check the response for successful POST result
341         //
342         if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
343                 throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
344                                 itemIdentifier, parentIdentifier));
345         }
346         //
347         // Since we're creating an item that was sourced from the SAS, we need to lock it.
348         //
349         authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier, 
350                         WorkflowClient.WORKFLOWTRANSITION_LOCK, AuthorityServiceUtils.DONT_UPDATE_REV);
351         }
352     
353     /**
354      * Try to synchronize a remote item (using its refName) with a local item.  If the local doesn't yet
355      * exist, we'll create it.
356      * Result values:
357      *  -1 = sync not needed; i.e., already in sync
358      *   0 = sync succeeded
359      *   1 = local item was missing so we created it
360      * @param ctx
361      * @param refName
362      * @return
363      * @throws Exception
364      */
365     protected long syncRemoteItemWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
366         long result = -1;
367         //
368         // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
369         //
370         AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
371         String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
372         String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
373         //
374         // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
375         //
376         AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();            
377         PoxPayloadOut localItemPayloadOut;
378         try {
379                 localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
380         } catch (DocumentNotFoundException dnf) {
381                 //
382                 // Document not found, means we need to create an item/term that exists only on the SAS
383                 //
384                 logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
385                 createLocalItem(ctx, parentIdentifier, itemIdentifier);
386                 return 1; // exit with status of 1 means we created a new authority item
387         }
388         //
389         // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
390         //
391         //
392         try {
393                 PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
394                 if (theUpdate != null) {
395                         result = 0; // means we needed to sync this item with SAS
396                         logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS.  Updated payload is: \n%s",
397                                         parentIdentifier, itemIdentifier, theUpdate.getXmlPayload()));
398                 }
399         } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them.
400                 result = -1;
401                 logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.",
402                                 itemIdentifier));
403         }
404         
405         return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item
406     }
407         
408     private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception {
409         PoxPayloadIn result = null;
410         
411         AuthorityClient client = (AuthorityClient) ctx.getClient();
412         Response res = client.readItemList(specifier.getURNValue(),
413                         null,   // partial term string
414                         null    // keyword string
415                         );
416         try {
417                 int statusCode = res.getStatus();
418         
419                 // Check the status code of the response: does it match
420                 // the expected response(s)?
421                 if (logger.isDebugEnabled()) {
422                     logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
423                 }
424                 
425             result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!             
426         } finally {
427                 res.close();
428         }
429         
430         return result;
431     }
432     
433
434     /*
435      * Non standard injection of CSID into common part, since caller may access through
436      * shortId, and not know the CSID.
437      * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
438      */
439     @Override
440     protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
441             throws Exception {
442         Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
443
444         // Add the CSID to the common part
445         if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
446             String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
447             unQObjectProperties.put("csid", csid);
448         }
449
450         return unQObjectProperties;
451     }
452     
453     public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
454         super.fillAllParts(wrapDoc, action);
455         //
456         // Update the record's revision number on both CREATE and UPDATE actions, but not on SYNC
457         //
458         if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
459                 updateRevNumbers(wrapDoc);
460         }
461     }
462     
463     protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
464         DocumentModel documentModel = wrapDoc.getWrappedObject();
465         Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
466         if (rev == null) {
467                 rev = (long)0;
468         } else {
469                 rev++;
470         }
471         documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
472     }
473     
474     /*
475      * We consider workflow state changes as changes that should bump the revision number
476      * (non-Javadoc)
477      * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
478      */
479     @Override
480     public void handleWorkflowTransition(ServiceContext ctx, DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception {
481         // Update the revision number
482         updateRevNumbers(wrapDoc);
483     }
484     
485     @Override
486     public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
487         super.handleCreate(wrapDoc);
488         // CSPACE-3178:
489         // Uncomment once debugged and App layer is read to integrate
490         // Experimenting with this uncommented now ...
491         handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
492         updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
493     }
494     
495     protected String buildWhereForShortId(String name) {
496         return authorityCommonSchemaName
497                 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
498                 + "='" + name + "'";
499     }
500     
501     private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
502         return true;
503     }
504     
505     private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
506         boolean result = true;
507         
508         ServiceContext ctx = this.getServiceContext();
509         String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
510         String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
511         try {
512                         DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
513                         if (searchResultWrapper != null) {
514                                 result = false;
515                                 if (logger.isInfoEnabled() == true) {
516                                         DocumentModel searchResult = searchResultWrapper.getWrappedObject();
517                                         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'",
518                                                         shortIdentifier, searchResult.getName());
519                                         logger.trace(debugMsg);
520                                 }
521                         }
522                 } catch (DocumentNotFoundException e) {
523                         // Not a problem, just means we couldn't find another authority with that short ID
524                 }
525         
526         return result;
527     }
528
529     /**
530      * If no short identifier was provided in the input payload,
531      * generate a short identifier from the display name. Either way though,
532      * the short identifier needs to be unique.
533      */
534     private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
535         String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
536         String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
537         String shortDisplayName = "";
538         String generateShortIdentifier = null;
539         if (Tools.isEmpty(shortIdentifier)) {
540                 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
541             docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
542         }
543         
544         if (isUnique(docModel, schemaName) == false) {
545                 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
546                 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
547                 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
548                                 errMsgVerb, shortId);
549                 throw new DocumentException(errMsg);
550         }
551     }
552  
553     /**
554      * Generate a refName for the authority from the short identifier
555      * and display name.
556      * 
557      * All refNames for authorities are generated.  If a client supplies
558      * a refName, it will be overwritten during create (per this method) 
559      * or discarded during update (per filterReadOnlyPropertiesForPart).
560      * 
561      * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
562      * 
563      */
564     protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
565         DocumentModel docModel = wrapDoc.getWrappedObject();
566         RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
567         String refName = authority.toString();
568         docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
569     }
570     
571     @Override
572     public RefName.RefNameInterface getRefName(ServiceContext ctx,
573                 DocumentModel docModel) {
574         RefName.RefNameInterface refname = null;
575
576         try {
577                 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
578                 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
579                 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
580                         ctx.getServiceName(),
581                         null,   // Only use shortId form!!!
582                         shortIdentifier,
583                         displayName);
584                 refname = authority;
585         } catch (Exception e) {
586                 logger.error(e.getMessage(), e);
587         }
588         
589         return refname;
590     }
591     
592     @Override
593     protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
594         String result = null;
595         
596         DocumentModel docModel = docWrapper.getWrappedObject();
597         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
598         RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
599         result = refname.getDisplayName();
600         
601         return result;
602     }    
603     
604     public String getShortIdentifier(ServiceContext ctx, String authCSID, String schemaName) throws Exception {
605         String shortIdentifier = null;
606         CoreSessionInterface repoSession = null;
607         boolean releaseSession = false;
608
609         RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
610         try {
611                 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
612             DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
613             DocumentModel docModel = wrapDoc.getWrappedObject();
614             if (docModel == null) {
615                 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
616             }
617             shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
618         } catch (ClientException ce) {
619             throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
620         } finally {
621                 if (repoSession != null) {
622                         nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
623                 }
624         }
625         
626         return shortIdentifier;
627     }
628
629     /**
630      * Filters out selected values supplied in an update request.
631      * 
632      * @param objectProps the properties filtered out from the update payload
633      * @param partMeta metadata for the object to fill
634      */
635     @Override
636     public void filterReadOnlyPropertiesForPart(
637             Map<String, Object> objectProps, ObjectPartType partMeta) {
638         super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
639         String commonPartLabel = getServiceContext().getCommonPartLabel();
640         if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
641             objectProps.remove(AuthorityJAXBSchema.CSID);
642             objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
643             objectProps.remove(AuthorityJAXBSchema.REF_NAME);
644         }
645     }    
646 }