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.ResourceBase;
33 import org.collectionspace.services.common.ServiceMessages;
34 import org.collectionspace.services.common.api.CommonAPI;
35 import org.collectionspace.services.common.api.RefName;
36 import org.collectionspace.services.common.api.Tools;
37 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
38 import org.collectionspace.services.common.context.MultipartServiceContext;
39 import org.collectionspace.services.common.context.ServiceBindingUtils;
40 import org.collectionspace.services.common.context.ServiceContext;
41 import org.collectionspace.services.common.document.DocumentException;
42 import org.collectionspace.services.common.document.DocumentFilter;
43 import org.collectionspace.services.common.document.DocumentWrapper;
44 import org.collectionspace.services.common.document.DocumentWrapperImpl;
45 import org.collectionspace.services.common.relation.IRelationsManager;
46 import org.collectionspace.services.common.repository.RepositoryClient;
47 import org.collectionspace.services.common.repository.RepositoryClientFactory;
48 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
49 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
50 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils;
51 import org.collectionspace.services.config.service.ListResultField;
52 import org.collectionspace.services.config.service.ObjectPartType;
53 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
54 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
55 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
56 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
57 import org.collectionspace.services.relation.RelationResource;
58 import org.collectionspace.services.relation.RelationsCommon;
59 import org.collectionspace.services.relation.RelationsCommonList;
60 import org.collectionspace.services.relation.RelationsDocListItem;
61 import org.collectionspace.services.relation.RelationshipType;
62 import org.nuxeo.ecm.core.api.ClientException;
63 import org.nuxeo.ecm.core.api.DocumentModel;
64 import org.nuxeo.ecm.core.api.model.PropertyException;
65 import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
66 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
67 import org.nuxeo.runtime.transaction.TransactionHelper;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
71 import javax.ws.rs.PathParam;
72 import javax.ws.rs.WebApplicationException;
73 import javax.ws.rs.core.Context;
74 import javax.ws.rs.core.MultivaluedMap;
75 import javax.ws.rs.core.Response;
76 import javax.ws.rs.core.UriInfo;
77 import java.util.ArrayList;
78 import java.util.List;
80 import java.util.regex.Matcher;
81 import java.util.regex.Pattern;
82 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
84 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
86 * AuthorityItemDocumentModelHandler
88 * $LastChangedRevision: $
91 public abstract class AuthorityItemDocumentModelHandler<AICommon>
92 extends DocHandlerBase<AICommon> {
94 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
95 private String authorityItemCommonSchemaName;
96 private String authorityItemTermGroupXPathBase;
98 * inVocabulary is the parent Authority for this context
100 protected String inAuthority = null;
101 protected String authorityRefNameBase = null;
102 // Used to determine when the displayName changes as part of the update.
103 protected String oldDisplayNameOnUpdate = null;
104 protected String oldRefNameOnUpdate = null;
105 protected String newRefNameOnUpdate = null;
107 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
108 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
111 public void setInAuthority(String inAuthority) {
112 this.inAuthority = inAuthority;
115 /** Subclasses may override this to customize the URI segment. */
116 public String getAuthorityServicePath() {
117 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
121 public String getUri(DocumentModel docModel) {
122 // Laramie20110510 CSPACE-3932
123 String authorityServicePath = getAuthorityServicePath();
124 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
126 inAuthority = (String) docModel.getProperty(authorityItemCommonSchemaName,
127 AuthorityItemJAXBSchema.IN_AUTHORITY);
128 } catch (ClientException pe) {
129 throw new RuntimeException("Could not get parent specifier for item!");
132 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
135 protected String getAuthorityRefNameBase() {
136 return this.authorityRefNameBase;
139 public void setAuthorityRefNameBase(String value) {
140 this.authorityRefNameBase = value;
144 public List<ListResultField> getListItemsArray() throws DocumentException {
145 List<ListResultField> list = super.getListItemsArray();
146 int nFields = list.size();
147 // Ensure that each item in a list of Authority items includes
148 // a set of common fields, so we do not depend upon configuration
149 // for general logic.
150 boolean hasDisplayName = false;
151 boolean hasShortId = false;
152 boolean hasRefName = false;
153 boolean hasTermStatus = false;
154 for (int i = 0; i < nFields; i++) {
155 ListResultField field = list.get(i);
156 String elName = field.getElement();
157 if (AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName)) {
158 hasDisplayName = true;
159 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
161 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
163 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
164 hasTermStatus = true;
167 ListResultField field;
168 if (!hasDisplayName) {
169 field = new ListResultField();
170 // Per CSPACE-5132, the name of this element remains 'displayName'
171 // for backwards compatibility, although its value is obtained
172 // from the termDisplayName field.
174 // In CSPACE-5134, these list results will change substantially
175 // to return display names for both the preferred term and for
176 // each non-preferred term (if any).
177 field.setElement(AuthorityItemJAXBSchema.DISPLAY_NAME);
178 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
179 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
183 field = new ListResultField();
184 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
185 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
189 field = new ListResultField();
190 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
191 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
194 if (!hasTermStatus) {
195 field = new ListResultField();
196 field.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
197 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
198 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
207 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
210 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
211 // first fill all the parts of the document
212 super.handleCreate(wrapDoc);
213 // Ensure we have required fields set properly
214 handleInAuthority(wrapDoc.getWrappedObject());
218 handleComputedDisplayNames(wrapDoc.getWrappedObject());
219 String displayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
220 AuthorityItemJAXBSchema.DISPLAY_NAME);
221 if (Tools.isEmpty(displayName)) {
222 logger.warn("Creating Authority Item with no displayName!");
228 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
229 // refName includes displayName, so we force a correct value here.
230 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
234 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
237 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
238 // First, get a copy of the old displayName
239 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
240 // AuthorityItemJAXBSchema.DISPLAY_NAME);
241 oldDisplayNameOnUpdate = (String) getStringValueInPrimaryRepeatingComplexProperty(
242 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
243 getItemTermInfoGroupXPathBase(),
244 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
245 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
246 AuthorityItemJAXBSchema.REF_NAME);
247 super.handleUpdate(wrapDoc);
248 // handleComputedDisplayNames(wrapDoc.getWrappedObject());
249 // String newDisplayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
250 // AuthorityItemJAXBSchema.DISPLAY_NAME);
251 String newDisplayName = (String) getStringValueInPrimaryRepeatingComplexProperty(
252 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
253 this.authorityItemTermGroupXPathBase,
254 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
255 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
256 // Need to update the refName, and then fix all references.
257 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
259 // Mark as not needing attention in completeUpdate phase.
260 newRefNameOnUpdate = null;
261 oldRefNameOnUpdate = null;
266 * Handle display name.
268 * @param docModel the doc model
269 * @throws Exception the exception
271 protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
272 // Do nothing by default.
276 * Handle refName updates for changes to display name.
277 * Assumes refName is already correct. Just ensures it is right.
279 * @param docModel the doc model
280 * @param newDisplayName the new display name
281 * @throws Exception the exception
283 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
284 String newDisplayName) throws Exception {
285 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
286 if (authItem == null) {
287 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
289 throw new IllegalArgumentException(err);
291 authItem.displayName = newDisplayName;
292 String updatedRefName = authItem.toString();
293 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
294 return updatedRefName;
297 protected String getRefPropName() {
298 return ServiceBindingUtils.AUTH_REF_PROP;
302 * Checks to see if the refName has changed, and if so,
303 * uses utilities to find all references and update them.
306 protected void handleItemRefNameReferenceUpdate() throws Exception {
307 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
308 // We have work to do.
309 if (logger.isDebugEnabled()) {
310 String eol = System.getProperty("line.separator");
311 logger.debug("Need to find and update references to Item." + eol
312 + " Old refName" + oldRefNameOnUpdate + eol
313 + " New refName" + newRefNameOnUpdate);
315 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
316 RepositoryClient repoClient = getRepositoryClient(ctx);
317 String refNameProp = getRefPropName();
319 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
320 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
321 if (logger.isDebugEnabled()) {
322 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
328 * If no short identifier was provided in the input payload, generate a
329 * short identifier from the preferred term display name or term name.
331 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
332 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
333 String termDisplayName =
334 (String) getStringValueInPrimaryRepeatingComplexProperty(
335 docModel, authorityItemCommonSchemaName,
336 getItemTermInfoGroupXPathBase(),
337 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
339 (String) getStringValueInPrimaryRepeatingComplexProperty(
340 docModel, authorityItemCommonSchemaName,
341 getItemTermInfoGroupXPathBase(),
342 AuthorityItemJAXBSchema.TERM_NAME);
343 if (Tools.isEmpty(shortIdentifier)) {
344 String generatedShortIdentifier =
345 AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName, termName);
346 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER, generatedShortIdentifier);
351 * Generate a refName for the authority item from the short identifier
354 * All refNames for authority items are generated. If a client supplies
355 * a refName, it will be overwritten during create (per this method)
356 * or discarded during update (per filterReadOnlyPropertiesForPart).
358 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
361 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
363 String authorityRefBaseName) throws Exception {
364 DocumentModel docModel = wrapDoc.getWrappedObject();
365 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
367 (String) getStringValueInPrimaryRepeatingComplexProperty(
368 docModel, authorityItemCommonSchemaName,
369 getItemTermInfoGroupXPathBase(),
370 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
371 if (Tools.isEmpty(authorityRefBaseName)) {
372 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
374 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
375 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
376 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
380 * Check the logic around the parent pointer. Note that we only need do this on
381 * create, since we have logic to make this read-only on update.
385 * @throws Exception the exception
387 private void handleInAuthority(DocumentModel docModel) throws Exception {
388 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
389 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
391 docModel.setProperty(authorityItemCommonSchemaName,
392 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
396 public AuthorityRefDocList getReferencingObjects(
397 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
398 List<String> serviceTypes,
400 String itemcsid) throws Exception {
401 AuthorityRefDocList authRefDocList = null;
402 RepositoryInstance repoSession = null;
403 boolean releaseRepoSession = false;
406 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
407 repoSession = this.getRepositorySession();
408 if (repoSession == null) {
409 repoSession = repoClient.getRepositorySession();
410 releaseRepoSession = true;
412 DocumentFilter myFilter = getDocumentFilter();
415 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
416 DocumentModel docModel = wrapper.getWrappedObject();
417 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
418 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
419 repoSession, ctx, repoClient,
423 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
424 } catch (PropertyException pe) {
426 } catch (DocumentException de) {
428 } catch (Exception e) {
429 if (logger.isDebugEnabled()) {
430 logger.debug("Caught exception ", e);
432 throw new DocumentException(e);
434 if (releaseRepoSession && repoSession != null) {
435 repoClient.releaseRepositorySession(repoSession);
438 } catch (Exception e) {
439 if (logger.isDebugEnabled()) {
440 logger.debug("Caught exception ", e);
442 throw new DocumentException(e);
444 return authRefDocList;
451 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
454 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
456 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
458 // Add the CSID to the common part, since they may have fetched via the shortId.
459 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
460 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
461 unQObjectProperties.put("csid", csid);
464 return unQObjectProperties;
468 * Filters out selected values supplied in an update request.
470 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
471 * that the link to the item's parent remains untouched.
473 * @param objectProps the properties filtered out from the update payload
474 * @param partMeta metadata for the object to fill
477 public void filterReadOnlyPropertiesForPart(
478 Map<String, Object> objectProps, ObjectPartType partMeta) {
479 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
480 String commonPartLabel = getServiceContext().getCommonPartLabel();
481 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
482 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
483 objectProps.remove(AuthorityItemJAXBSchema.CSID);
484 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
485 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
490 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
491 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
492 super.extractAllParts(wrapDoc);
494 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
495 if (Tools.isTrue(showSiblings)) {
496 showSiblings(wrapDoc, ctx);
497 return; // actual result is returned on ctx.addOutputPart();
500 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
501 if (Tools.isTrue(showRelations)) {
502 showRelations(wrapDoc, ctx);
503 return; // actual result is returned on ctx.addOutputPart();
506 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
507 if (Tools.isTrue(showAllRelations)) {
508 showAllRelations(wrapDoc, ctx);
509 return; // actual result is returned on ctx.addOutputPart();
513 /** @return null on parent not found
515 protected String getParentCSID(String thisCSID) throws Exception {
516 String parentCSID = null;
518 String predicate = RelationshipType.HAS_BROADER.value();
519 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
520 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
521 if (parentList != null) {
522 if (parentList.size() == 0) {
525 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
526 parentCSID = relationListItem.getObjectCsid();
529 } catch (Exception e) {
530 logger.error("Could not find parent for this: " + thisCSID, e);
535 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
536 MultipartServiceContext ctx) throws Exception {
537 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
539 String predicate = RelationshipType.HAS_BROADER.value();
540 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
541 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
543 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
544 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
546 if(logger.isTraceEnabled()) {
547 String dump = dumpLists(thisCSID, parentList, childrenList, null);
548 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
551 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
552 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
553 //Not optimal, but that's the current design spec.
555 for (RelationsCommonList.RelationListItem parent : parentList) {
556 childrenList.add(parent);
559 long childrenSize = childrenList.size();
560 childrenListOuter.setTotalItems(childrenSize);
561 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
563 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
564 ctx.addOutputPart(relationsPart);
567 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
568 MultipartServiceContext ctx) throws Exception {
569 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
570 String parentCSID = getParentCSID(thisCSID);
571 if (parentCSID == null) {
572 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
576 String predicate = RelationshipType.HAS_BROADER.value();
577 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
578 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
580 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
583 RelationsCommonList.RelationListItem item = null;
584 for (RelationsCommonList.RelationListItem sibling : siblingList) {
585 if (thisCSID.equals(sibling.getSubjectCsid())) {
586 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.
589 //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.
590 for (RelationsCommonList.RelationListItem self : toRemoveList) {
591 removeFromList(siblingList, self);
594 long siblingSize = siblingList.size();
595 siblingListOuter.setTotalItems(siblingSize);
596 siblingListOuter.setItemsInPage(siblingSize);
597 if(logger.isTraceEnabled()) {
598 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
599 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
602 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
603 ctx.addOutputPart(relationsPart);
606 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
607 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
609 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
610 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
612 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
613 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
615 if(logger.isTraceEnabled()) {
616 String dump = dumpLists(thisCSID, subjectList, objectList, null);
617 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
620 subjectList.addAll(objectList);
622 //now subjectList actually has records BOTH where thisCSID is subject and object.
623 long relatedSize = subjectList.size();
624 subjectListOuter.setTotalItems(relatedSize);
625 subjectListOuter.setItemsInPage(relatedSize);
627 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
628 ctx.addOutputPart(relationsPart);
631 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
632 super.fillAllParts(wrapDoc, action);
634 ServiceContext ctx = getServiceContext();
635 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
636 DocumentModel documentModel = (wrapDoc.getWrappedObject());
637 String itemCsid = documentModel.getName();
639 //UPDATE and CREATE will call. Updates relations part
640 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
642 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
643 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
647 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
648 super.completeCreate(wrapDoc);
649 handleRelationsPayload(wrapDoc, false);
652 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
653 super.completeUpdate(wrapDoc);
654 handleRelationsPayload(wrapDoc, true);
655 handleItemRefNameReferenceUpdate();
658 // Note that we must do this after we have completed the Update, so that the repository has the
659 // info for the item itself. The relations code must call into the repo to get info for each end.
660 // This could be optimized to pass in the parent docModel, since it will often be one end.
661 // Nevertheless, we should complete the item save before we do work on the relations, especially
662 // since a save on Create might fail, and we would not want to create relations for something
663 // that may not be created...
664 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
665 ServiceContext ctx = getServiceContext();
666 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
667 DocumentModel documentModel = (wrapDoc.getWrappedObject());
668 String itemCsid = documentModel.getName();
670 //Updates relations part
671 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
673 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
674 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
676 //now we add part for relations list
677 //ServiceContext ctx = getServiceContext();
678 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
679 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
682 /** updateRelations strategy:
684 go through inboundList, remove anything from childList that matches from childList
685 go through inboundList, remove anything from parentList that matches from parentList
686 go through parentList, delete all remaining
687 go through childList, delete all remaining
688 go through actionList, add all remaining.
689 check for duplicate children
690 check for more than one parent.
692 inboundList parentList childList actionList
693 ---------------- --------------- ---------------- ----------------
694 child-a parent-c child-a child-b
695 child-b parent-d child-c
698 private RelationsCommonList updateRelations(
699 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
701 if (logger.isTraceEnabled()) {
702 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
704 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
706 return null; //nothing to do--they didn't send a list of relations.
708 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
709 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
710 List<RelationsCommonList.RelationListItem> actionList = newList();
711 List<RelationsCommonList.RelationListItem> childList = null;
712 List<RelationsCommonList.RelationListItem> parentList = null;
713 DocumentModel docModel = wrapDoc.getWrappedObject();
714 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
716 ServiceContext ctx = getServiceContext();
717 //Do magic replacement of ${itemCSID} and fix URI's.
718 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
720 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
721 UriInfo uriInfo = ctx.getUriInfo();
722 MultivaluedMap queryParams = uriInfo.getQueryParameters();
725 //Run getList() once as sent to get childListOuter:
726 String predicate = RelationshipType.HAS_BROADER.value();
727 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
728 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
729 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
730 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
731 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
732 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
734 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
735 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
736 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
737 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
738 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
741 childList = childListOuter.getRelationListItem();
742 parentList = parentListOuter.getRelationListItem();
744 if (parentList.size() > 1) {
745 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
748 if (logger.isTraceEnabled()) {
749 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
754 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
755 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
756 // and so the CSID for those may be null
757 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
758 // Look for parents and children
759 if(itemCSID.equals(inboundItem.getObject().getCsid())
760 || itemRefName.equals(inboundItem.getObject().getRefName())) {
761 //then this is an item that says we have a child. That child is inboundItem
762 RelationsCommonList.RelationListItem childItem =
763 (childList == null) ? null : findInList(childList, inboundItem);
764 if (childItem != null) {
765 if (logger.isTraceEnabled()) {
766 StringBuilder sb = new StringBuilder();
767 itemToString(sb, "== Child: ", childItem);
768 logger.trace("Found inboundChild in current child list: " + sb.toString());
770 removeFromList(childList, childItem); //exists, just take it off delete list
772 if (logger.isTraceEnabled()) {
773 StringBuilder sb = new StringBuilder();
774 itemToString(sb, "== Child: ", inboundItem);
775 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
777 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
778 String newChildCsid = inboundItem.getSubject().getCsid();
779 if(newChildCsid == null) {
780 String newChildRefName = inboundItem.getSubject().getRefName();
781 if(newChildRefName==null) {
782 throw new RuntimeException("Child with no CSID or refName!");
784 if (logger.isTraceEnabled()) {
785 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
787 DocumentModel newChildDocModel =
788 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
789 newChildRefName, getServiceContext().getResourceMap());
790 newChildCsid = getCsid(newChildDocModel);
792 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
795 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
796 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
797 //then this is an item that says we have a parent. inboundItem is that parent.
798 RelationsCommonList.RelationListItem parentItem =
799 (parentList == null) ? null : findInList(parentList, inboundItem);
800 if (parentItem != null) {
801 removeFromList(parentList, parentItem); //exists, just take it off delete list
803 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
806 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
809 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
812 if (logger.isTraceEnabled()) {
813 String dump = dumpLists(itemCSID, parentList, childList, actionList);
814 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
817 if (logger.isTraceEnabled()) {
818 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
819 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
821 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
822 deleteRelations(childList, ctx, "childList");
824 if (logger.isTraceEnabled()) {
825 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
826 + actionList.size() + " new parents and children.");
828 createRelations(actionList, ctx);
829 if (logger.isTraceEnabled()) {
830 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
832 //We return all elements on the inbound list, since we have just worked to make them exist in the system
833 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
834 return relationsCommonListBody;
837 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
838 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
839 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
840 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
841 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
842 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
843 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
844 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
845 deleteRelations(parentList, ctx, "parentList-delete");
849 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
851 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
853 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
855 sb.append(item.getPredicate());
857 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
861 private String dumpLists(String itemCSID,
862 List<RelationsCommonList.RelationListItem> parentList,
863 List<RelationsCommonList.RelationListItem> childList,
864 List<RelationsCommonList.RelationListItem> actionList) {
865 StringBuilder sb = new StringBuilder();
866 sb.append("itemCSID: " + itemCSID + CR);
867 if(parentList!=null) {
868 sb.append(dumpList(parentList, "parentList"));
870 if(childList!=null) {
871 sb.append(dumpList(childList, "childList"));
873 if(actionList!=null) {
874 sb.append(dumpList(actionList, "actionList"));
876 return sb.toString();
878 private final static String CR = "\r\n";
879 private final static String T = " ";
881 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
882 StringBuilder sb = new StringBuilder();
884 if (list.size() > 0) {
885 sb.append("=========== " + label + " ==========" + CR);
887 for (RelationsCommonList.RelationListItem item : list) {
888 itemToString(sb, "== ", item);
891 return sb.toString();
894 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
895 * and sets URI correctly for related items.
896 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
898 protected void fixupInboundListItems(ServiceContext ctx,
899 List<RelationsCommonList.RelationListItem> inboundList,
900 DocumentModel docModel,
901 String itemCSID) throws Exception {
902 String thisURI = this.getUri(docModel);
903 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
904 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
905 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
906 RelationsDocListItem inboundItemObject = inboundItem.getObject();
907 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
909 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
910 inboundItem.setObjectCsid(itemCSID);
911 inboundItemObject.setCsid(itemCSID);
912 //inboundItemObject.setUri(getUri(docModel));
915 String objectCsid = inboundItemObject.getCsid();
916 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
917 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
918 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
919 inboundItemObject.setUri(uri); //CSPACE-4037
922 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
924 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
925 inboundItem.setSubjectCsid(itemCSID);
926 inboundItemSubject.setCsid(itemCSID);
927 //inboundItemSubject.setUri(getUri(docModel));
930 String subjectCsid = inboundItemSubject.getCsid();
931 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
932 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
933 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
934 inboundItemSubject.setUri(uri); //CSPACE-4037
937 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
942 // this method calls the RelationResource to have it create the relations and persist them.
943 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
944 for (RelationsCommonList.RelationListItem item : inboundList) {
945 RelationsCommon rc = new RelationsCommon();
946 //rc.setCsid(item.getCsid());
947 //todo: assignTo(item, rc);
948 RelationsDocListItem itemSubject = item.getSubject();
949 RelationsDocListItem itemObject = item.getObject();
951 // Set at least one of CSID and refName for Subject and Object
952 // Either value might be null for for each of Subject and Object
953 String subjectCsid = itemSubject.getCsid();
954 rc.setSubjectCsid(subjectCsid);
956 String objCsid = itemObject.getCsid();
957 rc.setObjectCsid(objCsid);
959 rc.setSubjectRefName(itemSubject.getRefName());
960 rc.setObjectRefName(itemObject.getRefName());
962 rc.setRelationshipType(item.getPredicate());
963 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
964 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
966 // This is superfluous, since it will be fetched by the Relations Create logic.
967 rc.setSubjectDocumentType(itemSubject.getDocumentType());
968 rc.setObjectDocumentType(itemObject.getDocumentType());
970 // This is superfluous, since it will be fetched by the Relations Create logic.
971 rc.setSubjectUri(itemSubject.getUri());
972 rc.setObjectUri(itemObject.getUri());
973 // May not have the info here. Only really require CSID or refName.
974 // Rest is handled in the Relation create mechanism
975 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
977 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
978 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
979 payloadOut.addPart(outputPart);
980 RelationResource relationResource = new RelationResource();
981 Object res = relationResource.create(ctx.getResourceMap(),
982 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
986 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
988 for (RelationsCommonList.RelationListItem item : list) {
989 RelationResource relationResource = new RelationResource();
990 if(logger.isTraceEnabled()) {
991 StringBuilder sb = new StringBuilder();
992 itemToString(sb, "==== TO DELETE: ", item);
993 logger.trace(sb.toString());
995 Object res = relationResource.delete(item.getCsid());
997 } catch (Throwable t) {
998 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1003 private List<RelationsCommonList.RelationListItem> newList() {
1004 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1008 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1009 List<RelationsCommonList.RelationListItem> result = newList();
1010 for (RelationsCommonList.RelationListItem item : inboundList) {
1016 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1017 // But the list items must not be sparse
1018 private RelationsCommonList.RelationListItem findInList(
1019 List<RelationsCommonList.RelationListItem> list,
1020 RelationsCommonList.RelationListItem item) {
1021 RelationsCommonList.RelationListItem foundItem = null;
1022 for (RelationsCommonList.RelationListItem listItem : list) {
1023 if (itemsEqual(listItem, item)) { //equals must be defined, else
1024 foundItem = listItem;
1031 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1032 // But item1 must not be sparse
1033 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1034 if (item1 == null || item2 == null) {
1037 RelationsDocListItem subj1 = item1.getSubject();
1038 RelationsDocListItem subj2 = item2.getSubject();
1039 RelationsDocListItem obj1 = item1.getObject();
1040 RelationsDocListItem obj2 = item2.getObject();
1041 String subj1Csid = subj1.getCsid();
1042 String subj2Csid = subj2.getCsid();
1043 String subj1RefName = subj1.getRefName();
1044 String subj2RefName = subj2.getRefName();
1046 String obj1Csid = obj1.getCsid();
1047 String obj2Csid = obj2.getCsid();
1048 String obj1RefName = obj1.getRefName();
1049 String obj2RefName = obj2.getRefName();
1052 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1053 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1054 // predicate is proper, but still allow relationshipType
1055 && (item1.getPredicate().equals(item2.getPredicate())
1056 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1057 // Allow missing docTypes, so long as they do not conflict
1058 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1059 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1063 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1067 /* don't even THINK of re-using this method.
1068 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1070 private String extractInAuthorityCSID(String uri) {
1071 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1072 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1073 Matcher m = p.matcher(uri);
1075 if (m.groupCount() < 3) {
1076 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1079 //String service = m.group(1);
1080 String inauth = m.group(2);
1081 //String theRest = m.group(3);
1083 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1086 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1091 //ensures CSPACE-4042
1092 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1093 String authorityCSID = extractInAuthorityCSID(thisURI);
1094 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1095 if (Tools.isBlank(authorityCSID)
1096 || Tools.isBlank(authorityCSIDForInbound)
1097 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1098 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1102 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1103 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1104 ServiceContext ctx = getServiceContext();
1105 MultivaluedMap queryParams = ctx.getQueryParams();
1106 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1107 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1108 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1110 RelationResource relationResource = new RelationResource();
1111 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1112 return relationsCommonList;
1114 //============================= END TODO refactor ==========================
1116 public String getItemTermInfoGroupXPathBase() {
1117 return this.authorityItemTermGroupXPathBase;
1120 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1121 this.authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;