]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
e6531db607806982adf6f83005000ffd202c107d
[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(relationDocModel, SUBJ_DOC_MODEL);
120         DocumentModel objectDocModel = getSubjectOrObjectDocModel(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                 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, this.getRepositorySession(), 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(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 = (String) subjectOrObjectDocModel.getType();
362                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_DOCTYPE:RelationJAXBSchema.OBJECT_DOCTYPE),
363                                                         doctype);
364         
365                 String csid = (String) subjectOrObjectDocModel.getName();
366                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_CSID:RelationJAXBSchema.OBJECT_CSID),
367                                                         csid);
368         
369                 String uri = (String) subjectOrObjectDocModel.getProperty(COLLECTIONSPACE_CORE_SCHEMA,
370                                                                                                                                         COLLECTIONSPACE_CORE_URI);
371                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_URI:RelationJAXBSchema.OBJECT_URI),
372                                                         uri);
373                 
374                 String common_schema = getCommonSchemaNameForDocType(doctype);
375                 
376                 if(common_schema!=null) {
377                         String refname = (String)subjectOrObjectDocModel.getProperty(common_schema, 
378                                                                                                                         RefName.REFNAME );
379                     properties.put((fSubject?RelationJAXBSchema.SUBJECT_REFNAME:RelationJAXBSchema.OBJECT_REFNAME),
380                                 refname);
381                 }
382         } catch (ClientException ce) {
383             throw new RuntimeException(
384                     "populateSubjectOrObjectValues: Problem fetching field " + ce.getLocalizedMessage());
385         }
386
387         // FIXME: Call below is based solely on Nuxeo API docs; have not yet verified that it correctly updates existing
388         // property values in the target document model.
389         try {
390                 relationDocModel.setProperties(ctx.getCommonPartLabel(), properties);
391         } catch (ClientException ce) {
392             throw new RuntimeException(
393                     "populateSubjectValues: Problem setting fields " + ce.getLocalizedMessage());
394         }
395     }
396     
397     private String getCommonSchemaNameForDocType(String docType) {
398         String common_schema = null;
399         if("Person".equals(docType))
400                 common_schema = PersonAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
401         else if("Organization".equals(docType))
402                 common_schema = OrgAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
403         else if("Locationitem".equals(docType))
404                 common_schema = LocationAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
405         else if("Taxon".equals(docType))
406                 common_schema = TaxonomyAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
407         //else leave it null.
408         return common_schema;
409     }
410
411 }