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.DocHandlerBase;
45 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
46 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
47 import org.collectionspace.services.relation.RelationResource;
48 import org.collectionspace.services.relation.RelationsCommon;
49 import org.collectionspace.services.relation.RelationsCommonList;
50 import org.collectionspace.services.relation.RelationsDocListItem;
51 import org.collectionspace.services.relation.RelationshipType;
52 import org.nuxeo.ecm.core.api.DocumentModel;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 import javax.ws.rs.core.MultivaluedMap;
57 import javax.ws.rs.core.UriInfo;
58 import java.util.ArrayList;
59 import java.util.List;
61 import java.util.regex.Matcher;
62 import java.util.regex.Pattern;
64 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
67 * AuthorityItemDocumentModelHandler
69 * $LastChangedRevision: $
72 public abstract class AuthorityItemDocumentModelHandler<AICommon>
73 extends DocHandlerBase<AICommon> {
75 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
77 private String authorityItemCommonSchemaName;
80 * inVocabulary is the parent Authority for this context
82 protected String inAuthority;
83 protected String authorityRefNameBase;
85 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
86 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
89 public String getInAuthority() {
93 public void setInAuthority(String inAuthority) {
94 this.inAuthority = inAuthority;
97 /** Subclasses may override this to customize the URI segment. */
98 public String getAuthorityServicePath(){
99 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
103 public String getUri(DocumentModel docModel) {
104 // Laramie20110510 CSPACE-3932
105 String authorityServicePath = getAuthorityServicePath();
106 return "/"+authorityServicePath+'/'+inAuthority+'/'+ AuthorityClient.ITEMS+'/'+getCsid(docModel);
109 public String getAuthorityRefNameBase(){
110 return this.authorityRefNameBase;
113 public void setAuthorityRefNameBase(String value){
114 this.authorityRefNameBase = value;
118 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
121 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
122 // first fill all the parts of the document
123 super.handleCreate(wrapDoc);
124 handleInAuthority(wrapDoc.getWrappedObject());
125 // Uncomment once debugged and App layer is read to integrate
126 //handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
127 //updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase()); //CSPACE-3178
130 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
131 String shortIdentifier = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
132 String displayName = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME);
133 if (Tools.isEmpty(shortIdentifier) && Tools.notEmpty(displayName)){
134 String cookedShortIdentifier = Tools.squeeze(displayName)+'-'+Tools.now().toString();
135 docModel.setProperty(schemaName , AuthorityItemJAXBSchema.SHORT_IDENTIFIER, cookedShortIdentifier);
139 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
141 String authorityRefBaseName) throws Exception {
142 DocumentModel docModel = wrapDoc.getWrappedObject();
143 String shortIdentifier = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
144 String displayName = (String)docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME);
145 if (Tools.isEmpty(authorityRefBaseName)){
146 throw new Exception("updateRefnameForAuthorityItem requires an authorityRefBaseName, but none was supplied.");
148 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
149 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
150 docModel.setProperty(schemaName , AuthorityItemJAXBSchema.REF_NAME, refName);
154 * Check the logic around the parent pointer. Note that we only need do this on
155 * create, since we have logic to make this read-only on update.
159 * @throws Exception the exception
161 private void handleInAuthority(DocumentModel docModel) throws Exception {
162 docModel.setProperty(authorityItemCommonSchemaName,
163 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
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)
171 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
173 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
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);
181 return unQObjectProperties;
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
191 public void filterReadOnlyPropertiesForPart(
192 Map<String, Object> objectProps, ObjectPartType partMeta) {
193 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
194 String commonPartLabel = getServiceContext().getCommonPartLabel();
195 if(partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
196 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
197 objectProps.remove(AuthorityItemJAXBSchema.CSID);
202 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
203 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
204 super.extractAllParts(wrapDoc);
206 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
207 if (Tools.isTrue(showSiblings)) {
208 showSiblings(wrapDoc, ctx);
209 return; // actual result is returned on ctx.addOutputPart();
212 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
213 if (Tools.isTrue(showRelations)) {
214 showRelations(wrapDoc, ctx);
215 return; // actual result is returned on ctx.addOutputPart();
218 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
219 if (Tools.isTrue(showAllRelations)) {
220 showAllRelations(wrapDoc, ctx);
221 return; // actual result is returned on ctx.addOutputPart();
225 /** @return null on parent not found
227 protected String getParentCSID(String thisCSID) throws Exception {
228 String parentCSID = null;
230 String predicate = RelationshipType.HAS_BROADER.value();
231 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
232 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
233 if (parentList != null) {
234 if (parentList.size()==0){
237 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
238 parentCSID = relationListItem.getObjectCsid();
241 } catch (Exception e) {
242 logger.error("Could not find parent for this: "+thisCSID, e);
247 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
248 MultipartServiceContext ctx) throws Exception {
249 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
251 String predicate = RelationshipType.HAS_BROADER.value();
252 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
253 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
255 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
256 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
258 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
259 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
260 //Not optimal, but that's the current design spec.
262 for (RelationsCommonList.RelationListItem parent : parentList) {
263 childrenList.add(parent);
266 long childrenSize = childrenList.size();
267 childrenListOuter.setTotalItems(childrenSize);
268 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage()+added);
270 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
271 ctx.addOutputPart(relationsPart);
274 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
275 MultipartServiceContext ctx) throws Exception {
276 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
277 String parentCSID = getParentCSID(thisCSID);
278 if (parentCSID == null){
279 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: "+thisCSID);
283 String predicate = RelationshipType.HAS_BROADER.value();
284 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
285 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
287 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
290 RelationsCommonList.RelationListItem item = null;
291 for (RelationsCommonList.RelationListItem sibling : siblingList) {
292 if (thisCSID.equals(sibling.getSubjectCsid())){
293 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.
296 //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.
297 for (RelationsCommonList.RelationListItem self : toRemoveList) {
298 removeFromList(siblingList, self);
301 long siblingSize = siblingList.size();
302 siblingListOuter.setTotalItems(siblingSize);
303 siblingListOuter.setItemsInPage(siblingSize);
305 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME,siblingListOuter);
306 ctx.addOutputPart(relationsPart);
309 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
310 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
312 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
313 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
315 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
316 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
319 subjectList.addAll(objectList);
321 //now subjectList actually has records BOTH where thisCSID is subject and object.
322 long relatedSize = subjectList.size();
323 subjectListOuter.setTotalItems(relatedSize);
324 subjectListOuter.setItemsInPage(relatedSize);
326 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME,subjectListOuter);
327 ctx.addOutputPart(relationsPart);
330 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
331 super.fillAllParts(wrapDoc, action);
332 ServiceContext ctx = getServiceContext();
333 PoxPayloadIn input = (PoxPayloadIn)ctx.getInput();
334 DocumentModel documentModel = (wrapDoc.getWrappedObject());
335 String itemCsid = documentModel.getName();
337 //UPDATE and CREATE will call. Updates relations part
338 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
340 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
341 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
344 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
345 super.completeUpdate(wrapDoc);
346 //now we add part for relations list
347 ServiceContext ctx = getServiceContext();
348 PayloadOutputPart foo = (PayloadOutputPart)ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
349 ((PoxPayloadOut)ctx.getOutput()).addPart(foo);
352 /** updateRelations strategy:
354 go through inboundList, remove anything from childList that matches from childList
355 go through inboundList, remove anything from parentList that matches from parentList
356 go through parentList, delete all remaining
357 go through childList, delete all remaining
358 go through actionList, add all remaining.
359 check for duplicate children
360 check for more than one parent.
362 inboundList parentList childList actionList
363 ---------------- --------------- ---------------- ----------------
364 child-a parent-c child-a child-b
365 child-b parent-d child-c
368 public RelationsCommonList updateRelations(String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc)
370 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
372 return null; //nothing to do--they didn't send a list of relations.
374 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
376 ServiceContext ctx = getServiceContext();
377 UriInfo uriInfo = ctx.getUriInfo();
378 MultivaluedMap queryParams = uriInfo.getQueryParameters();
380 //Run getList() once as sent to get childListOuter:
381 String predicate = RelationshipType.HAS_BROADER.value();
382 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
383 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
384 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
385 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
386 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
387 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
389 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
390 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
391 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
392 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
393 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
395 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
397 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
398 List<RelationsCommonList.RelationListItem> actionList = newList();
399 List<RelationsCommonList.RelationListItem> childList = childListOuter.getRelationListItem();
400 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
402 if (parentList.size()>1){
403 throw new Exception("Too many parents for object: "+itemCSID+" list: "+dumpList(parentList, "parentList"));
406 DocumentModel docModel = wrapDoc.getWrappedObject();
408 //Do magic replacement of ${itemCSID} and fix URI's.
409 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
411 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
412 if (inboundItem.getObject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
413 //then this is an item that says we have a child. That child is inboundItem
414 RelationsCommonList.RelationListItem childItem = findInList(childList, inboundItem);
415 if (childItem != null){
416 removeFromList(childList, childItem); //exists, just take it off delete list
418 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
420 ensureChildHasNoOtherParents(ctx, queryParams, inboundItem.getSubject().getCsid());
422 } else if (inboundItem.getSubject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
423 //then this is an item that says we have a parent. inboundItem is that parent.
424 RelationsCommonList.RelationListItem parentItem = findInList(parentList, inboundItem);
425 if (parentItem != null){
426 removeFromList(parentList, parentItem); //exists, just take it off delete list
428 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
431 logger.warn("Element didn't match parent or child, but may have partial fields that match. inboundItem: "+inboundItem);
432 //not dealing with: hasNarrower or any other predicate.
435 String dump = dumpLists(itemCSID, parentList, childList, actionList);
436 //System.out.println("====dump====="+CR+dump);
437 logger.info("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~"+CR+ dump);
438 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
439 deleteRelations(childList, ctx, "childList");
440 createRelations(actionList, ctx);
441 //We return all elements on the inbound list, since we have just worked to make them exist in the system
442 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
443 return relationsCommonListBody;
446 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID){
447 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
448 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
449 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
450 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
451 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
452 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
453 deleteRelations(parentList, ctx, "parentList-delete");
456 private String dumpLists(String itemCSID,
457 List <RelationsCommonList.RelationListItem> parentList,
458 List<RelationsCommonList.RelationListItem> childList,
459 List<RelationsCommonList.RelationListItem> actionList){
460 StringBuffer sb = new StringBuffer();
461 sb.append("itemCSID: "+itemCSID+CR);
462 sb.append(dumpList(parentList, "parentList"));
463 sb.append(dumpList(childList, "childList"));
464 sb.append(dumpList(actionList, "actionList"));
465 return sb.toString();
468 private final static String CR="\r\n";
469 private final static String T = " ";
471 private String dumpList(List <RelationsCommonList.RelationListItem> list, String label){
472 StringBuffer sb = new StringBuffer();
474 if (list.size()>0) sb.append("=========== "+label+" =========="+CR);
475 for (RelationsCommonList.RelationListItem item : list) {
477 T + item.getSubject().getCsid() //+T4 + item.getSubject().getUri()
478 + T + item.getPredicate()
479 + T + item.getObject().getCsid() //+T4 + item.getObject().getUri()
481 //+"subject:{"+item.getSubject()+"}\r\n object:{"+item.getObject()+"}"
482 //+ CR + "relation-record: {"+item+"}"
487 return sb.toString();
490 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
491 * and sets URI correctly for related items.
492 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
494 protected void fixupInboundListItems(ServiceContext ctx,
495 List<RelationsCommonList.RelationListItem> inboundList,
496 DocumentModel docModel,
497 String itemCSID) throws Exception {
498 String thisURI = this.getUri(docModel);
499 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
500 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
501 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
502 RelationsDocListItem inboundItemObject = inboundItem.getObject();
503 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
505 if (inboundItemObject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)){
506 inboundItem.setObjectCsid(itemCSID);
507 inboundItemObject.setCsid(itemCSID);
508 inboundItemObject.setUri(getUri(docModel));
510 String objectCsid = inboundItemObject.getCsid();
511 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
512 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
513 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
514 inboundItemObject.setUri(uri); //CSPACE-4037
516 uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
518 if (inboundItemSubject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)){
519 inboundItem.setSubjectCsid(itemCSID);
520 inboundItemSubject.setCsid(itemCSID);
521 inboundItemSubject.setUri(getUri(docModel));
523 String subjectCsid =inboundItemSubject.getCsid();
524 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
525 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
526 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
527 inboundItemSubject.setUri(uri); //CSPACE-4037
529 uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
534 public RepositoryClient getRepositoryClient(ServiceContext ctx) {
535 RepositoryClient repositoryClient = RepositoryClientFactory.getInstance().getClient(ctx.getRepositoryClientName());
536 return repositoryClient;
539 // this method calls the RelationResource to have it create the relations and persist them.
540 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx){
541 for (RelationsCommonList.RelationListItem item : inboundList) {
542 RelationsCommon rc = new RelationsCommon();
543 //rc.setCsid(item.getCsid());
544 //todo: assignTo(item, rc);
545 RelationsDocListItem itemSubject = item.getSubject();
546 RelationsDocListItem itemObject = item.getObject();
548 String subjectCsid = itemSubject.getCsid();
549 rc.setDocumentId1(subjectCsid);
550 rc.setSubjectCsid(subjectCsid);
552 String objCsid = item.getObject().getCsid();
553 rc.setDocumentId2(objCsid);
554 rc.setObjectCsid(objCsid);
556 rc.setRelationshipType(item.getPredicate());
557 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
558 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
560 rc.setDocumentType1(itemSubject.getDocumentType());
561 rc.setDocumentType2(itemObject.getDocumentType());
563 rc.setSubjectUri(itemSubject.getUri());
564 rc.setObjectUri(itemObject.getUri());
567 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
568 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
569 payloadOut.addPart(outputPart);
570 //System.out.println("\r\n==== TO CREATE: "+rc.getDocumentId1()+"==>"+rc.getPredicate()+"==>"+rc.getDocumentId2());
571 RelationResource relationResource = new RelationResource();
572 Object res = relationResource.create(ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
575 private void deleteRelations(List<RelationsCommonList.RelationListItem> list,ServiceContext ctx, String listName){
577 //if (list.size()>0){ logger.info("==== deleteRelations from : "+listName); }
578 for (RelationsCommonList.RelationListItem item : list) {
579 RelationResource relationResource = new RelationResource();
580 //logger.info("==== TO DELETE: " + item.getCsid() + ": " + item.getSubject().getCsid() + "--" + item.getPredicate() + "-->" + item.getObject().getCsid());
581 Object res = relationResource.delete(item.getCsid());
583 } catch (Throwable t){
584 String msg = "Unable to deleteRelations: "+ Tools.errorToString(t, true);
589 private List<RelationsCommonList.RelationListItem> newList(){
590 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
593 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList){
594 List<RelationsCommonList.RelationListItem> result = newList();
595 for (RelationsCommonList.RelationListItem item: inboundList){
600 private RelationsCommonList.RelationListItem findInList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
601 for (RelationsCommonList.RelationListItem listItem : list) {
602 if (itemsEqual(listItem, item)){ //equals must be defined, else
609 private boolean itemsEqual(RelationsCommonList.RelationListItem item, RelationsCommonList.RelationListItem item2){
610 if (item==null || item2==null){
613 RelationsDocListItem subj1 = item.getSubject();
614 RelationsDocListItem subj2 = item2.getSubject();
615 RelationsDocListItem obj1 = item.getObject();
616 RelationsDocListItem obj2 = item2.getObject();
618 return (subj1.getCsid().equals(subj2.getCsid()))
619 && (obj1.getCsid().equals(obj1.getCsid()))
620 && ( (item.getPredicate().equals(item2.getPredicate()))
621 && (item.getRelationshipType().equals(item2.getRelationshipType())) )
622 && (obj1.getDocumentType().equals(obj2.getDocumentType()))
623 && (subj1.getDocumentType().equals(subj2.getDocumentType())) ;
626 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
630 /* don't even THINK of re-using this method.
631 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
633 private String extractInAuthorityCSID(String uri){
634 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
635 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
636 Matcher m = p.matcher(uri);
638 if (m.groupCount()<3){
639 logger.warn("REGEX-WRONG-GROUPCOUNT looking in "+uri);
642 //String service = m.group(1);
643 String inauth = m.group(2);
644 //String theRest = m.group(3);
646 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
649 logger.warn("REGEX-NOT-MATCHED looking in "+uri);
654 //ensures CSPACE-4042
655 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
656 String authorityCSID = extractInAuthorityCSID(thisURI);
657 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
658 if ( Tools.isBlank(authorityCSID)
659 || Tools.isBlank(authorityCSIDForInbound)
660 || ( ! authorityCSID.equalsIgnoreCase(authorityCSIDForInbound) )
662 throw new Exception("Item URI "+thisURI+" must point to same authority as related item: "+inboundItemURI);
666 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
667 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
668 ServiceContext ctx = getServiceContext();
669 MultivaluedMap queryParams = ctx.getQueryParams();
670 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
671 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
672 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
674 RelationResource relationResource = new RelationResource();
675 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
676 return relationsCommonList;
678 //============================= END TODO refactor ==========================