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:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
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.
24 package org.collectionspace.services.common.vocabulary.nuxeo;
26 import org.collectionspace.services.client.AuthorityClient;
27 import org.collectionspace.services.client.PayloadInputPart;
28 import org.collectionspace.services.client.PayloadOutputPart;
29 import org.collectionspace.services.client.PoxPayloadIn;
30 import org.collectionspace.services.client.PoxPayloadOut;
31 import org.collectionspace.services.client.RelationClient;
32 import org.collectionspace.services.common.api.CommonAPI;
33 import org.collectionspace.services.common.api.RefName;
34 import org.collectionspace.services.common.api.Tools;
35 import org.collectionspace.services.common.context.MultipartServiceContext;
36 import org.collectionspace.services.common.context.ServiceContext;
37 import org.collectionspace.services.common.document.DocumentWrapper;
38 import org.collectionspace.services.common.document.DocumentWrapperImpl;
39 import org.collectionspace.services.common.relation.IRelationsManager;
40 import org.collectionspace.services.common.repository.RepositoryClient;
41 import org.collectionspace.services.common.repository.RepositoryClientFactory;
42 import org.collectionspace.services.common.service.ObjectPartType;
43 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
44 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
45 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
46 import org.collectionspace.services.relation.RelationResource;
47 import org.collectionspace.services.relation.RelationsCommon;
48 import org.collectionspace.services.relation.RelationsCommonList;
49 import org.collectionspace.services.relation.RelationsDocListItem;
50 import org.collectionspace.services.relation.RelationshipType;
51 import org.nuxeo.ecm.core.api.DocumentModel;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 import javax.ws.rs.core.MultivaluedMap;
56 import javax.ws.rs.core.UriInfo;
57 import java.util.ArrayList;
58 import java.util.List;
60 import java.util.regex.Matcher;
61 import java.util.regex.Pattern;
63 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
66 * AuthorityItemDocumentModelHandler
68 * $LastChangedRevision: $
71 public abstract class AuthorityItemDocumentModelHandler<AICommon, AICommonList>
72 extends RemoteDocumentModelHandlerImpl<AICommon, AICommonList> {
74 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
76 private String authorityItemCommonSchemaName;
78 //private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
80 * item is used to stash JAXB object to use when handle is called
81 * for Action.CREATE, Action.UPDATE or Action.GET
83 protected AICommon item;
85 * itemList is stashed when handle is called
88 protected AICommonList itemList;
91 * inVocabulary is the parent Authority for this context
93 protected String inAuthority;
94 protected String authorityRefNameBase;
96 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
97 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
100 public String getInAuthority() {
104 public void setInAuthority(String inAuthority) {
105 this.inAuthority = inAuthority;
108 /** Subclasses may override this to customize the URI segment. */
109 public String getAuthorityServicePath(){
110 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
114 public String getUri(DocumentModel docModel) {
115 // Laramie20110510 CSPACE-3932
116 String authorityServicePath = getAuthorityServicePath();
117 return "/"+authorityServicePath+'/'+inAuthority+'/'+ AuthorityClient.ITEMS+'/'+getCsid(docModel);
120 public String getAuthorityRefNameBase(){
121 return this.authorityRefNameBase;
124 public void setAuthorityRefNameBase(String value){
125 this.authorityRefNameBase = value;
129 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
132 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
133 // first fill all the parts of the document
134 super.handleCreate(wrapDoc);
135 handleInAuthority(wrapDoc.getWrappedObject());
136 // Uncomment once debugged and App layer is read to integrate
137 //handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
138 //updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase()); //CSPACE-3178
141 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
142 String shortIdentifier = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
143 String displayName = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME);
144 if (Tools.isEmpty(shortIdentifier) && Tools.notEmpty(displayName)){
145 String cookedShortIdentifier = Tools.squeeze(displayName)+'-'+Tools.now().toString();
146 docModel.setProperty(schemaName , AuthorityItemJAXBSchema.SHORT_IDENTIFIER, cookedShortIdentifier);
150 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
152 String authorityRefBaseName) throws Exception {
153 DocumentModel docModel = wrapDoc.getWrappedObject();
154 String shortIdentifier = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
155 String displayName = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME);
156 if (Tools.isEmpty(authorityRefBaseName)){
157 throw new Exception("updateRefnameForAuthorityItem requires an authorityRefBaseName, but none was supplied.");
159 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
160 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
161 docModel.setProperty(schemaName , AuthorityItemJAXBSchema.REF_NAME, refName);
165 * Check the logic around the parent pointer. Note that we only need do this on
166 * create, since we have logic to make this read-only on update.
170 * @throws Exception the exception
172 private void handleInAuthority(DocumentModel docModel) throws Exception {
173 docModel.setProperty(authorityItemCommonSchemaName,
174 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
179 * getCommonPart get associated item
183 public AICommon getCommonPart() {
188 public void setCommonPart(AICommon item) {
193 * getCommonPartList get associated item (for index/GET_ALL)
197 public AICommonList getCommonPartList() {
202 public void setCommonPartList(AICommonList itemList) {
203 this.itemList = itemList;
207 public AICommon extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc)
209 throw new UnsupportedOperationException();
213 public void fillCommonPart(AICommon itemObject, DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
214 throw new UnsupportedOperationException();
218 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
221 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
223 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
225 // Add the CSID to the common part
226 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
227 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
228 unQObjectProperties.put("csid", csid);
231 return unQObjectProperties;
235 * Filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure that
236 * the parent link remains untouched.
237 * @param objectProps the properties parsed from the update payload
238 * @param partMeta metadata for the object to fill
241 public void filterReadOnlyPropertiesForPart(
242 Map<String, Object> objectProps, ObjectPartType partMeta) {
243 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
244 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
245 objectProps.remove(AuthorityItemJAXBSchema.CSID);
249 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
250 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
251 super.extractAllParts(wrapDoc);
253 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
254 if (Tools.isTrue(showSiblings)) {
255 showSiblings(wrapDoc, ctx);
256 return; // actual result is returned on ctx.addOutputPart();
259 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
260 if (Tools.isTrue(showRelations)) {
261 showRelations(wrapDoc, ctx);
262 return; // actual result is returned on ctx.addOutputPart();
265 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
266 if (Tools.isTrue(showAllRelations)) {
267 showAllRelations(wrapDoc, ctx);
268 return; // actual result is returned on ctx.addOutputPart();
272 /** @return null on parent not found
274 protected String getParentCSID(String thisCSID) throws Exception {
275 String parentCSID = null;
277 String predicate = RelationshipType.HAS_BROADER.value();
278 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
279 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
280 if (parentList != null) {
281 if (parentList.size()==0){
284 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
285 parentCSID = relationListItem.getObjectCsid();
288 } catch (Exception e) {
289 logger.error("Could not find parent for this: "+thisCSID, e);
294 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
295 MultipartServiceContext ctx) throws Exception {
296 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
298 String predicate = RelationshipType.HAS_BROADER.value();
299 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
300 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
302 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
303 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
305 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
306 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
307 //Not optimal, but that's the current design spec.
309 for (RelationsCommonList.RelationListItem parent : parentList) {
310 childrenList.add(parent);
313 long childrenSize = childrenList.size();
314 childrenListOuter.setTotalItems(childrenSize);
315 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage()+added);
317 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
318 ctx.addOutputPart(relationsPart);
321 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
322 MultipartServiceContext ctx) throws Exception {
323 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
324 String parentCSID = getParentCSID(thisCSID);
325 if (parentCSID == null){
326 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: "+thisCSID);
330 String predicate = RelationshipType.HAS_BROADER.value();
331 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
332 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
334 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
337 RelationsCommonList.RelationListItem item = null;
338 for (RelationsCommonList.RelationListItem sibling : siblingList) {
339 if (thisCSID.equals(sibling.getSubjectCsid())){
340 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.
343 //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.
344 for (RelationsCommonList.RelationListItem self : toRemoveList) {
345 removeFromList(siblingList, self);
348 long siblingSize = siblingList.size();
349 siblingListOuter.setTotalItems(siblingSize);
350 siblingListOuter.setItemsInPage(siblingSize);
352 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME,siblingListOuter);
353 ctx.addOutputPart(relationsPart);
356 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
357 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
359 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
360 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
362 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
363 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
366 subjectList.addAll(objectList);
368 //now subjectList actually has records BOTH where thisCSID is subject and object.
369 long relatedSize = subjectList.size();
370 subjectListOuter.setTotalItems(relatedSize);
371 subjectListOuter.setItemsInPage(relatedSize);
373 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME,subjectListOuter);
374 ctx.addOutputPart(relationsPart);
377 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
378 super.fillAllParts(wrapDoc, action);
379 ServiceContext ctx = getServiceContext();
380 PoxPayloadIn input = (PoxPayloadIn)ctx.getInput();
381 DocumentModel documentModel = (wrapDoc.getWrappedObject());
382 String itemCsid = documentModel.getName();
384 //UPDATE and CREATE will call. Updates relations part
385 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
387 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
388 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
391 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
392 super.completeUpdate(wrapDoc);
393 //now we add part for relations list
394 ServiceContext ctx = getServiceContext();
395 PayloadOutputPart foo = (PayloadOutputPart)ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
396 ((PoxPayloadOut)ctx.getOutput()).addPart(foo);
399 /** updateRelations strategy:
401 go through inboundList, remove anything from childList that matches from childList
402 go through inboundList, remove anything from parentList that matches from parentList
403 go through parentList, delete all remaining
404 go through childList, delete all remaining
405 go through actionList, add all remaining.
406 check for duplicate children
407 check for more than one parent.
409 inboundList parentList childList actionList
410 ---------------- --------------- ---------------- ----------------
411 child-a parent-c child-a child-b
412 child-b parent-d child-c
415 public RelationsCommonList updateRelations(String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc)
417 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
419 return null; //nothing to do--they didn't send a list of relations.
421 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
423 ServiceContext ctx = getServiceContext();
424 UriInfo uriInfo = ctx.getUriInfo();
425 MultivaluedMap queryParams = uriInfo.getQueryParameters();
427 //Run getList() once as sent to get childListOuter:
428 String predicate = RelationshipType.HAS_BROADER.value();
429 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
430 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
431 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
432 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
433 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
434 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
436 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
437 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
438 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
439 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
440 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
442 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
444 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
445 List<RelationsCommonList.RelationListItem> actionList = newList();
446 List<RelationsCommonList.RelationListItem> childList = childListOuter.getRelationListItem();
447 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
449 if (parentList.size()>1){
450 throw new Exception("Too many parents for object: "+itemCSID+" list: "+dumpList(parentList, "parentList"));
453 DocumentModel docModel = wrapDoc.getWrappedObject();
455 //Do magic replacement of ${itemCSID} and fix URI's.
456 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
458 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
459 if (inboundItem.getObject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
460 //then this is an item that says we have a child. That child is inboundItem
461 RelationsCommonList.RelationListItem childItem = findInList(childList, inboundItem);
462 if (childItem != null){
463 removeFromList(childList, childItem); //exists, just take it off delete list
465 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
467 ensureChildHasNoOtherParents(ctx, queryParams, inboundItem.getSubject().getCsid());
469 } else if (inboundItem.getSubject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
470 //then this is an item that says we have a parent. inboundItem is that parent.
471 RelationsCommonList.RelationListItem parentItem = findInList(parentList, inboundItem);
472 if (parentItem != null){
473 removeFromList(parentList, parentItem); //exists, just take it off delete list
475 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
478 logger.warn("Element didn't match parent or child, but may have partial fields that match. inboundItem: "+inboundItem);
479 //not dealing with: hasNarrower or any other predicate.
482 String dump = dumpLists(itemCSID, parentList, childList, actionList);
483 //System.out.println("====dump====="+CR+dump);
484 logger.info("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~"+CR+ dump);
485 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
486 deleteRelations(childList, ctx, "childList");
487 createRelations(actionList, ctx);
488 //We return all elements on the inbound list, since we have just worked to make them exist in the system
489 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
490 return relationsCommonListBody;
493 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID){
494 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
495 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
496 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
497 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
498 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
499 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
500 deleteRelations(parentList, ctx, "parentList-delete");
503 private String dumpLists(String itemCSID,
504 List <RelationsCommonList.RelationListItem> parentList,
505 List<RelationsCommonList.RelationListItem> childList,
506 List<RelationsCommonList.RelationListItem> actionList){
507 StringBuffer sb = new StringBuffer();
508 sb.append("itemCSID: "+itemCSID+CR);
509 sb.append(dumpList(parentList, "parentList"));
510 sb.append(dumpList(childList, "childList"));
511 sb.append(dumpList(actionList, "actionList"));
512 return sb.toString();
515 private final static String CR="\r\n";
516 private final static String T = " ";
518 private String dumpList(List <RelationsCommonList.RelationListItem> list, String label){
519 StringBuffer sb = new StringBuffer();
521 if (list.size()>0) sb.append("=========== "+label+" =========="+CR);
522 for (RelationsCommonList.RelationListItem item : list) {
524 T + item.getSubject().getCsid() //+T4 + item.getSubject().getUri()
525 + T + item.getPredicate()
526 + T + item.getObject().getCsid() //+T4 + item.getObject().getUri()
528 //+"subject:{"+item.getSubject()+"}\r\n object:{"+item.getObject()+"}"
529 //+ CR + "relation-record: {"+item+"}"
534 return sb.toString();
537 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
538 * and sets URI correctly for related items.
539 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
541 protected void fixupInboundListItems(ServiceContext ctx,
542 List<RelationsCommonList.RelationListItem> inboundList,
543 DocumentModel docModel,
544 String itemCSID) throws Exception {
545 String thisURI = this.getUri(docModel);
546 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
547 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
548 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
549 RelationsDocListItem inboundItemObject = inboundItem.getObject();
550 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
552 if (inboundItemObject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)){
553 inboundItem.setObjectCsid(itemCSID);
554 inboundItemObject.setCsid(itemCSID);
555 inboundItemObject.setUri(getUri(docModel));
557 String objectCsid = inboundItemObject.getCsid();
558 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
559 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
560 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
561 inboundItemObject.setUri(uri); //CSPACE-4037
563 uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
565 if (inboundItemSubject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)){
566 inboundItem.setSubjectCsid(itemCSID);
567 inboundItemSubject.setCsid(itemCSID);
568 inboundItemSubject.setUri(getUri(docModel));
570 String subjectCsid =inboundItemSubject.getCsid();
571 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
572 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
573 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
574 inboundItemSubject.setUri(uri); //CSPACE-4037
576 uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
581 public RepositoryClient getRepositoryClient(ServiceContext ctx) {
582 RepositoryClient repositoryClient = RepositoryClientFactory.getInstance().getClient(ctx.getRepositoryClientName());
583 return repositoryClient;
586 // this method calls the RelationResource to have it create the relations and persist them.
587 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx){
588 for (RelationsCommonList.RelationListItem item : inboundList) {
589 RelationsCommon rc = new RelationsCommon();
590 //rc.setCsid(item.getCsid());
591 //todo: assignTo(item, rc);
592 RelationsDocListItem itemSubject = item.getSubject();
593 RelationsDocListItem itemObject = item.getObject();
595 String subjectCsid = itemSubject.getCsid();
596 rc.setDocumentId1(subjectCsid);
597 rc.setSubjectCsid(subjectCsid);
599 String objCsid = item.getObject().getCsid();
600 rc.setDocumentId2(objCsid);
601 rc.setObjectCsid(objCsid);
603 rc.setRelationshipType(item.getPredicate());
604 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
605 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
607 rc.setDocumentType1(itemSubject.getDocumentType());
608 rc.setDocumentType2(itemObject.getDocumentType());
610 rc.setSubjectUri(itemSubject.getUri());
611 rc.setObjectUri(itemObject.getUri());
614 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
615 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
616 payloadOut.addPart(outputPart);
617 //System.out.println("\r\n==== TO CREATE: "+rc.getDocumentId1()+"==>"+rc.getPredicate()+"==>"+rc.getDocumentId2());
618 RelationResource relationResource = new RelationResource();
619 Object res = relationResource.create(ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
622 private void deleteRelations(List<RelationsCommonList.RelationListItem> list,ServiceContext ctx, String listName){
624 //if (list.size()>0){ logger.info("==== deleteRelations from : "+listName); }
625 for (RelationsCommonList.RelationListItem item : list) {
626 RelationResource relationResource = new RelationResource();
627 //logger.info("==== TO DELETE: " + item.getCsid() + ": " + item.getSubject().getCsid() + "--" + item.getPredicate() + "-->" + item.getObject().getCsid());
628 Object res = relationResource.delete(item.getCsid());
630 } catch (Throwable t){
631 String msg = "Unable to deleteRelations: "+ Tools.errorToString(t, true);
636 private List<RelationsCommonList.RelationListItem> newList(){
637 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
640 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList){
641 List<RelationsCommonList.RelationListItem> result = newList();
642 for (RelationsCommonList.RelationListItem item: inboundList){
647 private RelationsCommonList.RelationListItem findInList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
648 for (RelationsCommonList.RelationListItem listItem : list) {
649 if (itemsEqual(listItem, item)){ //equals must be defined, else
656 private boolean itemsEqual(RelationsCommonList.RelationListItem item, RelationsCommonList.RelationListItem item2){
657 if (item==null || item2==null){
660 RelationsDocListItem subj1 = item.getSubject();
661 RelationsDocListItem subj2 = item2.getSubject();
662 RelationsDocListItem obj1 = item.getObject();
663 RelationsDocListItem obj2 = item2.getObject();
665 return (subj1.getCsid().equals(subj2.getCsid()))
666 && (obj1.getCsid().equals(obj1.getCsid()))
667 && ( (item.getPredicate().equals(item2.getPredicate()))
668 && (item.getRelationshipType().equals(item2.getRelationshipType())) )
669 && (obj1.getDocumentType().equals(obj2.getDocumentType()))
670 && (subj1.getDocumentType().equals(subj2.getDocumentType())) ;
673 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
677 /* don't even THINK of re-using this method.
678 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
680 private String extractInAuthorityCSID(String uri){
681 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
682 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
683 Matcher m = p.matcher(uri);
685 if (m.groupCount()<3){
686 logger.warn("REGEX-WRONG-GROUPCOUNT looking in "+uri);
689 //String service = m.group(1);
690 String inauth = m.group(2);
691 //String theRest = m.group(3);
693 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
696 logger.warn("REGEX-NOT-MATCHED looking in "+uri);
701 //ensures CSPACE-4042
702 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
703 String authorityCSID = extractInAuthorityCSID(thisURI);
704 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
705 if ( Tools.isBlank(authorityCSID)
706 || Tools.isBlank(authorityCSIDForInbound)
707 || ( ! authorityCSID.equalsIgnoreCase(authorityCSIDForInbound) )
709 throw new Exception("Item URI "+thisURI+" must point to same authority as related item: "+inboundItemURI);
713 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
714 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
715 ServiceContext ctx = getServiceContext();
716 MultivaluedMap queryParams = ctx.getQueryParams();
717 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
718 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
719 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
721 RelationResource relationResource = new RelationResource();
722 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
723 return relationsCommonList;
725 //============================= END TODO refactor ==========================