]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
dc38d6e6de17c4cfb4fef2b56676ecabb7e28262
[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.relation.RelationsDocListItem;
61 import org.nuxeo.ecm.core.api.ClientException;
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 ctx = getServiceContext();
115         DocumentModel subjectDocModel = getSubjectOrObjectDocModel(relationDocModel, ctx, SUBJ_DOC_MODEL);
116         DocumentModel objectDocModel = getSubjectOrObjectDocModel(relationDocModel, ctx, OBJ_DOC_MODEL);
117
118         // Use values from the subject and object document models to populate the
119         // relevant fields of the relation's own document model.
120         if (subjectDocModel != null) {
121             populateSubjectOrObjectValues(relationDocModel, subjectDocModel, ctx, SUBJ_DOC_MODEL);
122         }
123         if (objectDocModel != null) {
124             populateSubjectOrObjectValues(relationDocModel, objectDocModel, ctx, OBJ_DOC_MODEL);
125         }
126     }
127
128     @Override
129     public RelationsCommon getCommonPart() {
130         return relation;
131     }
132
133     @Override
134     public void setCommonPart(RelationsCommon theRelation) {
135         this.relation = theRelation;
136     }
137
138     /**get associated Relation (for index/GET_ALL)
139      */
140     @Override
141     public RelationsCommonList getCommonPartList() {
142         return relationList;
143     }
144
145     @Override
146     public void setCommonPartList(RelationsCommonList theRelationList) {
147         this.relationList = theRelationList;
148     }
149
150     @Override
151     public RelationsCommon extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc)
152             throws Exception {
153         throw new UnsupportedOperationException();
154     }
155
156     @Override
157     public void fillCommonPart(RelationsCommon theRelation, DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
158         throw new UnsupportedOperationException();
159     }
160
161     @Override
162     public RelationsCommonList extractCommonPartList(DocumentWrapper<DocumentModelList> wrapDoc) throws Exception {
163         RelationsCommonList relList = this.extractPagingInfo(new RelationsCommonList(), wrapDoc);
164         relList.setFieldsReturned("subjectCsid|relationshipType|predicateDisplayName|objectCsid|uri|csid|subject|object");
165         ServiceContext ctx = getServiceContext();
166         String serviceContextPath = getServiceContextPath();
167
168         TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance().getTenantBindingConfigReader();
169         String serviceName = getServiceContext().getServiceName().toLowerCase();
170         ServiceBindingType sbt = tReader.getServiceBinding(ctx.getTenantId(), serviceName);
171
172         Iterator<DocumentModel> iter = wrapDoc.getWrappedObject().iterator();
173         while (iter.hasNext()) {
174             DocumentModel docModel = iter.next();
175             RelationListItem relListItem = getRelationListItem(ctx, sbt, tReader, docModel, serviceContextPath);
176             relList.getRelationListItem().add(relListItem);
177         }
178         return relList;
179     }
180
181     /** Gets the relation list item, looking up the subject and object documents, and getting summary
182      *  info via the objectName and objectNumber properties in tenant-bindings.
183      * @param ctx the ctx
184      * @param sbt the ServiceBindingType of Relations service
185      * @param tReader the tenant-bindings reader, for looking up docnumber and docname
186      * @param docModel the doc model
187      * @param serviceContextPath the service context path
188      * @return the relation list item, with nested subject and object summary info.
189      * @throws Exception the exception
190      */
191     private RelationListItem getRelationListItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
192             ServiceBindingType sbt,
193             TenantBindingConfigReaderImpl tReader,
194             DocumentModel docModel,
195             String serviceContextPath) throws Exception {
196         RelationListItem relationListItem = new RelationListItem();
197         String id = getCsid(docModel);
198         relationListItem.setCsid(id);
199
200         relationListItem.setSubjectCsid((String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.DOCUMENT_ID_1));
201
202         String predicate = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.RELATIONSHIP_TYPE);
203         relationListItem.setRelationshipType(predicate);
204         relationListItem.setPredicate(predicate); //predicate is new name for relationshipType.
205         relationListItem.setPredicateDisplayName((String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.RELATIONSHIP_TYPE_DISPLAYNAME));
206
207         relationListItem.setObjectCsid((String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.DOCUMENT_ID_2));
208
209         relationListItem.setUri(serviceContextPath + id);
210
211         //Now fill in summary info for the related docs: subject and object.
212         String subjectCsid = relationListItem.getSubjectCsid();
213         String documentType = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.DOCUMENT_TYPE_1);
214         RelationsDocListItem subject = createRelationsDocListItem(ctx, sbt, subjectCsid, tReader, documentType);
215
216         //Object o1 =  docModel.getProperty(ctx.getCommonPartLabel(), "subject");
217         //Object o2 =  docModel.getProperty(ctx.getCommonPartLabel(), "object");
218
219         String subjectUri = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.SUBJECT_URI);
220         subject.setUri(subjectUri);
221         String subjectRefName = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.SUBJECT_REFNAME);
222         subject.setRefName(subjectRefName);
223         relationListItem.setSubject(subject);
224
225         String objectCsid = relationListItem.getObjectCsid();
226         String documentType2 = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.DOCUMENT_TYPE_2);
227         RelationsDocListItem object = createRelationsDocListItem(ctx, sbt, objectCsid, tReader, documentType2);
228
229         String objectUri = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.OBJECT_URI);
230         object.setUri(objectUri);
231         String objectRefName = (String) docModel.getProperty(ctx.getCommonPartLabel(), RelationJAXBSchema.OBJECT_REFNAME);
232         object.setRefName(objectRefName);
233         relationListItem.setObject(object);
234
235         return relationListItem;
236     }
237
238     // DocumentModel itemDocModel = docModelFromCSID(ctx, itemCsid);
239     protected RelationsDocListItem createRelationsDocListItem(ServiceContext ctx,
240             ServiceBindingType sbt,
241             String itemCsid,
242             TenantBindingConfigReaderImpl tReader,
243             String documentType) throws Exception {
244         RelationsDocListItem item = new RelationsDocListItem();
245         item.setDocumentType(documentType);//this one comes from the record, as documentType1, documentType2.
246         // CSPACE-4037 REMOVING: item.setService(documentType);//this one comes from the record, as documentType1, documentType2.   Current app seems to use servicename for this.
247         item.setCsid(itemCsid);
248
249         DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, itemCsid);    //null if not found.
250         if (itemDocModel != null) {
251             String itemDocType = itemDocModel.getDocumentType().getName();
252             // CSPACE-4037 REMOVING: item.setDocumentTypeFromModel(itemDocType);           //this one comes from the nuxeo documentType
253
254             //DEBUG: System.out.println("\r\n******** AuthorityItemDocumentModelHandlder documentType **************\r\n\tdocModel: "+itemDocType+"\r\n\tpayload: "+documentType);
255             //boolean usedDocumentTypeFromPayload = true;
256             /*if ( ! Tools.isBlank(documentType)){
257             if (documentType.equals(itemDocType)){
258             //usedDocumentTypeFromPayload = true;
259             }  else {
260             // Laramie20110510 CSPACE-3739  throw the exception for 3739, otherwise, don't throw it.
261             //throw new Exception("documentType supplied was wrong.  supplied: "+documentType+" required: "+itemDocType+ " itemCsid: "+itemCsid );
262             }
263             } else {
264             //usedDocumentTypeFromPayload = false;
265             item.setDocumentType(itemDocType);
266             }   */
267             if (Tools.isBlank(documentType)) {
268                 item.setDocumentType(itemDocType);
269             }
270
271             // TODO: clean all the output statements out of here when CSPACE-4037 is done.
272             //TODO: ensure that itemDocType is really the entry point, i.e. servicename==doctype
273             //ServiceBindingType itemSbt2 = tReader.getServiceBinding(ctx.getTenantId(), itemDocType);
274             String propName = "ERROR-FINDING-PROP-VALUE";
275             ServiceBindingType itemSbt = tReader.getServiceBindingForDocType(ctx.getTenantId(), itemDocType);
276             try {
277                 propName = ServiceBindingUtils.getPropertyValue(itemSbt, ServiceBindingUtils.OBJ_NAME_PROP);
278                 String itemDocname = ServiceBindingUtils.getMappedFieldInDoc(itemSbt, ServiceBindingUtils.OBJ_NAME_PROP, itemDocModel);
279                 if (propName == null || itemDocname == null) {
280                     //System.out.println("=== prop NOT found: "+ServiceBindingUtils.OBJ_NAME_PROP+"::"+propName+"="+itemDocname+" documentType: "+documentType);
281                 } else {
282                     item.setName(itemDocname);
283                     //System.out.println("=== found prop : "+ServiceBindingUtils.OBJ_NAME_PROP+"::"+propName+"="+itemDocname+" documentType: "+documentType);
284                 }
285             } catch (Throwable t) {
286                 System.out.println("====Error finding objectNameProperty: " + itemDocModel + " field " + ServiceBindingUtils.OBJ_NAME_PROP + "=" + propName
287                         + " not found in itemDocType: " + itemDocType + " inner: " + t.getMessage());
288             }
289             propName = "ERROR-FINDING-PROP-VALUE";
290             try {
291                 propName = ServiceBindingUtils.getPropertyValue(itemSbt, ServiceBindingUtils.OBJ_NUMBER_PROP);
292                 String itemDocnumber = ServiceBindingUtils.getMappedFieldInDoc(itemSbt, ServiceBindingUtils.OBJ_NUMBER_PROP, itemDocModel);
293
294                 if (propName == null || itemDocnumber == null) {
295                     //System.out.println("=== prop NOT found: "+ServiceBindingUtils.OBJ_NUMBER_PROP+"::"+propName+"="+itemDocnumber
296                     //                          +" documentType: "+documentType);
297                 } else {
298                     item.setNumber(itemDocnumber);
299                     //System.out.println("============ found prop : "+ServiceBindingUtils.OBJ_NUMBER_PROP+"::"+propName+"="+itemDocnumber
300                     //                          +" documentType: "+documentType);
301                 }
302             } catch (Throwable t) {
303                 logger.error("====Error finding objectNumberProperty: " + ServiceBindingUtils.OBJ_NUMBER_PROP + "=" + propName
304                         + " not found in itemDocType: " + itemDocType + " inner: " + t.getMessage());
305             }
306         } else {
307             item.setError("INVALID: related object is absent");
308             // Laramie20110510 CSPACE-3739  throw the exception for 3739, otherwise, don't throw it.
309             //throw new Exception("INVALID: related object is absent "+itemCsid);
310         }
311         return item;
312     }
313
314     @Override
315     public String getQProperty(String prop) {
316         return "/" + RelationConstants.NUXEO_SCHEMA_ROOT_ELEMENT + "/" + prop;
317     }
318
319     private final boolean SUBJ_DOC_MODEL = true;
320     private final boolean OBJ_DOC_MODEL = false;
321     
322     private DocumentModel getSubjectOrObjectDocModel(
323                 DocumentModel relationDocModel, ServiceContext ctx, boolean fSubject) throws Exception {
324         // Get the document model for the object of the relation.
325         String commonPartLabel = ctx.getCommonPartLabel();
326         String csid = "";
327         String refName = "";
328         DocumentModel docModel = null;
329         // FIXME: Currently assumes that the object CSID is valid if present
330         // in the incoming payload.
331         try {
332             csid = (String) relationDocModel.getProperty(commonPartLabel, 
333                         (fSubject?RelationJAXBSchema.SUBJECT_CSID:RelationJAXBSchema.OBJECT_CSID));
334             // FIXME: Remove this entire 'if' statement when legacy fields are removed from the Relation record:
335             if (Tools.isBlank(csid)) {
336                 csid = (String) relationDocModel.getProperty(commonPartLabel, 
337                                         (fSubject?RelationJAXBSchema.DOCUMENT_ID_1:RelationJAXBSchema.DOCUMENT_ID_2));
338             }
339         } catch (PropertyException pe) {
340             // Per CSPACE-4468, ignore any property exception here.
341             // The objectCsid and/or subjectCsid field in a relation record
342             // can now be null (missing), because a refName value can be
343             // provided as an alternate identifier.
344         }
345         if (Tools.notBlank(csid)) {
346             DocumentWrapper<DocumentModel> docWrapper = getRepositoryClient(ctx).getDocFromCsid(ctx, csid);
347             docModel = docWrapper.getWrappedObject();
348         } else { //  if (Tools.isBlank(objectCsid)) {
349             try {
350                 refName = (String) relationDocModel.getProperty(commonPartLabel, 
351                                 (fSubject?RelationJAXBSchema.SUBJECT_REFNAME:RelationJAXBSchema.OBJECT_REFNAME));
352                 docModel = ResourceBase.getDocModelForRefName(refName, ctx.getResourceMap());
353             } catch (Exception e) {
354                 throw new InvalidDocumentException(
355                         "Relation record must have a CSID or refName to identify the object of the relation.", e);
356             }
357         }
358         if(docModel==null) {
359                 throw new DocumentNotFoundException("Relation.getSubjectOrObjectDocModel could not find doc with CSID: "
360                                         +csid+" and/or refName: "+refName );
361         }
362         return docModel;
363     }
364     
365     private void populateSubjectOrObjectValues(
366                 DocumentModel relationDocModel, 
367                 DocumentModel subjectOrObjectDocModel,
368                 ServiceContext ctx,
369                 boolean fSubject ) {
370         HashMap<String,Object> properties = new HashMap<String,Object>();
371
372         try {
373                 String doctype = (String) subjectOrObjectDocModel.getType();
374                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_DOCTYPE:RelationJAXBSchema.OBJECT_DOCTYPE),
375                                                         doctype);
376                 // FIXME: Remove the line below when legacy fields are removed from the Relation record:
377                 properties.put((fSubject?RelationJAXBSchema.DOCUMENT_TYPE_1:RelationJAXBSchema.DOCUMENT_TYPE_2), 
378                                                         doctype);
379         
380                 String csid = (String) subjectOrObjectDocModel.getName();
381                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_CSID:RelationJAXBSchema.OBJECT_CSID),
382                                                         csid);
383                 // FIXME: Remove the two lines immediately below when legacy fields are removed from the Relation record:
384                 properties.put((fSubject?RelationJAXBSchema.DOCUMENT_ID_1:RelationJAXBSchema.DOCUMENT_ID_2),
385                                                         csid);
386         
387                 String uri = (String) subjectOrObjectDocModel.getProperty(COLLECTIONSPACE_CORE_SCHEMA,
388                                                                                                                                         COLLECTIONSPACE_CORE_URI);
389                 properties.put((fSubject?RelationJAXBSchema.SUBJECT_URI:RelationJAXBSchema.OBJECT_URI),
390                                                         uri);
391                 
392                 String common_schema = getCommonSchemaNameForDocType(doctype);
393                 
394                 if(common_schema!=null) {
395                         String refname = (String)subjectOrObjectDocModel.getProperty(common_schema, 
396                                                                                                                         RefName.REFNAME );
397                     properties.put((fSubject?RelationJAXBSchema.SUBJECT_REFNAME:RelationJAXBSchema.OBJECT_REFNAME),
398                                 refname);
399                 }
400         } catch (ClientException ce) {
401             throw new RuntimeException(
402                     "populateSubjectOrObjectValues: Problem fetching field " + ce.getLocalizedMessage());
403         }
404
405         // FIXME: Call below is based solely on Nuxeo API docs; have not yet verified that it correctly updates existing
406         // property values in the target document model.
407         try {
408                 relationDocModel.setProperties(ctx.getCommonPartLabel(), properties);
409         } catch (ClientException ce) {
410             throw new RuntimeException(
411                     "populateSubjectValues: Problem setting fields " + ce.getLocalizedMessage());
412         }
413     }
414     
415     private String getCommonSchemaNameForDocType(String docType) {
416         String common_schema = null;
417         if("Person".equals(docType))
418                 common_schema = PersonAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
419         else if("Organization".equals(docType))
420                 common_schema = OrgAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
421         else if("Locationitem".equals(docType))
422                 common_schema = LocationAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
423         else if("Taxon".equals(docType))
424                 common_schema = TaxonomyAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME;
425         //else leave it null.
426         return common_schema;
427     }
428
429 }