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