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