]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
a14a6294bb58b93d325129c27fc0c1ed22af73e0
[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.relation.nuxeo;
25
26 import java.util.HashMap;
27 import java.util.Iterator;
28
29 import org.collectionspace.services.client.PoxPayloadIn;
30 import org.collectionspace.services.client.PoxPayloadOut;
31 import org.collectionspace.services.common.ResourceBase;
32 import org.collectionspace.services.common.ServiceMain;
33 import org.collectionspace.services.common.api.RefName;
34 import org.collectionspace.services.common.api.Tools;
35 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
36 import org.collectionspace.services.common.context.ServiceBindingUtils;
37 import org.collectionspace.services.common.document.DocumentNotFoundException;
38 import org.collectionspace.services.common.document.DocumentWrapper;
39 import org.collectionspace.services.common.document.InvalidDocumentException;
40 import org.collectionspace.services.common.relation.RelationJAXBSchema;
41 import org.collectionspace.services.common.relation.nuxeo.RelationConstants;
42 import org.collectionspace.services.common.context.ServiceContext;
43 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
44 import org.collectionspace.services.relation.RelationsCommon;
45 import org.collectionspace.services.relation.RelationsCommonList;
46 import org.collectionspace.services.relation.RelationsCommonList.RelationListItem;
47 import org.collectionspace.services.relation.RelationsDocListItem;
48
49 // HACK HACK HACK
50 import org.collectionspace.services.client.PersonAuthorityClient;
51 import org.collectionspace.services.client.OrgAuthorityClient;
52 import org.collectionspace.services.client.LocationAuthorityClient;
53 import org.collectionspace.services.client.TaxonomyAuthorityClient;
54 import org.collectionspace.services.client.PlaceAuthorityClient;
55 import org.collectionspace.services.client.ConceptAuthorityClient;
56
57 import org.collectionspace.services.config.service.ServiceBindingType;
58 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
59 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
60 import org.nuxeo.ecm.core.api.ClientException;
61 import org.nuxeo.ecm.core.api.CoreSession;
62 import org.nuxeo.ecm.core.api.DocumentModel;
63 import org.nuxeo.ecm.core.api.DocumentModelList;
64 import org.nuxeo.ecm.core.api.model.PropertyException;
65 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 /**
70  * RelationDocumentModelHandler
71  *
72  * $LastChangedRevision: $
73  * $LastChangedDate: $
74  */
75 public class RelationDocumentModelHandler
76         extends RemoteDocumentModelHandlerImpl<RelationsCommon, RelationsCommonList> {
77
78     private final Logger logger = LoggerFactory.getLogger(RelationDocumentModelHandler.class);
79     /**
80      * relation is used to stash JAXB object to use when handle is called
81      * for Action.CREATE, Action.UPDATE or Action.GET
82      */
83     private RelationsCommon relation;
84     /**
85      * relationList is stashed when handle is called
86      * for ACTION.GET_ALL
87      */
88     private RelationsCommonList relationList;
89
90     @Override
91     public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
92         // Merge in the data from the payload
93         super.handleCreate(wrapDoc);
94
95         // And take care of ensuring all the values for the relation info are correct 
96         populateSubjectAndObjectValues(wrapDoc);
97     }
98
99     @Override
100     public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
101         // Merge in the data from the payload
102         super.handleUpdate(wrapDoc);
103         
104         // And take care of ensuring all the values for the relation info are correct 
105         populateSubjectAndObjectValues(wrapDoc);
106     }
107     
108     private void populateSubjectAndObjectValues(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
109         // Obtain document models for the subject and object of the relation, so that
110         // we ensure we have value docType, URI info. If the docModels support refNames, 
111         // we will also set those.
112         // Note that this introduces another caching problem... 
113         DocumentModel relationDocModel = wrapDoc.getWrappedObject();
114         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
115         RepositoryInstance repoSession = this.getRepositorySession();
116         
117         DocumentModel subjectDocModel = getSubjectOrObjectDocModel(repoSession, relationDocModel, SUBJ_DOC_MODEL);
118         DocumentModel objectDocModel = getSubjectOrObjectDocModel(repoSession, relationDocModel, OBJ_DOC_MODEL);
119
120         // Use values from the subject and object document models to populate the
121         // relevant fields of the relation's own document model.
122         if (subjectDocModel != null) {
123             populateSubjectOrObjectValues(relationDocModel, subjectDocModel, SUBJ_DOC_MODEL);
124         }
125         if (objectDocModel != null) {
126             populateSubjectOrObjectValues(relationDocModel, objectDocModel, OBJ_DOC_MODEL);
127         }
128     }
129
130     @Override
131     public RelationsCommon getCommonPart() {
132         return relation;
133     }
134
135     @Override
136     public void setCommonPart(RelationsCommon theRelation) {
137         this.relation = theRelation;
138     }
139
140     /**get associated Relation (for index/GET_ALL)
141      */
142     @Override
143     public RelationsCommonList getCommonPartList() {
144         return relationList;
145     }
146
147     @Override
148     public void setCommonPartList(RelationsCommonList theRelationList) {
149         this.relationList = theRelationList;
150     }
151
152     @Override
153     public RelationsCommon extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc)
154             throws Exception {
155         throw new UnsupportedOperationException();
156     }
157
158     @Override
159     public void fillCommonPart(RelationsCommon theRelation, DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
160         throw new UnsupportedOperationException();
161     }
162
163     @Override
164     public RelationsCommonList extractCommonPartList(DocumentWrapper<DocumentModelList> wrapDoc) throws Exception {
165         RelationsCommonList relList = this.extractPagingInfo(new RelationsCommonList(), wrapDoc);
166         relList.setFieldsReturned("subjectCsid|relationshipType|predicateDisplayName|objectCsid|uri|csid|subject|object");
167         ServiceContext ctx = getServiceContext();
168         String serviceContextPath = getServiceContextPath();
169
170         TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance().getTenantBindingConfigReader();
171         String serviceName = getServiceContext().getServiceName().toLowerCase();
172         ServiceBindingType sbt = tReader.getServiceBinding(ctx.getTenantId(), serviceName);
173
174         Iterator<DocumentModel> iter = wrapDoc.getWrappedObject().iterator();
175         while (iter.hasNext()) {
176             DocumentModel docModel = iter.next();
177             RelationListItem relListItem = getRelationListItem(ctx, sbt, tReader, docModel, serviceContextPath);
178             relList.getRelationListItem().add(relListItem);
179         }
180         return relList;
181     }
182
183     /** Gets the relation list item, looking up the subject and object documents, and getting summary
184      *  info via the objectName and objectNumber properties in tenant-bindings.
185      * @param ctx the ctx
186      * @param sbt the ServiceBindingType of Relations service
187      * @param tReader the tenant-bindings reader, for looking up docnumber and docname
188      * @param docModel the doc model
189      * @param serviceContextPath the service context path
190      * @return the relation list item, with nested subject and object summary info.
191      * @throws Exception the exception
192      */
193     private RelationListItem getRelationListItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
194             ServiceBindingType sbt,
195             TenantBindingConfigReaderImpl tReader,
196             DocumentModel docModel,
197             String serviceContextPath) throws Exception {
198         RelationListItem relationListItem = new RelationListItem();
199         String id = getCsid(docModel);
200         relationListItem.setCsid(id);
201
202         relationListItem.setSubjectCsid((String) docModel.getProperty(ctx.getCommonPartLabel(), 
203                                                                                                         RelationJAXBSchema.SUBJECT_CSID));
204
205         String predicate = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
206                                                                                                         RelationJAXBSchema.RELATIONSHIP_TYPE);
207         relationListItem.setRelationshipType(predicate);
208         relationListItem.setPredicate(predicate); //predicate is new name for relationshipType.
209         relationListItem.setPredicateDisplayName((String) docModel.getProperty(ctx.getCommonPartLabel(), 
210                                                                                                         RelationJAXBSchema.RELATIONSHIP_TYPE_DISPLAYNAME));
211
212         relationListItem.setObjectCsid((String) docModel.getProperty(ctx.getCommonPartLabel(), 
213                                                                                                         RelationJAXBSchema.OBJECT_CSID));
214
215         relationListItem.setUri(serviceContextPath + id);
216
217         //Now fill in summary info for the related docs: subject and object.
218         String subjectCsid = relationListItem.getSubjectCsid();
219         String subjectDocumentType = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
220                                                                                                         RelationJAXBSchema.SUBJECT_DOCTYPE);
221         RelationsDocListItem subject = createRelationsDocListItem(ctx, sbt, subjectCsid, tReader, subjectDocumentType);
222
223         String subjectUri = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
224                                                                                                         RelationJAXBSchema.SUBJECT_URI);
225         subject.setUri(subjectUri);
226         String subjectRefName = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
227                                                                                                         RelationJAXBSchema.SUBJECT_REFNAME);
228         subject.setRefName(subjectRefName);
229         relationListItem.setSubject(subject);
230
231         String objectCsid = relationListItem.getObjectCsid();
232         String objectDocumentType = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
233                                                                                                         RelationJAXBSchema.OBJECT_DOCTYPE);
234         RelationsDocListItem object = createRelationsDocListItem(ctx, sbt, objectCsid, tReader, objectDocumentType);
235
236         String objectUri = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
237                                                                                                         RelationJAXBSchema.OBJECT_URI);
238         object.setUri(objectUri);
239         String objectRefName = (String) docModel.getProperty(ctx.getCommonPartLabel(), 
240                                                                                                         RelationJAXBSchema.OBJECT_REFNAME);
241         object.setRefName(objectRefName);
242         relationListItem.setObject(object);
243
244         return relationListItem;
245     }
246
247     // DocumentModel itemDocModel = docModelFromCSID(ctx, itemCsid);
248     protected RelationsDocListItem createRelationsDocListItem(
249                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
250             ServiceBindingType sbt,
251             String itemCsid,
252             TenantBindingConfigReaderImpl tReader,
253             String documentType) throws Exception {
254         RelationsDocListItem item = new RelationsDocListItem();
255         item.setDocumentType(documentType);//this one comes from the record, as subjectDocumentType, objectDocumentType.
256         item.setCsid(itemCsid);
257
258         DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(ctx, this.getRepositorySession(), itemCsid);    //null if not found.
259         if (itemDocModel != null) {
260             String itemDocType = itemDocModel.getDocumentType().getName();
261             itemDocType = ServiceBindingUtils.getUnqualifiedTenantDocType(itemDocType);
262             if (Tools.isBlank(documentType)) {
263                 item.setDocumentType(itemDocType);
264             }
265
266             //TODO: ensure that itemDocType is really the entry point, i.e. servicename==doctype
267             //ServiceBindingType itemSbt2 = tReader.getServiceBinding(ctx.getTenantId(), itemDocType);
268             String propName = "ERROR-FINDING-PROP-VALUE";
269             ServiceBindingType itemSbt = tReader.getServiceBindingForDocType(ctx.getTenantId(), itemDocType);
270             try {
271                 propName = ServiceBindingUtils.getPropertyValue(itemSbt, ServiceBindingUtils.OBJ_NAME_PROP);
272                 String itemDocname = ServiceBindingUtils.getMappedFieldInDoc(itemSbt, ServiceBindingUtils.OBJ_NAME_PROP, itemDocModel);
273                 if (propName == null || itemDocname == null) {
274                 } else {
275                     item.setName(itemDocname);
276                 }
277             } catch (Throwable t) {
278                 logger.error("====Error finding objectNameProperty: " + itemDocModel + " field " + ServiceBindingUtils.OBJ_NAME_PROP + "=" + propName
279                         + " not found in itemDocType: " + itemDocType + " inner: " + t.getMessage());
280             }
281             propName = "ERROR-FINDING-PROP-VALUE";
282             try {
283                 propName = ServiceBindingUtils.getPropertyValue(itemSbt, ServiceBindingUtils.OBJ_NUMBER_PROP);
284                 String itemDocnumber = ServiceBindingUtils.getMappedFieldInDoc(itemSbt, ServiceBindingUtils.OBJ_NUMBER_PROP, itemDocModel);
285
286                 if (propName == null || itemDocnumber == null) {
287                 } else {
288                     item.setNumber(itemDocnumber);
289                 }
290             } catch (Throwable t) {
291                 logger.error("====Error finding objectNumberProperty: " + ServiceBindingUtils.OBJ_NUMBER_PROP + "=" + propName
292                         + " not found in itemDocType: " + itemDocType + " inner: " + t.getMessage());
293             }
294         } else {
295             item.setError("INVALID: related object is absent");
296             // Laramie20110510 CSPACE-3739  throw the exception for 3739, otherwise, don't throw it.
297             //throw new Exception("INVALID: related object is absent "+itemCsid);
298         }
299         return item;
300     }
301
302     @Override
303     public String getQProperty(String prop) {
304         return "/" + RelationConstants.NUXEO_SCHEMA_ROOT_ELEMENT + "/" + prop;
305     }
306
307     private final boolean SUBJ_DOC_MODEL = true;
308     private final boolean OBJ_DOC_MODEL = false;
309     
310     private DocumentModel getSubjectOrObjectDocModel(
311                 RepositoryInstance repoSession,
312                 DocumentModel relationDocModel,
313                 boolean fSubject) throws Exception {
314         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
315         
316         // Get the document model for the object of the relation.
317         String commonPartLabel = ctx.getCommonPartLabel();
318         String csid = "";
319         String refName = "";
320         DocumentModel docModel = null;
321         // FIXME: Currently assumes that the object CSID is valid if present
322         // in the incoming payload.
323         try {
324             csid = (String) relationDocModel.getProperty(commonPartLabel, 
325                         (fSubject?RelationJAXBSchema.SUBJECT_CSID:RelationJAXBSchema.OBJECT_CSID));
326         } catch (PropertyException pe) {
327             // Per CSPACE-4468, ignore any property exception here.
328             // The objectCsid and/or subjectCsid field in a relation record
329             // can now be null (missing), because a refName value can be
330             // provided as an alternate identifier.
331         }
332         if (Tools.notBlank(csid)) {
333                 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)getRepositoryClient(ctx);
334             DocumentWrapper<DocumentModel> docWrapper = nuxeoRepoClient.getDocFromCsid(ctx, repoSession, csid);
335             docModel = docWrapper.getWrappedObject();
336         } else { //  if (Tools.isBlank(objectCsid)) {
337             try {
338                 refName = (String) relationDocModel.getProperty(commonPartLabel, 
339                                 (fSubject?RelationJAXBSchema.SUBJECT_REFNAME:RelationJAXBSchema.OBJECT_REFNAME));
340                 docModel = ResourceBase.getDocModelForRefName(repoSession, refName, ctx.getResourceMap());
341             } catch (Exception e) {
342                 throw new InvalidDocumentException(
343                         "Relation record must have a CSID or refName to identify the object of the relation.", e);
344             }
345         }
346         if(docModel==null) {
347                 throw new DocumentNotFoundException("Relation.getSubjectOrObjectDocModel could not find doc with CSID: "
348                                         +csid+" and/or refName: "+refName );
349         }
350         return docModel;
351     }
352     
353     private void populateSubjectOrObjectValues(
354                 DocumentModel relationDocModel, 
355                 DocumentModel subjectOrObjectDocModel,
356                 boolean fSubject ) {
357         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = this.getServiceContext();
358         
359         HashMap<String,Object> properties = new HashMap<String,Object>();
360         try {
361                 String doctype = subjectOrObjectDocModel.getDocumentType().getName();
362             doctype = ServiceBindingUtils.getUnqualifiedTenantDocType(doctype);
363                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_DOCTYPE:RelationJAXBSchema.OBJECT_DOCTYPE),
364                                                         doctype);
365         
366                 String csid = (String) subjectOrObjectDocModel.getName();
367                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_CSID:RelationJAXBSchema.OBJECT_CSID),
368                                                         csid);
369         
370                 String uri = (String) subjectOrObjectDocModel.getProperty(COLLECTIONSPACE_CORE_SCHEMA,
371                                                                                                                                         COLLECTIONSPACE_CORE_URI);
372                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_URI:RelationJAXBSchema.OBJECT_URI),
373                                                         uri);
374                 
375                 String common_schema = getCommonSchemaNameForDocType(doctype);
376                 
377                 if(common_schema!=null) {
378                         String refname = (String)subjectOrObjectDocModel.getProperty(common_schema, 
379                                                                                                                         RefName.REFNAME );
380                     properties.put((fSubject?RelationJAXBSchema.SUBJECT_REFNAME:RelationJAXBSchema.OBJECT_REFNAME),
381                                 refname);
382                 }
383         } catch (ClientException ce) {
384             throw new RuntimeException(
385                     "populateSubjectOrObjectValues: Problem fetching field " + ce.getLocalizedMessage());
386         }
387
388         // FIXME: Call below is based solely on Nuxeo API docs; have not yet verified that it correctly updates existing
389         // property values in the target document model.
390         try {
391                 relationDocModel.setProperties(ctx.getCommonPartLabel(), properties);
392         } catch (ClientException ce) {
393             throw new RuntimeException(
394                     "populateSubjectValues: Problem setting fields " + ce.getLocalizedMessage());
395         }
396     }
397     
398     private String getCommonSchemaNameForDocType(String docType) {
399         String common_schema = null;
400         if(docType!=null) {
401                 // HACK - Use startsWith to allow for extension of schemas.
402                 if(docType.startsWith("Person"))
403                         common_schema = PersonAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
404                 else if(docType.startsWith("Organization"))
405                         common_schema = OrgAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
406                 else if(docType.startsWith("Locationitem"))
407                         common_schema = LocationAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
408                 else if(docType.startsWith("Taxon"))
409                         common_schema = TaxonomyAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
410                 else if(docType.startsWith("Placeitem"))
411                         common_schema = PlaceAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
412                 else if(docType.startsWith("Conceptitem"))
413                         common_schema = ConceptAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
414                 //else leave it null.
415         }
416         return common_schema;
417     }
418
419 }