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 field.setElement(AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
171 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
172 null, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
173 // field.setXpath(AuthorityItemJAXBSchema.DISPLAY_NAME);
177 field = new ListResultField();
178 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
179 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
183 field = new ListResultField();
184 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
185 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
188 if (!hasTermStatus) {
189 field = new ListResultField();
190 field.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
191 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
192 null, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
193 // field.setXpath(AuthorityItemJAXBSchema.TERM_STATUS);
202 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
205 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
206 // first fill all the parts of the document
207 super.handleCreate(wrapDoc);
208 // Ensure we have required fields set properly
209 handleInAuthority(wrapDoc.getWrappedObject());
213 handleComputedDisplayNames(wrapDoc.getWrappedObject());
214 String displayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
215 AuthorityItemJAXBSchema.DISPLAY_NAME);
216 if (Tools.isEmpty(displayName)) {
217 logger.warn("Creating Authority Item with no displayName!");
222 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
223 // refName includes displayName, so we force a correct value here.
224 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
228 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
231 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
232 // First, get a copy of the old displayName
233 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
234 // AuthorityItemJAXBSchema.DISPLAY_NAME);
235 oldDisplayNameOnUpdate = (String) getStringValueInPrimaryRepeatingComplexProperty(
236 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
237 getItemTermInfoGroupXPathBase(),
238 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
239 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
240 AuthorityItemJAXBSchema.REF_NAME);
241 super.handleUpdate(wrapDoc);
242 // handleComputedDisplayNames(wrapDoc.getWrappedObject());
243 // String newDisplayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
244 // AuthorityItemJAXBSchema.DISPLAY_NAME);
245 String newDisplayName = (String) getStringValueInPrimaryRepeatingComplexProperty(
246 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
247 this.authorityItemTermGroupXPathBase,
248 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
249 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
250 // Need to update the refName, and then fix all references.
251 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
253 // Mark as not needing attention in completeUpdate phase.
254 newRefNameOnUpdate = null;
255 oldRefNameOnUpdate = null;
260 * Handle display name.
262 * @param docModel the doc model
263 * @throws Exception the exception
265 protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
266 // Do nothing by default.
270 * Handle refName updates for changes to display name.
271 * Assumes refName is already correct. Just ensures it is right.
273 * @param docModel the doc model
274 * @param newDisplayName the new display name
275 * @throws Exception the exception
277 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
278 String newDisplayName) throws Exception {
279 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
280 if (authItem == null) {
281 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
283 throw new IllegalArgumentException(err);
285 authItem.displayName = newDisplayName;
286 String updatedRefName = authItem.toString();
287 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
288 return updatedRefName;
291 protected String getRefPropName() {
292 return ServiceBindingUtils.AUTH_REF_PROP;
296 * Checks to see if the refName has changed, and if so,
297 * uses utilities to find all references and update them.
300 protected void handleItemRefNameReferenceUpdate() throws Exception {
301 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
302 // We have work to do.
303 if (logger.isDebugEnabled()) {
304 String eol = System.getProperty("line.separator");
305 logger.debug("Need to find and update references to Item." + eol
306 + " Old refName" + oldRefNameOnUpdate + eol
307 + " New refName" + newRefNameOnUpdate);
309 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
310 RepositoryClient repoClient = getRepositoryClient(ctx);
311 String refNameProp = getRefPropName();
313 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
314 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
315 if (logger.isDebugEnabled()) {
316 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
322 * If no short identifier was provided in the input payload, generate a
323 * short identifier from the preferred term display name or term name.
325 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
326 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
327 String termDisplayName =
328 (String) getStringValueInPrimaryRepeatingComplexProperty(
329 docModel, authorityItemCommonSchemaName,
330 getItemTermInfoGroupXPathBase(),
331 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
333 (String) getStringValueInPrimaryRepeatingComplexProperty(
334 docModel, authorityItemCommonSchemaName,
335 getItemTermInfoGroupXPathBase(),
336 AuthorityItemJAXBSchema.TERM_NAME);
337 if (Tools.isEmpty(shortIdentifier)) {
338 String generatedShortIdentifier =
339 AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName, termName);
340 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER, generatedShortIdentifier);
345 * Generate a refName for the authority item from the short identifier
348 * All refNames for authority items are generated. If a client supplies
349 * a refName, it will be overwritten during create (per this method)
350 * or discarded during update (per filterReadOnlyPropertiesForPart).
352 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
355 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
357 String authorityRefBaseName) throws Exception {
358 DocumentModel docModel = wrapDoc.getWrappedObject();
359 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
361 (String) getStringValueInPrimaryRepeatingComplexProperty(
362 docModel, authorityItemCommonSchemaName,
363 getItemTermInfoGroupXPathBase(),
364 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
365 if (Tools.isEmpty(authorityRefBaseName)) {
366 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
368 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
369 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
370 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
374 * Check the logic around the parent pointer. Note that we only need do this on
375 * create, since we have logic to make this read-only on update.
379 * @throws Exception the exception
381 private void handleInAuthority(DocumentModel docModel) throws Exception {
382 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
383 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
385 docModel.setProperty(authorityItemCommonSchemaName,
386 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
390 public AuthorityRefDocList getReferencingObjects(
391 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
392 List<String> serviceTypes,
394 String itemcsid) throws Exception {
395 AuthorityRefDocList authRefDocList = null;
396 RepositoryInstance repoSession = null;
397 boolean releaseRepoSession = false;
400 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
401 repoSession = this.getRepositorySession();
402 if (repoSession == null) {
403 repoSession = repoClient.getRepositorySession();
404 releaseRepoSession = true;
406 DocumentFilter myFilter = getDocumentFilter();
409 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
410 DocumentModel docModel = wrapper.getWrappedObject();
411 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
412 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
413 repoSession, ctx, repoClient,
417 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
418 } catch (PropertyException pe) {
420 } catch (DocumentException de) {
422 } catch (Exception e) {
423 if (logger.isDebugEnabled()) {
424 logger.debug("Caught exception ", e);
426 throw new DocumentException(e);
428 if (releaseRepoSession && repoSession != null) {
429 repoClient.releaseRepositorySession(repoSession);
432 } catch (Exception e) {
433 if (logger.isDebugEnabled()) {
434 logger.debug("Caught exception ", e);
436 throw new DocumentException(e);
438 return authRefDocList;
445 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
448 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
450 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
452 // Add the CSID to the common part, since they may have fetched via the shortId.
453 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
454 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
455 unQObjectProperties.put("csid", csid);
458 return unQObjectProperties;
462 * Filters out selected values supplied in an update request.
464 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
465 * that the link to the item's parent remains untouched.
467 * @param objectProps the properties filtered out from the update payload
468 * @param partMeta metadata for the object to fill
471 public void filterReadOnlyPropertiesForPart(
472 Map<String, Object> objectProps, ObjectPartType partMeta) {
473 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
474 String commonPartLabel = getServiceContext().getCommonPartLabel();
475 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
476 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
477 objectProps.remove(AuthorityItemJAXBSchema.CSID);
478 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
479 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
484 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
485 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
486 super.extractAllParts(wrapDoc);
488 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
489 if (Tools.isTrue(showSiblings)) {
490 showSiblings(wrapDoc, ctx);
491 return; // actual result is returned on ctx.addOutputPart();
494 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
495 if (Tools.isTrue(showRelations)) {
496 showRelations(wrapDoc, ctx);
497 return; // actual result is returned on ctx.addOutputPart();
500 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
501 if (Tools.isTrue(showAllRelations)) {
502 showAllRelations(wrapDoc, ctx);
503 return; // actual result is returned on ctx.addOutputPart();
507 /** @return null on parent not found
509 protected String getParentCSID(String thisCSID) throws Exception {
510 String parentCSID = null;
512 String predicate = RelationshipType.HAS_BROADER.value();
513 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
514 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
515 if (parentList != null) {
516 if (parentList.size() == 0) {
519 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
520 parentCSID = relationListItem.getObjectCsid();
523 } catch (Exception e) {
524 logger.error("Could not find parent for this: " + thisCSID, e);
529 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
530 MultipartServiceContext ctx) throws Exception {
531 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
533 String predicate = RelationshipType.HAS_BROADER.value();
534 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
535 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
537 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
538 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
540 if(logger.isTraceEnabled()) {
541 String dump = dumpLists(thisCSID, parentList, childrenList, null);
542 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
545 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
546 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
547 //Not optimal, but that's the current design spec.
549 for (RelationsCommonList.RelationListItem parent : parentList) {
550 childrenList.add(parent);
553 long childrenSize = childrenList.size();
554 childrenListOuter.setTotalItems(childrenSize);
555 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
557 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
558 ctx.addOutputPart(relationsPart);
561 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
562 MultipartServiceContext ctx) throws Exception {
563 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
564 String parentCSID = getParentCSID(thisCSID);
565 if (parentCSID == null) {
566 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
570 String predicate = RelationshipType.HAS_BROADER.value();
571 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
572 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
574 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
577 RelationsCommonList.RelationListItem item = null;
578 for (RelationsCommonList.RelationListItem sibling : siblingList) {
579 if (thisCSID.equals(sibling.getSubjectCsid())) {
580 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.
583 //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.
584 for (RelationsCommonList.RelationListItem self : toRemoveList) {
585 removeFromList(siblingList, self);
588 long siblingSize = siblingList.size();
589 siblingListOuter.setTotalItems(siblingSize);
590 siblingListOuter.setItemsInPage(siblingSize);
591 if(logger.isTraceEnabled()) {
592 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
593 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
596 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
597 ctx.addOutputPart(relationsPart);
600 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
601 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
603 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
604 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
606 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
607 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
609 if(logger.isTraceEnabled()) {
610 String dump = dumpLists(thisCSID, subjectList, objectList, null);
611 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
614 subjectList.addAll(objectList);
616 //now subjectList actually has records BOTH where thisCSID is subject and object.
617 long relatedSize = subjectList.size();
618 subjectListOuter.setTotalItems(relatedSize);
619 subjectListOuter.setItemsInPage(relatedSize);
621 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
622 ctx.addOutputPart(relationsPart);
625 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
626 super.fillAllParts(wrapDoc, action);
628 ServiceContext ctx = getServiceContext();
629 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
630 DocumentModel documentModel = (wrapDoc.getWrappedObject());
631 String itemCsid = documentModel.getName();
633 //UPDATE and CREATE will call. Updates relations part
634 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
636 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
637 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
641 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
642 super.completeCreate(wrapDoc);
643 handleRelationsPayload(wrapDoc, false);
646 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
647 super.completeUpdate(wrapDoc);
648 handleRelationsPayload(wrapDoc, true);
649 handleItemRefNameReferenceUpdate();
652 // Note that we must do this after we have completed the Update, so that the repository has the
653 // info for the item itself. The relations code must call into the repo to get info for each end.
654 // This could be optimized to pass in the parent docModel, since it will often be one end.
655 // Nevertheless, we should complete the item save before we do work on the relations, especially
656 // since a save on Create might fail, and we would not want to create relations for something
657 // that may not be created...
658 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
659 ServiceContext ctx = getServiceContext();
660 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
661 DocumentModel documentModel = (wrapDoc.getWrappedObject());
662 String itemCsid = documentModel.getName();
664 //Updates relations part
665 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
667 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
668 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
670 //now we add part for relations list
671 //ServiceContext ctx = getServiceContext();
672 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
673 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
676 /** updateRelations strategy:
678 go through inboundList, remove anything from childList that matches from childList
679 go through inboundList, remove anything from parentList that matches from parentList
680 go through parentList, delete all remaining
681 go through childList, delete all remaining
682 go through actionList, add all remaining.
683 check for duplicate children
684 check for more than one parent.
686 inboundList parentList childList actionList
687 ---------------- --------------- ---------------- ----------------
688 child-a parent-c child-a child-b
689 child-b parent-d child-c
692 private RelationsCommonList updateRelations(
693 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
695 if (logger.isTraceEnabled()) {
696 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
698 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
700 return null; //nothing to do--they didn't send a list of relations.
702 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
703 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
704 List<RelationsCommonList.RelationListItem> actionList = newList();
705 List<RelationsCommonList.RelationListItem> childList = null;
706 List<RelationsCommonList.RelationListItem> parentList = null;
707 DocumentModel docModel = wrapDoc.getWrappedObject();
708 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
710 ServiceContext ctx = getServiceContext();
711 //Do magic replacement of ${itemCSID} and fix URI's.
712 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
714 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
715 UriInfo uriInfo = ctx.getUriInfo();
716 MultivaluedMap queryParams = uriInfo.getQueryParameters();
719 //Run getList() once as sent to get childListOuter:
720 String predicate = RelationshipType.HAS_BROADER.value();
721 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
722 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
723 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
724 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
725 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
726 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
728 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
729 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
730 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
731 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
732 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
735 childList = childListOuter.getRelationListItem();
736 parentList = parentListOuter.getRelationListItem();
738 if (parentList.size() > 1) {
739 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
742 if (logger.isTraceEnabled()) {
743 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
748 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
749 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
750 // and so the CSID for those may be null
751 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
752 // Look for parents and children
753 if(itemCSID.equals(inboundItem.getObject().getCsid())
754 || itemRefName.equals(inboundItem.getObject().getRefName())) {
755 //then this is an item that says we have a child. That child is inboundItem
756 RelationsCommonList.RelationListItem childItem =
757 (childList == null) ? null : findInList(childList, inboundItem);
758 if (childItem != null) {
759 if (logger.isTraceEnabled()) {
760 StringBuilder sb = new StringBuilder();
761 itemToString(sb, "== Child: ", childItem);
762 logger.trace("Found inboundChild in current child list: " + sb.toString());
764 removeFromList(childList, childItem); //exists, just take it off delete list
766 if (logger.isTraceEnabled()) {
767 StringBuilder sb = new StringBuilder();
768 itemToString(sb, "== Child: ", inboundItem);
769 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
771 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
772 String newChildCsid = inboundItem.getSubject().getCsid();
773 if(newChildCsid == null) {
774 String newChildRefName = inboundItem.getSubject().getRefName();
775 if(newChildRefName==null) {
776 throw new RuntimeException("Child with no CSID or refName!");
778 if (logger.isTraceEnabled()) {
779 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
781 DocumentModel newChildDocModel =
782 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
783 newChildRefName, getServiceContext().getResourceMap());
784 newChildCsid = getCsid(newChildDocModel);
786 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
789 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
790 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
791 //then this is an item that says we have a parent. inboundItem is that parent.
792 RelationsCommonList.RelationListItem parentItem =
793 (parentList == null) ? null : findInList(parentList, inboundItem);
794 if (parentItem != null) {
795 removeFromList(parentList, parentItem); //exists, just take it off delete list
797 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
800 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
803 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
806 if (logger.isTraceEnabled()) {
807 String dump = dumpLists(itemCSID, parentList, childList, actionList);
808 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
811 if (logger.isTraceEnabled()) {
812 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
813 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
815 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
816 deleteRelations(childList, ctx, "childList");
818 if (logger.isTraceEnabled()) {
819 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
820 + actionList.size() + " new parents and children.");
822 createRelations(actionList, ctx);
823 if (logger.isTraceEnabled()) {
824 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
826 //We return all elements on the inbound list, since we have just worked to make them exist in the system
827 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
828 return relationsCommonListBody;
831 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
832 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
833 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
834 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
835 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
836 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
837 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
838 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
839 deleteRelations(parentList, ctx, "parentList-delete");
843 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
845 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
847 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
849 sb.append(item.getPredicate());
851 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
855 private String dumpLists(String itemCSID,
856 List<RelationsCommonList.RelationListItem> parentList,
857 List<RelationsCommonList.RelationListItem> childList,
858 List<RelationsCommonList.RelationListItem> actionList) {
859 StringBuilder sb = new StringBuilder();
860 sb.append("itemCSID: " + itemCSID + CR);
861 if(parentList!=null) {
862 sb.append(dumpList(parentList, "parentList"));
864 if(childList!=null) {
865 sb.append(dumpList(childList, "childList"));
867 if(actionList!=null) {
868 sb.append(dumpList(actionList, "actionList"));
870 return sb.toString();
872 private final static String CR = "\r\n";
873 private final static String T = " ";
875 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
876 StringBuilder sb = new StringBuilder();
878 if (list.size() > 0) {
879 sb.append("=========== " + label + " ==========" + CR);
881 for (RelationsCommonList.RelationListItem item : list) {
882 itemToString(sb, "== ", item);
885 return sb.toString();
888 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
889 * and sets URI correctly for related items.
890 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
892 protected void fixupInboundListItems(ServiceContext ctx,
893 List<RelationsCommonList.RelationListItem> inboundList,
894 DocumentModel docModel,
895 String itemCSID) throws Exception {
896 String thisURI = this.getUri(docModel);
897 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
898 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
899 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
900 RelationsDocListItem inboundItemObject = inboundItem.getObject();
901 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
903 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
904 inboundItem.setObjectCsid(itemCSID);
905 inboundItemObject.setCsid(itemCSID);
906 //inboundItemObject.setUri(getUri(docModel));
909 String objectCsid = inboundItemObject.getCsid();
910 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
911 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
912 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
913 inboundItemObject.setUri(uri); //CSPACE-4037
916 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
918 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
919 inboundItem.setSubjectCsid(itemCSID);
920 inboundItemSubject.setCsid(itemCSID);
921 //inboundItemSubject.setUri(getUri(docModel));
924 String subjectCsid = inboundItemSubject.getCsid();
925 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
926 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
927 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
928 inboundItemSubject.setUri(uri); //CSPACE-4037
931 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
936 // this method calls the RelationResource to have it create the relations and persist them.
937 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
938 for (RelationsCommonList.RelationListItem item : inboundList) {
939 RelationsCommon rc = new RelationsCommon();
940 //rc.setCsid(item.getCsid());
941 //todo: assignTo(item, rc);
942 RelationsDocListItem itemSubject = item.getSubject();
943 RelationsDocListItem itemObject = item.getObject();
945 // Set at least one of CSID and refName for Subject and Object
946 // Either value might be null for for each of Subject and Object
947 String subjectCsid = itemSubject.getCsid();
948 rc.setSubjectCsid(subjectCsid);
950 String objCsid = itemObject.getCsid();
951 rc.setObjectCsid(objCsid);
953 rc.setSubjectRefName(itemSubject.getRefName());
954 rc.setObjectRefName(itemObject.getRefName());
956 rc.setRelationshipType(item.getPredicate());
957 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
958 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
960 // This is superfluous, since it will be fetched by the Relations Create logic.
961 rc.setSubjectDocumentType(itemSubject.getDocumentType());
962 rc.setObjectDocumentType(itemObject.getDocumentType());
964 // This is superfluous, since it will be fetched by the Relations Create logic.
965 rc.setSubjectUri(itemSubject.getUri());
966 rc.setObjectUri(itemObject.getUri());
967 // May not have the info here. Only really require CSID or refName.
968 // Rest is handled in the Relation create mechanism
969 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
971 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
972 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
973 payloadOut.addPart(outputPart);
974 RelationResource relationResource = new RelationResource();
975 Object res = relationResource.create(ctx.getResourceMap(),
976 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
980 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
982 for (RelationsCommonList.RelationListItem item : list) {
983 RelationResource relationResource = new RelationResource();
984 if(logger.isTraceEnabled()) {
985 StringBuilder sb = new StringBuilder();
986 itemToString(sb, "==== TO DELETE: ", item);
987 logger.trace(sb.toString());
989 Object res = relationResource.delete(item.getCsid());
991 } catch (Throwable t) {
992 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
997 private List<RelationsCommonList.RelationListItem> newList() {
998 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1002 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1003 List<RelationsCommonList.RelationListItem> result = newList();
1004 for (RelationsCommonList.RelationListItem item : inboundList) {
1010 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1011 // But the list items must not be sparse
1012 private RelationsCommonList.RelationListItem findInList(
1013 List<RelationsCommonList.RelationListItem> list,
1014 RelationsCommonList.RelationListItem item) {
1015 RelationsCommonList.RelationListItem foundItem = null;
1016 for (RelationsCommonList.RelationListItem listItem : list) {
1017 if (itemsEqual(listItem, item)) { //equals must be defined, else
1018 foundItem = listItem;
1025 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1026 // But item1 must not be sparse
1027 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1028 if (item1 == null || item2 == null) {
1031 RelationsDocListItem subj1 = item1.getSubject();
1032 RelationsDocListItem subj2 = item2.getSubject();
1033 RelationsDocListItem obj1 = item1.getObject();
1034 RelationsDocListItem obj2 = item2.getObject();
1035 String subj1Csid = subj1.getCsid();
1036 String subj2Csid = subj2.getCsid();
1037 String subj1RefName = subj1.getRefName();
1038 String subj2RefName = subj2.getRefName();
1040 String obj1Csid = obj1.getCsid();
1041 String obj2Csid = obj2.getCsid();
1042 String obj1RefName = obj1.getRefName();
1043 String obj2RefName = obj2.getRefName();
1046 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1047 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1048 // predicate is proper, but still allow relationshipType
1049 && (item1.getPredicate().equals(item2.getPredicate())
1050 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1051 // Allow missing docTypes, so long as they do not conflict
1052 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1053 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1057 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1061 /* don't even THINK of re-using this method.
1062 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1064 private String extractInAuthorityCSID(String uri) {
1065 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1066 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1067 Matcher m = p.matcher(uri);
1069 if (m.groupCount() < 3) {
1070 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1073 //String service = m.group(1);
1074 String inauth = m.group(2);
1075 //String theRest = m.group(3);
1077 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1080 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1085 //ensures CSPACE-4042
1086 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1087 String authorityCSID = extractInAuthorityCSID(thisURI);
1088 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1089 if (Tools.isBlank(authorityCSID)
1090 || Tools.isBlank(authorityCSIDForInbound)
1091 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1092 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1096 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1097 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1098 ServiceContext ctx = getServiceContext();
1099 MultivaluedMap queryParams = ctx.getQueryParams();
1100 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1101 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1102 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1104 RelationResource relationResource = new RelationResource();
1105 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1106 return relationsCommonList;
1108 //============================= END TODO refactor ==========================
1110 public String getItemTermInfoGroupXPathBase() {
1111 return this.authorityItemTermGroupXPathBase;
1114 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1115 this.authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;