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