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