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;
28 import javax.ws.rs.core.Response;
30 import org.collectionspace.services.client.AuthorityClient;
31 import org.collectionspace.services.client.CollectionSpaceClient;
32 import org.collectionspace.services.client.PayloadInputPart;
33 import org.collectionspace.services.client.VocabularyClient;
34 import org.collectionspace.services.client.PoxPayloadIn;
35 import org.collectionspace.services.client.PoxPayloadOut;
36 import org.collectionspace.services.common.ResourceMap;
37 import org.collectionspace.services.common.XmlTools;
38 import org.collectionspace.services.common.api.RefName;
39 import org.collectionspace.services.common.api.RefName.Authority;
40 import org.collectionspace.services.common.api.RefNameUtils;
41 import org.collectionspace.services.common.api.RefNameUtils.AuthorityInfo;
42 import org.collectionspace.services.common.api.Tools;
43 import org.collectionspace.services.common.context.ServiceContext;
44 import org.collectionspace.services.common.document.DocumentException;
45 import org.collectionspace.services.common.document.DocumentNotFoundException;
46 import org.collectionspace.services.common.document.DocumentWrapper;
47 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
48 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
49 import org.collectionspace.services.common.vocabulary.AuthorityResource;
50 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
51 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
52 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
53 import org.collectionspace.services.config.service.ObjectPartType;
54 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
55 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
56 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
57 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
58 import org.dom4j.Document;
59 import org.dom4j.Element;
60 import org.nuxeo.ecm.core.api.ClientException;
61 import org.nuxeo.ecm.core.api.DocumentModel;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
66 * AuthorityDocumentModelHandler
68 * $LastChangedRevision: $
71 public abstract class AuthorityDocumentModelHandler<AuthCommon>
72 extends NuxeoDocumentModelHandler<AuthCommon> {
74 private final Logger logger = LoggerFactory.getLogger(AuthorityDocumentModelHandler.class);
75 protected String authorityCommonSchemaName;
76 protected String authorityItemCommonSchemaName;
78 public AuthorityDocumentModelHandler(String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
79 this.authorityCommonSchemaName = authorityCommonSchemaName;
80 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
84 * The entity type expected from the JAX-RS Response object
86 public Class<String> getEntityResponseType() {
90 protected PayloadInputPart extractPart(Response res, String partLabel)
92 PoxPayloadIn input = new PoxPayloadIn((String)res.readEntity(getEntityResponseType()));
93 PayloadInputPart payloadInputPart = input.getPart(partLabel);
94 if (payloadInputPart == null) {
95 logger.error("Part " + partLabel + " was unexpectedly null.");
97 return payloadInputPart;
101 public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
102 boolean result = false;
103 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
104 Specifier specifier = (Specifier) wrapDoc.getWrappedObject();
106 // Get the rev number of the authority so we can compare with rev number of shared authority
108 DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, specifier);
109 Long rev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
110 String shortId = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
111 String refName = (String) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REF_NAME);
113 // Using the short ID of the local authority, created a URN specifier to retrieve the SAS authority
115 Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, RefNameUtils.createShortIdRefName(shortId));
116 PoxPayloadIn sasPayloadIn = getPayloadIn(ctx, sasSpecifier);
118 Long sasRev = getRevision(sasPayloadIn);
120 ResourceMap resourceMap = ctx.getResourceMap();
121 String resourceName = ctx.getClient().getServiceName();
122 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
123 PoxPayloadOut payloadOut = authorityResource.update(ctx, resourceMap, null, docModel.getName(), sasPayloadIn);
124 if (payloadOut != null) {
125 ctx.setOutput(payloadOut);
133 private PoxPayloadIn getPayloadIn(ServiceContext ctx, Specifier specifier) throws Exception {
134 PoxPayloadIn result = null;
136 AuthorityClient client = (AuthorityClient) ctx.getClient();
137 Response res = client.read(specifier.value);
139 int statusCode = res.getStatus();
141 // Check the status code of the response: does it match
142 // the expected response(s)?
143 if (logger.isDebugEnabled()) {
144 logger.debug(client.getClass().getCanonicalName() + ": status = " + statusCode);
147 result = new PoxPayloadIn((String)res.readEntity(getEntityResponseType())); // Get the entire response!
156 * Non standard injection of CSID into common part, since caller may access through
157 * shortId, and not know the CSID.
158 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
161 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
163 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
165 // Add the CSID to the common part
166 if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) {
167 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
168 unQObjectProperties.put("csid", csid);
171 return unQObjectProperties;
174 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
175 super.fillAllParts(wrapDoc, action);
177 // Update the record's revision number on both CREATE and UPDATE actions
179 updateRevNumbers(wrapDoc);
182 protected void updateRevNumbers(DocumentWrapper<DocumentModel> wrapDoc) {
183 DocumentModel documentModel = wrapDoc.getWrappedObject();
184 Long rev = (Long)documentModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV);
190 documentModel.setProperty(authorityCommonSchemaName, AuthorityJAXBSchema.REV, rev);
194 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
195 super.handleCreate(wrapDoc);
197 // Uncomment once debugged and App layer is read to integrate
198 // Experimenting with this uncommented now ...
199 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityCommonSchemaName);
200 updateRefnameForAuthority(wrapDoc, authorityCommonSchemaName);//CSPACE-3178
203 protected String buildWhereForShortId(String name) {
204 return authorityCommonSchemaName
205 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
209 private boolean isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
213 private boolean temp_isUnique(DocumentModel docModel, String schemaName) throws DocumentException {
214 boolean result = true;
216 ServiceContext ctx = this.getServiceContext();
217 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
218 String nxqlWhereClause = buildWhereForShortId(shortIdentifier);
220 DocumentWrapper<DocumentModel> searchResultWrapper = getRepositoryClient(ctx).findDoc(ctx, nxqlWhereClause);
221 if (searchResultWrapper != null) {
223 if (logger.isInfoEnabled() == true) {
224 DocumentModel searchResult = searchResultWrapper.getWrappedObject();
225 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'",
226 shortIdentifier, searchResult.getName());
227 logger.trace(debugMsg);
230 } catch (DocumentNotFoundException e) {
231 // Not a problem, just means we couldn't find another authority with that short ID
238 * If no short identifier was provided in the input payload,
239 * generate a short identifier from the display name. Either way though,
240 * the short identifier needs to be unique.
242 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
243 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
244 String displayName = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.DISPLAY_NAME);
245 String shortDisplayName = "";
246 String generateShortIdentifier = null;
247 if (Tools.isEmpty(shortIdentifier)) {
248 generateShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
249 docModel.setProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER, shortIdentifier);
252 if (isUnique(docModel, schemaName) == false) {
253 String shortId = generateShortIdentifier == null ? shortIdentifier : generateShortIdentifier;
254 String errMsgVerb = generateShortIdentifier == null ? "supplied" : "generated";
255 String errMsg = String.format("The %s short identifier '%s' was not unique, so the new authority could not be created.",
256 errMsgVerb, shortId);
257 throw new DocumentException(errMsg);
262 * Generate a refName for the authority from the short identifier
265 * All refNames for authorities are generated. If a client supplies
266 * a refName, it will be overwritten during create (per this method)
267 * or discarded during update (per filterReadOnlyPropertiesForPart).
269 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
272 protected void updateRefnameForAuthority(DocumentWrapper<DocumentModel> wrapDoc, String schemaName) throws Exception {
273 DocumentModel docModel = wrapDoc.getWrappedObject();
274 RefName.Authority authority = (Authority) getRefName(getServiceContext(), docModel);
275 String refName = authority.toString();
276 docModel.setProperty(schemaName, AuthorityJAXBSchema.REF_NAME, refName);
280 public RefName.RefNameInterface getRefName(ServiceContext ctx,
281 DocumentModel docModel) {
282 RefName.RefNameInterface refname = null;
285 String shortIdentifier = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
286 String displayName = (String) docModel.getProperty(authorityCommonSchemaName, AuthorityJAXBSchema.DISPLAY_NAME);
287 RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
288 ctx.getServiceName(),
289 null, // Only use shortId form!!!
293 } catch (Exception e) {
294 logger.error(e.getMessage(), e);
301 protected String getRefnameDisplayName(DocumentWrapper<DocumentModel> docWrapper) {
302 String result = null;
304 DocumentModel docModel = docWrapper.getWrappedObject();
305 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
306 RefName.Authority refname = (RefName.Authority)getRefName(ctx, docModel);
307 result = refname.getDisplayName();
312 public String getShortIdentifier(String authCSID, String schemaName) throws Exception {
313 String shortIdentifier = null;
314 CoreSessionInterface repoSession = null;
316 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
317 RepositoryClientImpl nuxeoRepoClient = (RepositoryClientImpl)this.getRepositoryClient(ctx);
319 repoSession = nuxeoRepoClient.getRepositorySession(ctx);
320 DocumentWrapper<DocumentModel> wrapDoc = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, authCSID);
321 DocumentModel docModel = wrapDoc.getWrappedObject();
322 if (docModel == null) {
323 throw new DocumentNotFoundException(String.format("Could not find authority resource with CSID='%s'.", authCSID));
325 shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityJAXBSchema.SHORT_IDENTIFIER);
326 } catch (ClientException ce) {
327 throw new RuntimeException("AuthorityDocHandler Internal Error: cannot get shortId!", ce);
329 if (repoSession != null) {
330 nuxeoRepoClient.releaseRepositorySession(ctx, repoSession);
334 return shortIdentifier;
338 * Filters out selected values supplied in an update request.
340 * @param objectProps the properties filtered out from the update payload
341 * @param partMeta metadata for the object to fill
344 public void filterReadOnlyPropertiesForPart(
345 Map<String, Object> objectProps, ObjectPartType partMeta) {
346 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
347 String commonPartLabel = getServiceContext().getCommonPartLabel();
348 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
349 objectProps.remove(AuthorityJAXBSchema.CSID);
350 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
351 objectProps.remove(AuthorityJAXBSchema.REF_NAME);