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.AuthorityJAXBSchema;
44 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
45 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
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.nuxeo.ecm.core.api.model.PropertyNotFoundException;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import javax.ws.rs.core.MultivaluedMap;
58 import javax.ws.rs.core.UriInfo;
59 import java.util.ArrayList;
60 import java.util.List;
62 import java.util.regex.Matcher;
63 import java.util.regex.Pattern;
65 //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);
76 private String authorityItemCommonSchemaName;
78 * inVocabulary is the parent Authority for this context
80 protected String inAuthority;
81 protected String authorityRefNameBase;
83 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
84 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
87 public String getInAuthority() {
91 public void setInAuthority(String inAuthority) {
92 this.inAuthority = inAuthority;
95 /** Subclasses may override this to customize the URI segment. */
96 public String getAuthorityServicePath() {
97 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
101 public String getUri(DocumentModel docModel) {
102 // Laramie20110510 CSPACE-3932
103 String authorityServicePath = getAuthorityServicePath();
104 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
107 public String getAuthorityRefNameBase() {
108 return this.authorityRefNameBase;
111 public void setAuthorityRefNameBase(String value) {
112 this.authorityRefNameBase = value;
116 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
119 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
120 // first fill all the parts of the document
121 super.handleCreate(wrapDoc);
122 handleInAuthority(wrapDoc.getWrappedObject());
124 // Uncomment once debugged and App layer is read to integrate
125 // Experimenting with these uncommented now ...
126 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
127 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
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 String shortDisplayName = "";
135 shortDisplayName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_DISPLAY_NAME);
136 } catch (PropertyNotFoundException pnfe) {
137 // Do nothing on exception. Some vocabulary schemas may not include a short display name.
139 if (Tools.isEmpty(shortIdentifier)) {
140 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
141 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER, generatedShortIdentifier);
145 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
147 String authorityRefBaseName) throws Exception {
148 DocumentModel docModel = wrapDoc.getWrappedObject();
149 String suppliedRefName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME);
151 // Temporarily accept client-supplied refName values, rather than always generating such values.
152 // Remove the surrounding 'if' statement when clients should no longer supply refName values.
153 if (suppliedRefName == null || suppliedRefName.isEmpty()) {
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("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
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);
166 * Check the logic around the parent pointer. Note that we only need do this on
167 * create, since we have logic to make this read-only on update.
171 * @throws Exception the exception
173 private void handleInAuthority(DocumentModel docModel) throws Exception {
174 docModel.setProperty(authorityItemCommonSchemaName,
175 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
180 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
183 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
185 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
187 // Add the CSID to the common part
188 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
189 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
190 unQObjectProperties.put("csid", csid);
193 return unQObjectProperties;
197 * Filters out selected values supplied in an update request.
199 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
200 * that the link to the item's parent remains untouched.
202 * @param objectProps the properties filtered out from the update payload
203 * @param partMeta metadata for the object to fill
206 public void filterReadOnlyPropertiesForPart(
207 Map<String, Object> objectProps, ObjectPartType partMeta) {
208 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
209 String commonPartLabel = getServiceContext().getCommonPartLabel();
210 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
211 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
212 objectProps.remove(AuthorityItemJAXBSchema.CSID);
213 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
214 // Enable when clients should no longer supply refName values
215 // objectProps.remove(AuthorityItemJAXBSchema.REF_NAME); // CSPACE-3178
221 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
222 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
223 super.extractAllParts(wrapDoc);
225 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
226 if (Tools.isTrue(showSiblings)) {
227 showSiblings(wrapDoc, ctx);
228 return; // actual result is returned on ctx.addOutputPart();
231 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
232 if (Tools.isTrue(showRelations)) {
233 showRelations(wrapDoc, ctx);
234 return; // actual result is returned on ctx.addOutputPart();
237 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
238 if (Tools.isTrue(showAllRelations)) {
239 showAllRelations(wrapDoc, ctx);
240 return; // actual result is returned on ctx.addOutputPart();
244 /** @return null on parent not found
246 protected String getParentCSID(String thisCSID) throws Exception {
247 String parentCSID = null;
249 String predicate = RelationshipType.HAS_BROADER.value();
250 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
251 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
252 if (parentList != null) {
253 if (parentList.size() == 0) {
256 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
257 parentCSID = relationListItem.getObjectCsid();
260 } catch (Exception e) {
261 logger.error("Could not find parent for this: " + thisCSID, e);
266 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
267 MultipartServiceContext ctx) throws Exception {
268 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
270 String predicate = RelationshipType.HAS_BROADER.value();
271 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
272 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
274 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
275 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
277 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
278 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
279 //Not optimal, but that's the current design spec.
281 for (RelationsCommonList.RelationListItem parent : parentList) {
282 childrenList.add(parent);
285 long childrenSize = childrenList.size();
286 childrenListOuter.setTotalItems(childrenSize);
287 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
289 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
290 ctx.addOutputPart(relationsPart);
293 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
294 MultipartServiceContext ctx) throws Exception {
295 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
296 String parentCSID = getParentCSID(thisCSID);
297 if (parentCSID == null) {
298 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
302 String predicate = RelationshipType.HAS_BROADER.value();
303 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
304 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
306 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
309 RelationsCommonList.RelationListItem item = null;
310 for (RelationsCommonList.RelationListItem sibling : siblingList) {
311 if (thisCSID.equals(sibling.getSubjectCsid())) {
312 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.
315 //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.
316 for (RelationsCommonList.RelationListItem self : toRemoveList) {
317 removeFromList(siblingList, self);
320 long siblingSize = siblingList.size();
321 siblingListOuter.setTotalItems(siblingSize);
322 siblingListOuter.setItemsInPage(siblingSize);
324 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
325 ctx.addOutputPart(relationsPart);
328 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
329 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
331 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
332 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
334 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
335 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
338 subjectList.addAll(objectList);
340 //now subjectList actually has records BOTH where thisCSID is subject and object.
341 long relatedSize = subjectList.size();
342 subjectListOuter.setTotalItems(relatedSize);
343 subjectListOuter.setItemsInPage(relatedSize);
345 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
346 ctx.addOutputPart(relationsPart);
349 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
350 super.fillAllParts(wrapDoc, action);
351 ServiceContext ctx = getServiceContext();
352 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
353 DocumentModel documentModel = (wrapDoc.getWrappedObject());
354 String itemCsid = documentModel.getName();
356 //UPDATE and CREATE will call. Updates relations part
357 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
359 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
360 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
363 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
364 super.completeUpdate(wrapDoc);
365 //now we add part for relations list
366 ServiceContext ctx = getServiceContext();
367 PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
368 ((PoxPayloadOut) ctx.getOutput()).addPart(foo);
371 /** updateRelations strategy:
373 go through inboundList, remove anything from childList that matches from childList
374 go through inboundList, remove anything from parentList that matches from parentList
375 go through parentList, delete all remaining
376 go through childList, delete all remaining
377 go through actionList, add all remaining.
378 check for duplicate children
379 check for more than one parent.
381 inboundList parentList childList actionList
382 ---------------- --------------- ---------------- ----------------
383 child-a parent-c child-a child-b
384 child-b parent-d child-c
387 public RelationsCommonList updateRelations(String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc)
389 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
391 return null; //nothing to do--they didn't send a list of relations.
393 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
395 ServiceContext ctx = getServiceContext();
396 UriInfo uriInfo = ctx.getUriInfo();
397 MultivaluedMap queryParams = uriInfo.getQueryParameters();
399 //Run getList() once as sent to get childListOuter:
400 String predicate = RelationshipType.HAS_BROADER.value();
401 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
402 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
403 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
404 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
405 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
406 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
408 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
409 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
410 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
411 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
412 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
414 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
416 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
417 List<RelationsCommonList.RelationListItem> actionList = newList();
418 List<RelationsCommonList.RelationListItem> childList = childListOuter.getRelationListItem();
419 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
421 if (parentList.size() > 1) {
422 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
425 DocumentModel docModel = wrapDoc.getWrappedObject();
427 //Do magic replacement of ${itemCSID} and fix URI's.
428 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
430 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
431 if (inboundItem.getObject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
432 //then this is an item that says we have a child. That child is inboundItem
433 RelationsCommonList.RelationListItem childItem = findInList(childList, inboundItem);
434 if (childItem != null) {
435 removeFromList(childList, childItem); //exists, just take it off delete list
437 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
439 ensureChildHasNoOtherParents(ctx, queryParams, inboundItem.getSubject().getCsid());
441 } else if (inboundItem.getSubject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
442 //then this is an item that says we have a parent. inboundItem is that parent.
443 RelationsCommonList.RelationListItem parentItem = findInList(parentList, inboundItem);
444 if (parentItem != null) {
445 removeFromList(parentList, parentItem); //exists, just take it off delete list
447 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
450 logger.warn("Element didn't match parent or child, but may have partial fields that match. inboundItem: " + inboundItem);
451 //not dealing with: hasNarrower or any other predicate.
454 String dump = dumpLists(itemCSID, parentList, childList, actionList);
455 //System.out.println("====dump====="+CR+dump);
456 logger.info("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
457 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
458 deleteRelations(childList, ctx, "childList");
459 createRelations(actionList, ctx);
460 //We return all elements on the inbound list, since we have just worked to make them exist in the system
461 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
462 return relationsCommonListBody;
465 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
466 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
467 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
468 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
469 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
470 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
471 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
472 deleteRelations(parentList, ctx, "parentList-delete");
475 private String dumpLists(String itemCSID,
476 List<RelationsCommonList.RelationListItem> parentList,
477 List<RelationsCommonList.RelationListItem> childList,
478 List<RelationsCommonList.RelationListItem> actionList) {
479 StringBuffer sb = new StringBuffer();
480 sb.append("itemCSID: " + itemCSID + CR);
481 sb.append(dumpList(parentList, "parentList"));
482 sb.append(dumpList(childList, "childList"));
483 sb.append(dumpList(actionList, "actionList"));
484 return sb.toString();
486 private final static String CR = "\r\n";
487 private final static String T = " ";
489 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
490 StringBuffer sb = new StringBuffer();
492 if (list.size() > 0) {
493 sb.append("=========== " + label + " ==========" + CR);
495 for (RelationsCommonList.RelationListItem item : list) {
497 T + item.getSubject().getCsid() //+T4 + item.getSubject().getUri()
498 + T + item.getPredicate()
499 + T + item.getObject().getCsid() //+T4 + item.getObject().getUri()
500 + CR //+"subject:{"+item.getSubject()+"}\r\n object:{"+item.getObject()+"}"
501 //+ CR + "relation-record: {"+item+"}"
506 return sb.toString();
509 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
510 * and sets URI correctly for related items.
511 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
513 protected void fixupInboundListItems(ServiceContext ctx,
514 List<RelationsCommonList.RelationListItem> inboundList,
515 DocumentModel docModel,
516 String itemCSID) throws Exception {
517 String thisURI = this.getUri(docModel);
518 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
519 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
520 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
521 RelationsDocListItem inboundItemObject = inboundItem.getObject();
522 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
524 if (inboundItemObject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)) {
525 inboundItem.setObjectCsid(itemCSID);
526 inboundItemObject.setCsid(itemCSID);
527 inboundItemObject.setUri(getUri(docModel));
529 String objectCsid = inboundItemObject.getCsid();
530 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
531 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
532 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
533 inboundItemObject.setUri(uri); //CSPACE-4037
535 uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
537 if (inboundItemSubject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)) {
538 inboundItem.setSubjectCsid(itemCSID);
539 inboundItemSubject.setCsid(itemCSID);
540 inboundItemSubject.setUri(getUri(docModel));
542 String subjectCsid = inboundItemSubject.getCsid();
543 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
544 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
545 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
546 inboundItemSubject.setUri(uri); //CSPACE-4037
548 uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
553 public RepositoryClient getRepositoryClient(ServiceContext ctx) {
554 RepositoryClient repositoryClient = RepositoryClientFactory.getInstance().getClient(ctx.getRepositoryClientName());
555 return repositoryClient;
558 // this method calls the RelationResource to have it create the relations and persist them.
559 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) {
560 for (RelationsCommonList.RelationListItem item : inboundList) {
561 RelationsCommon rc = new RelationsCommon();
562 //rc.setCsid(item.getCsid());
563 //todo: assignTo(item, rc);
564 RelationsDocListItem itemSubject = item.getSubject();
565 RelationsDocListItem itemObject = item.getObject();
567 String subjectCsid = itemSubject.getCsid();
568 rc.setDocumentId1(subjectCsid);
569 rc.setSubjectCsid(subjectCsid);
571 String objCsid = item.getObject().getCsid();
572 rc.setDocumentId2(objCsid);
573 rc.setObjectCsid(objCsid);
575 rc.setRelationshipType(item.getPredicate());
576 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
577 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
579 rc.setDocumentType1(itemSubject.getDocumentType());
580 rc.setDocumentType2(itemObject.getDocumentType());
582 rc.setSubjectUri(itemSubject.getUri());
583 rc.setObjectUri(itemObject.getUri());
586 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
587 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
588 payloadOut.addPart(outputPart);
589 //System.out.println("\r\n==== TO CREATE: "+rc.getDocumentId1()+"==>"+rc.getPredicate()+"==>"+rc.getDocumentId2());
590 RelationResource relationResource = new RelationResource();
591 Object res = relationResource.create(ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
595 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
597 //if (list.size()>0){ logger.info("==== deleteRelations from : "+listName); }
598 for (RelationsCommonList.RelationListItem item : list) {
599 RelationResource relationResource = new RelationResource();
600 //logger.info("==== TO DELETE: " + item.getCsid() + ": " + item.getSubject().getCsid() + "--" + item.getPredicate() + "-->" + item.getObject().getCsid());
601 Object res = relationResource.delete(item.getCsid());
603 } catch (Throwable t) {
604 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
609 private List<RelationsCommonList.RelationListItem> newList() {
610 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
614 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
615 List<RelationsCommonList.RelationListItem> result = newList();
616 for (RelationsCommonList.RelationListItem item : inboundList) {
622 private RelationsCommonList.RelationListItem findInList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
623 for (RelationsCommonList.RelationListItem listItem : list) {
624 if (itemsEqual(listItem, item)) { //equals must be defined, else
631 private boolean itemsEqual(RelationsCommonList.RelationListItem item, RelationsCommonList.RelationListItem item2) {
632 if (item == null || item2 == null) {
635 RelationsDocListItem subj1 = item.getSubject();
636 RelationsDocListItem subj2 = item2.getSubject();
637 RelationsDocListItem obj1 = item.getObject();
638 RelationsDocListItem obj2 = item2.getObject();
640 return (subj1.getCsid().equals(subj2.getCsid()))
641 && (obj1.getCsid().equals(obj1.getCsid()))
642 && ((item.getPredicate().equals(item2.getPredicate()))
643 && (item.getRelationshipType().equals(item2.getRelationshipType())))
644 && (obj1.getDocumentType().equals(obj2.getDocumentType()))
645 && (subj1.getDocumentType().equals(subj2.getDocumentType()));
648 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
652 /* don't even THINK of re-using this method.
653 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
655 private String extractInAuthorityCSID(String uri) {
656 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
657 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
658 Matcher m = p.matcher(uri);
660 if (m.groupCount() < 3) {
661 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
664 //String service = m.group(1);
665 String inauth = m.group(2);
666 //String theRest = m.group(3);
668 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
671 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
676 //ensures CSPACE-4042
677 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
678 String authorityCSID = extractInAuthorityCSID(thisURI);
679 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
680 if (Tools.isBlank(authorityCSID)
681 || Tools.isBlank(authorityCSIDForInbound)
682 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
683 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
687 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
688 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
689 ServiceContext ctx = getServiceContext();
690 MultivaluedMap queryParams = ctx.getQueryParams();
691 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
692 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
693 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
695 RelationResource relationResource = new RelationResource();
696 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
697 return relationsCommonList;
699 //============================= END TODO refactor ==========================