]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
6ca1012de64a49cac4d602d40f5411b2ef685bfa
[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.common.vocabulary.nuxeo;
25
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.ListIterator;
31 import java.util.Map;
32
33 import org.collectionspace.services.client.PayloadInputPart;
34 import org.collectionspace.services.client.PayloadOutputPart;
35 import org.collectionspace.services.client.PoxPayloadIn;
36 import org.collectionspace.services.client.PoxPayloadOut;
37 import org.collectionspace.services.client.RelationClient;
38 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
39 import org.collectionspace.services.common.api.CommonAPI;
40 import org.collectionspace.services.common.api.Tools;
41 import org.collectionspace.services.common.context.MultipartServiceContext;
42 import org.collectionspace.services.common.context.ServiceContext;
43 import org.collectionspace.services.common.document.DocumentWrapper;
44 import org.collectionspace.services.common.relation.IRelationsManager;
45 import org.collectionspace.services.common.service.ObjectPartType;
46 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
47 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
48 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
49 import org.collectionspace.services.relation.RelationResource;
50 import org.collectionspace.services.relation.RelationsCommon;
51 import org.collectionspace.services.relation.RelationsCommonList;
52 import org.collectionspace.services.relation.RelationsDocListItem;
53 import org.collectionspace.services.relation.RelationshipType;
54 import org.nuxeo.ecm.core.api.DocumentModel;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import javax.management.relation.Relation;
59 import javax.ws.rs.core.MultivaluedMap;
60 import javax.ws.rs.core.UriInfo;
61
62 /**
63  * AuthorityItemDocumentModelHandler
64  *
65  * $LastChangedRevision: $
66  * $LastChangedDate: $
67  */
68 public abstract class AuthorityItemDocumentModelHandler<AICommon, AICommonList>
69         extends RemoteDocumentModelHandlerImpl<AICommon, AICommonList> {
70
71     private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
72
73         private String authorityItemCommonSchemaName;
74         
75     //private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
76     /**
77      * item is used to stash JAXB object to use when handle is called
78      * for Action.CREATE, Action.UPDATE or Action.GET
79      */
80     protected AICommon item;
81     /**
82      * itemList is stashed when handle is called
83      * for ACTION.GET_ALL
84      */
85     protected AICommonList itemList;
86     
87     /**
88      * inVocabulary is the parent Authority for this context
89      */
90     protected String inAuthority;
91     
92     public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
93         this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
94     }
95
96     public String getInAuthority() {
97                 return inAuthority;
98         }
99
100         public void setInAuthority(String inAuthority) {
101                 this.inAuthority = inAuthority;
102         }
103
104     /* (non-Javadoc)
105      * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
106      */
107     @Override
108     public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
109         // first fill all the parts of the document
110         super.handleCreate(wrapDoc);            
111         handleInAuthority(wrapDoc.getWrappedObject());
112     }
113     
114     /**
115      * Check the logic around the parent pointer. Note that we only need do this on
116      * create, since we have logic to make this read-only on update. 
117      * 
118      * @param docModel
119      * 
120      * @throws Exception the exception
121      */
122     private void handleInAuthority(DocumentModel docModel) throws Exception {
123         docModel.setProperty(authorityItemCommonSchemaName, 
124                         AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
125     }
126
127
128     /**
129      * getCommonPart get associated item
130      * @return
131      */
132     @Override
133     public AICommon getCommonPart() {
134         return item;
135     }
136
137     @Override
138     public void setCommonPart(AICommon item) {
139         this.item = item;
140     }
141
142     /**
143      * getCommonPartList get associated item (for index/GET_ALL)
144      * @return
145      */
146     @Override
147     public AICommonList getCommonPartList() {
148         return itemList;
149     }
150
151     @Override
152     public void setCommonPartList(AICommonList itemList) {
153         this.itemList = itemList;
154     }
155
156     @Override
157     public AICommon extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc)
158             throws Exception {
159         throw new UnsupportedOperationException();
160     }
161
162     @Override
163     public void fillCommonPart(AICommon itemObject, DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
164         throw new UnsupportedOperationException();
165     }
166     
167     /* (non-Javadoc)
168      * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
169      */
170     @Override
171     protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
172             throws Exception {
173         Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
174         
175         // Add the CSID to the common part
176         if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
177                 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
178                 unQObjectProperties.put("csid", csid);
179         }
180         
181         return unQObjectProperties;
182     }
183     
184     /**
185      * Filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure that
186      * the parent link remains untouched.
187      * @param objectProps the properties parsed from the update payload
188      * @param partMeta metadata for the object to fill
189      */
190     @Override
191     public void filterReadOnlyPropertiesForPart(
192                 Map<String, Object> objectProps, ObjectPartType partMeta) {
193         super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
194         objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
195         objectProps.remove(AuthorityItemJAXBSchema.CSID);
196     }
197
198      @Override
199     public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
200             throws Exception {
201         MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
202         super.extractAllParts(wrapDoc);
203          String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
204          if (!Tools.isTrue(showRelations)){
205              return;
206          }
207          String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
208
209          String predicate = RelationshipType.HAS_BROADER.value();
210          RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
211          List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
212
213          RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
214          List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
215
216          //Assume that there are more children than parents.  Will be true for parent/child, but maybe not for other relations.
217          //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
218          //Not optimal, but that's the current design spec.
219         long added = 0;
220         for (RelationsCommonList.RelationListItem parent : parentList) {
221              childrenList.add(parent);
222              added++;
223         }
224         long childrenSize = childrenList.size();
225         childrenListOuter.setTotalItems(childrenSize);
226         childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage()+added);
227
228         PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
229         ctx.addOutputPart(relationsPart);
230     }
231
232     public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
233         super.fillAllParts(wrapDoc, action);
234         ServiceContext ctx = getServiceContext();
235         PoxPayloadIn input = (PoxPayloadIn)ctx.getInput();
236         DocumentModel documentModel = (wrapDoc.getWrappedObject());
237         String itemCsid = documentModel.getName();
238
239         //TODO: create all relations....  UPDATE and CREATE will call.   Updates AuthorityItem part
240         RelationsCommonList relationsCommonList = updateRelations(itemCsid, input);
241         PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
242         ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
243     }
244
245     public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
246         super.completeUpdate(wrapDoc);
247         //now we add part for relations list
248         ServiceContext ctx = getServiceContext();
249         PayloadOutputPart foo = (PayloadOutputPart)ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
250         ((PoxPayloadOut)ctx.getOutput()).addPart(foo);
251     }
252
253     //===================================================================
254     /*
255         for (RelationsCommonList.RelationListItem parentListItem : parentList.getRelationListItem()) {
256             System.out.println("    parentListItems " + parentListItem);
257             //todo: if num-parents > 1 then complain.
258             //todo: if not found in update list, remove from system
259             //todo: if update list item not found in parent list, add to system.
260         }
261         for (RelationsCommonList.RelationListItem childListItem : childList.getRelationListItem()) {
262            System.out.println("    childListItem: " + childListItem);
263             //todo: if not found in update list, remove from system
264             //todo: if update list item not found in child list, add to system.
265         }
266
267
268
269      */
270     public RelationsCommonList updateRelations(String itemCSID, PoxPayloadIn input) throws Exception {
271         PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME);        //input.getPart("relations_common");
272         if (part == null) {
273             //System.out.println("Nothing to do in updateRelations: " + input);
274             return null;
275         }
276         RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
277
278         ServiceContext ctx = getServiceContext();
279         UriInfo uriInfo = ctx.getUriInfo();
280         MultivaluedMap queryParams = uriInfo.getQueryParameters();
281
282         String predicate = RelationshipType.HAS_BROADER.value();
283         queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
284         queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
285         queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
286         queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
287         queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
288
289         RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo());    //magically knows all query params because they are in the context.
290
291         //Leave predicate, swap subject and object.
292         queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
293         queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
294         queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
295
296         RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
297         /*
298             go through inboundList, remove anything from childList that matches  from childList
299             go through inboundList, remove anything from parentList that matches  from parentList
300             go through parentList, delete all remaining
301             go through childList, delete all remaining
302             go through actionList, add all remaining.
303             check for duplicate children
304             check for more than one parent.
305
306         inboundList                           parentList                      childList          actionList
307         ----------------                          ---------------                  ----------------       ----------------
308         child-a                                   parent-c                        child-a             child-b
309         child-b                                   parent-d                        child-c
310          parent-a
311            */
312         String HAS_BROADER = RelationshipType.HAS_BROADER.value();
313
314         List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
315         List<RelationsCommonList.RelationListItem> actionList = newList();
316         List<RelationsCommonList.RelationListItem> childList = childListOuter.getRelationListItem();
317         List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
318
319         for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
320             if (inboundItem.getObject().getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)){
321                 inboundItem.setObjectCsid(itemCSID);
322                 inboundItem.getObject().setCsid(itemCSID);
323             }
324             if (inboundItem.getSubject().getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)){
325                 inboundItem.setSubjectCsid(itemCSID);
326                 inboundItem.getSubject().setCsid(itemCSID);
327             }
328             if (inboundItem.getObject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
329                 //then this is an item that says we have a child.
330                 RelationsCommonList.RelationListItem childItem = findInList(childList, inboundItem);
331                 if (childItem != null){
332                     removeFromList(childList,  childItem);    //exists, just take it off delete list
333                 } else {
334                     actionList.add(inboundItem);   //doesn't exist as a child, but is a child.  Add to additions list
335                 }
336             } else if  (inboundItem.getSubject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
337                 //then this is an item that says we have a parent
338                 RelationsCommonList.RelationListItem parentItem = findInList(parentList, inboundItem);
339                 if (parentItem != null){
340                     removeFromList(parentList,  parentItem);    //exists, just take it off delete list
341                 } else {
342                     actionList.add(inboundItem);   //doesn't exist as a parent, but is a parent. Add to additions list
343                 }
344             }  else {
345
346                 System.out.println("\r\n\r\n================\r\n    Element didn't match parent or child, but may have partial fields that match. inboundItem: "+inboundItem);
347                 //not dealing with: hasNarrower or any other predicate.
348             }
349         }
350         deleteRelations(parentList, ctx);               //todo: there are items appearing on both lists....april 20.
351         deleteRelations(childList, ctx);
352         createRelations(actionList, ctx);
353
354         return relationsCommonListBody;
355     }
356
357     private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx){
358          for (RelationsCommonList.RelationListItem item : inboundList) {
359              RelationsCommon rc = new RelationsCommon();
360              //rc.setCsid(item.getCsid());
361              String itemCsid =  item.getSubject().getCsid();
362              rc.setDocumentId1(itemCsid);
363              rc.setSubjectCsid(itemCsid);
364
365              String objCsid = item.getObject().getCsid();
366              rc.setDocumentId2(objCsid);
367              rc.setObjectCsid(objCsid);
368
369              rc.setRelationshipType(item.getPredicate());
370              //RelationshipType  foo = (RelationshipType.valueOf(item.getPredicate())) ;
371              //rc.setPredicate(foo);
372
373              rc.setDocumentType1(item.getSubject().getDocumentType());
374              rc.setDocumentType2(item.getObject().getDocumentType());
375
376             PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
377             PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
378             payloadOut.addPart(outputPart);
379             //System.out.println("\r\n==== TO CREATE: "+rc.getDocumentId1()+"==>"+rc.getPredicate()+"==>"+rc.getDocumentId2());
380             RelationResource relationResource = new RelationResource();
381             Object res = relationResource.create(ctx.getUriInfo(), payloadOut.toXML());    //NOTE ui recycled from above to pass in unknown query params.
382         }
383     }
384      private void deleteRelations(List<RelationsCommonList.RelationListItem> list,ServiceContext ctx){
385           try {
386               for (RelationsCommonList.RelationListItem inboundItem : list) {
387                   RelationResource relationResource = new RelationResource();
388                   //System.out.println("\r\n==== TO DELETE: "+inboundItem.getCsid());
389                   Object res = relationResource.delete(inboundItem.getCsid());
390               }
391           } catch (Throwable t){
392               String msg = "Unable to deleteRelations: "+ Tools.errorToString(t, true);
393               logger.error(msg);
394           }
395      }
396
397     private  List<RelationsCommonList.RelationListItem> newList(){
398         List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
399         return result;
400     }
401      protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList){
402         List<RelationsCommonList.RelationListItem> result = newList();
403         for (RelationsCommonList.RelationListItem item: inboundList){
404             result.add(item);
405         }
406         return result;
407     }
408      private RelationsCommonList.RelationListItem findInList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
409          for (RelationsCommonList.RelationListItem listItem : list) {
410              if (itemsEqual(listItem, item)){   //equals must be defined, else
411                 return listItem;
412              }
413          }
414          return null;
415      }
416
417     private boolean itemsEqual(RelationsCommonList.RelationListItem item, RelationsCommonList.RelationListItem item2){
418         if (item==null || item2==null){
419             return false;
420         }
421         RelationsDocListItem subj1 = item.getSubject();
422         RelationsDocListItem subj2 = item2.getSubject();
423         RelationsDocListItem obj1 = item.getObject();
424         RelationsDocListItem obj2 = item2.getObject();
425
426         return     (subj1.getCsid().equals(subj2.getCsid()))
427                 && (obj1.getCsid().equals(obj1.getCsid()))
428                 && ( (item.getPredicate().equals(item2.getPredicate()))
429                 && (item.getRelationshipType().equals(item2.getRelationshipType()))   )
430                 && (obj1.getDocumentType().equals(obj2.getDocumentType()))
431                 && (subj1.getDocumentType().equals(subj2.getDocumentType())) ;
432     }
433
434      private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
435         list.remove(item);
436     }
437     //================= TODO: move this to common, refactoring this and  CollectionObjectResource.java
438
439     public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
440         ServiceContext ctx = getServiceContext();
441         MultivaluedMap queryParams = ctx.getQueryParams();
442         queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
443         queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
444         queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
445
446         RelationResource relationResource = new RelationResource();
447         RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
448         return relationsCommonList;
449     }
450
451     //============================= END refactor ==========================
452
453 }
454