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 * Note that the Vocabulary service's item-documentmodel-handler will override this method.
146 protected ListResultField getListResultField() {
147 ListResultField result = new ListResultField();
148 // Per CSPACE-5132, the name of this element remains 'displayName'
149 // for backwards compatibility, although its value is obtained
150 // from the termDisplayName field.
152 // In CSPACE-5134, these list results will change substantially
153 // to return display names for both the preferred term and for
154 // each non-preferred term (if any).
155 result.setElement(AuthorityItemJAXBSchema.DISPLAY_NAME);
156 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
157 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
163 public List<ListResultField> getListItemsArray() throws DocumentException {
164 List<ListResultField> list = super.getListItemsArray();
165 int nFields = list.size();
166 // Ensure that each item in a list of Authority items includes
167 // a set of common fields, so we do not depend upon configuration
168 // for general logic.
169 boolean hasDisplayName = false;
170 boolean hasShortId = false;
171 boolean hasRefName = false;
172 boolean hasTermStatus = false;
173 for (int i = 0; i < nFields; i++) {
174 ListResultField field = list.get(i);
175 String elName = field.getElement();
176 if (AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName) || AuthorityItemJAXBSchema.DISPLAY_NAME.equals(elName)) {
177 hasDisplayName = true;
178 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
180 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
182 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
183 hasTermStatus = true;
186 ListResultField field;
187 if (!hasDisplayName) {
188 field = getListResultField();
192 field = new ListResultField();
193 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
194 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
198 field = new ListResultField();
199 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
200 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
203 if (!hasTermStatus) {
204 field = new ListResultField();
205 field.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
206 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
207 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
216 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
219 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
220 // first fill all the parts of the document
221 super.handleCreate(wrapDoc);
222 // Ensure we have required fields set properly
223 handleInAuthority(wrapDoc.getWrappedObject());
226 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
227 // refName includes displayName, so we force a correct value here.
228 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
232 * Note that the Vocabulary service's document-model for items overrides this method.
234 protected String getPrimaryDisplayName(DocumentModel docModel, String schema,
235 String complexPropertyName, String fieldName) {
236 String result = null;
238 result = getStringValueInPrimaryRepeatingComplexProperty(docModel, schema, complexPropertyName, fieldName);
244 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
247 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
248 // First, get a copy of the old displayName
249 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
250 // AuthorityItemJAXBSchema.DISPLAY_NAME);
251 oldDisplayNameOnUpdate = getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
252 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
253 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
254 AuthorityItemJAXBSchema.REF_NAME);
255 super.handleUpdate(wrapDoc);
257 // Now, check the new display and handle the refname update.
258 String newDisplayName = (String) getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
259 this.authorityItemTermGroupXPathBase,
260 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
261 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
262 // Need to update the refName, and then fix all references.
263 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
265 // Mark as not needing attention in completeUpdate phase.
266 newRefNameOnUpdate = null;
267 oldRefNameOnUpdate = null;
272 * Handle display name.
274 * @param docModel the doc model
275 * @throws Exception the exception
277 // protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
278 // // Do nothing by default.
282 * Handle refName updates for changes to display name.
283 * Assumes refName is already correct. Just ensures it is right.
285 * @param docModel the doc model
286 * @param newDisplayName the new display name
287 * @throws Exception the exception
289 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
290 String newDisplayName) throws Exception {
291 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
292 if (authItem == null) {
293 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
295 throw new IllegalArgumentException(err);
297 authItem.displayName = newDisplayName;
298 String updatedRefName = authItem.toString();
299 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
300 return updatedRefName;
303 protected String getRefPropName() {
304 return ServiceBindingUtils.AUTH_REF_PROP;
308 * Checks to see if the refName has changed, and if so,
309 * uses utilities to find all references and update them.
312 protected void handleItemRefNameReferenceUpdate() throws Exception {
313 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
314 // We have work to do.
315 if (logger.isDebugEnabled()) {
316 String eol = System.getProperty("line.separator");
317 logger.debug("Need to find and update references to Item." + eol
318 + " Old refName" + oldRefNameOnUpdate + eol
319 + " New refName" + newRefNameOnUpdate);
321 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
322 RepositoryClient repoClient = getRepositoryClient(ctx);
323 String refNameProp = getRefPropName();
325 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
326 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
327 if (logger.isDebugEnabled()) {
328 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
334 * If no short identifier was provided in the input payload, generate a
335 * short identifier from the preferred term display name or term name.
337 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel,
338 String schemaName) throws Exception {
339 String shortIdentifier = (String) docModel.getProperty(schemaName,
340 AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
342 String termDisplayName = getPrimaryDisplayName(
343 docModel, authorityItemCommonSchemaName,
344 getItemTermInfoGroupXPathBase(),
345 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
347 String termName = getPrimaryDisplayName(
348 docModel, authorityItemCommonSchemaName,
349 getItemTermInfoGroupXPathBase(),
350 AuthorityItemJAXBSchema.TERM_NAME);
352 if (Tools.isEmpty(shortIdentifier)) {
353 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName,
355 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER,
356 generatedShortIdentifier);
361 * Generate a refName for the authority item from the short identifier
364 * All refNames for authority items are generated. If a client supplies
365 * a refName, it will be overwritten during create (per this method)
366 * or discarded during update (per filterReadOnlyPropertiesForPart).
368 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
371 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
373 String authorityRefBaseName) throws Exception {
374 DocumentModel docModel = wrapDoc.getWrappedObject();
375 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
376 String displayName = getPrimaryDisplayName(docModel, authorityItemCommonSchemaName,
377 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
379 if (Tools.isEmpty(authorityRefBaseName)) {
380 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
383 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
384 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
385 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
389 * Check the logic around the parent pointer. Note that we only need do this on
390 * create, since we have logic to make this read-only on update.
394 * @throws Exception the exception
396 private void handleInAuthority(DocumentModel docModel) throws Exception {
397 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
398 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
400 docModel.setProperty(authorityItemCommonSchemaName,
401 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
405 public AuthorityRefDocList getReferencingObjects(
406 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
407 List<String> serviceTypes,
409 String itemcsid) throws Exception {
410 AuthorityRefDocList authRefDocList = null;
411 RepositoryInstance repoSession = null;
412 boolean releaseRepoSession = false;
415 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
416 repoSession = this.getRepositorySession();
417 if (repoSession == null) {
418 repoSession = repoClient.getRepositorySession();
419 releaseRepoSession = true;
421 DocumentFilter myFilter = getDocumentFilter();
424 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
425 DocumentModel docModel = wrapper.getWrappedObject();
426 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
427 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
428 repoSession, ctx, repoClient,
432 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
433 } catch (PropertyException pe) {
435 } catch (DocumentException de) {
437 } catch (Exception e) {
438 if (logger.isDebugEnabled()) {
439 logger.debug("Caught exception ", e);
441 throw new DocumentException(e);
443 if (releaseRepoSession && repoSession != null) {
444 repoClient.releaseRepositorySession(repoSession);
447 } catch (Exception e) {
448 if (logger.isDebugEnabled()) {
449 logger.debug("Caught exception ", e);
451 throw new DocumentException(e);
453 return authRefDocList;
460 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
463 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
465 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
467 // Add the CSID to the common part, since they may have fetched via the shortId.
468 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
469 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
470 unQObjectProperties.put("csid", csid);
473 return unQObjectProperties;
477 * Filters out selected values supplied in an update request.
479 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
480 * that the link to the item's parent remains untouched.
482 * @param objectProps the properties filtered out from the update payload
483 * @param partMeta metadata for the object to fill
486 public void filterReadOnlyPropertiesForPart(
487 Map<String, Object> objectProps, ObjectPartType partMeta) {
488 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
489 String commonPartLabel = getServiceContext().getCommonPartLabel();
490 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
491 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
492 objectProps.remove(AuthorityItemJAXBSchema.CSID);
493 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
494 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
499 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
500 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
501 super.extractAllParts(wrapDoc);
503 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
504 if (Tools.isTrue(showSiblings)) {
505 showSiblings(wrapDoc, ctx);
506 return; // actual result is returned on ctx.addOutputPart();
509 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
510 if (Tools.isTrue(showRelations)) {
511 showRelations(wrapDoc, ctx);
512 return; // actual result is returned on ctx.addOutputPart();
515 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
516 if (Tools.isTrue(showAllRelations)) {
517 showAllRelations(wrapDoc, ctx);
518 return; // actual result is returned on ctx.addOutputPart();
522 /** @return null on parent not found
524 protected String getParentCSID(String thisCSID) throws Exception {
525 String parentCSID = null;
527 String predicate = RelationshipType.HAS_BROADER.value();
528 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
529 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
530 if (parentList != null) {
531 if (parentList.size() == 0) {
534 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
535 parentCSID = relationListItem.getObjectCsid();
538 } catch (Exception e) {
539 logger.error("Could not find parent for this: " + thisCSID, e);
544 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
545 MultipartServiceContext ctx) throws Exception {
546 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
548 String predicate = RelationshipType.HAS_BROADER.value();
549 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
550 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
552 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
553 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
555 if(logger.isTraceEnabled()) {
556 String dump = dumpLists(thisCSID, parentList, childrenList, null);
557 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
560 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
561 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
562 //Not optimal, but that's the current design spec.
564 for (RelationsCommonList.RelationListItem parent : parentList) {
565 childrenList.add(parent);
568 long childrenSize = childrenList.size();
569 childrenListOuter.setTotalItems(childrenSize);
570 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
572 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
573 ctx.addOutputPart(relationsPart);
576 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
577 MultipartServiceContext ctx) throws Exception {
578 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
579 String parentCSID = getParentCSID(thisCSID);
580 if (parentCSID == null) {
581 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
585 String predicate = RelationshipType.HAS_BROADER.value();
586 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
587 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
589 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
592 RelationsCommonList.RelationListItem item = null;
593 for (RelationsCommonList.RelationListItem sibling : siblingList) {
594 if (thisCSID.equals(sibling.getSubjectCsid())) {
595 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.
598 //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.
599 for (RelationsCommonList.RelationListItem self : toRemoveList) {
600 removeFromList(siblingList, self);
603 long siblingSize = siblingList.size();
604 siblingListOuter.setTotalItems(siblingSize);
605 siblingListOuter.setItemsInPage(siblingSize);
606 if(logger.isTraceEnabled()) {
607 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
608 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
611 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
612 ctx.addOutputPart(relationsPart);
615 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
616 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
618 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
619 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
621 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
622 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
624 if(logger.isTraceEnabled()) {
625 String dump = dumpLists(thisCSID, subjectList, objectList, null);
626 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
629 subjectList.addAll(objectList);
631 //now subjectList actually has records BOTH where thisCSID is subject and object.
632 long relatedSize = subjectList.size();
633 subjectListOuter.setTotalItems(relatedSize);
634 subjectListOuter.setItemsInPage(relatedSize);
636 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
637 ctx.addOutputPart(relationsPart);
640 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
641 super.fillAllParts(wrapDoc, action);
643 ServiceContext ctx = getServiceContext();
644 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
645 DocumentModel documentModel = (wrapDoc.getWrappedObject());
646 String itemCsid = documentModel.getName();
648 //UPDATE and CREATE will call. Updates relations part
649 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
651 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
652 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
656 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
657 super.completeCreate(wrapDoc);
658 handleRelationsPayload(wrapDoc, false);
661 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
662 super.completeUpdate(wrapDoc);
663 handleRelationsPayload(wrapDoc, true);
664 handleItemRefNameReferenceUpdate();
667 // Note that we must do this after we have completed the Update, so that the repository has the
668 // info for the item itself. The relations code must call into the repo to get info for each end.
669 // This could be optimized to pass in the parent docModel, since it will often be one end.
670 // Nevertheless, we should complete the item save before we do work on the relations, especially
671 // since a save on Create might fail, and we would not want to create relations for something
672 // that may not be created...
673 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
674 ServiceContext ctx = getServiceContext();
675 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
676 DocumentModel documentModel = (wrapDoc.getWrappedObject());
677 String itemCsid = documentModel.getName();
679 //Updates relations part
680 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
682 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
683 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
685 //now we add part for relations list
686 //ServiceContext ctx = getServiceContext();
687 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
688 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
691 /** updateRelations strategy:
693 go through inboundList, remove anything from childList that matches from childList
694 go through inboundList, remove anything from parentList that matches from parentList
695 go through parentList, delete all remaining
696 go through childList, delete all remaining
697 go through actionList, add all remaining.
698 check for duplicate children
699 check for more than one parent.
701 inboundList parentList childList actionList
702 ---------------- --------------- ---------------- ----------------
703 child-a parent-c child-a child-b
704 child-b parent-d child-c
707 private RelationsCommonList updateRelations(
708 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
710 if (logger.isTraceEnabled()) {
711 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
713 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
715 return null; //nothing to do--they didn't send a list of relations.
717 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
718 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
719 List<RelationsCommonList.RelationListItem> actionList = newList();
720 List<RelationsCommonList.RelationListItem> childList = null;
721 List<RelationsCommonList.RelationListItem> parentList = null;
722 DocumentModel docModel = wrapDoc.getWrappedObject();
723 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
725 ServiceContext ctx = getServiceContext();
726 //Do magic replacement of ${itemCSID} and fix URI's.
727 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
729 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
730 UriInfo uriInfo = ctx.getUriInfo();
731 MultivaluedMap queryParams = uriInfo.getQueryParameters();
734 //Run getList() once as sent to get childListOuter:
735 String predicate = RelationshipType.HAS_BROADER.value();
736 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
737 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
738 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
739 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
740 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
741 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
743 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
744 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
745 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
746 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
747 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
750 childList = childListOuter.getRelationListItem();
751 parentList = parentListOuter.getRelationListItem();
753 if (parentList.size() > 1) {
754 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
757 if (logger.isTraceEnabled()) {
758 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
763 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
764 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
765 // and so the CSID for those may be null
766 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
767 // Look for parents and children
768 if(itemCSID.equals(inboundItem.getObject().getCsid())
769 || itemRefName.equals(inboundItem.getObject().getRefName())) {
770 //then this is an item that says we have a child. That child is inboundItem
771 RelationsCommonList.RelationListItem childItem =
772 (childList == null) ? null : findInList(childList, inboundItem);
773 if (childItem != null) {
774 if (logger.isTraceEnabled()) {
775 StringBuilder sb = new StringBuilder();
776 itemToString(sb, "== Child: ", childItem);
777 logger.trace("Found inboundChild in current child list: " + sb.toString());
779 removeFromList(childList, childItem); //exists, just take it off delete list
781 if (logger.isTraceEnabled()) {
782 StringBuilder sb = new StringBuilder();
783 itemToString(sb, "== Child: ", inboundItem);
784 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
786 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
787 String newChildCsid = inboundItem.getSubject().getCsid();
788 if(newChildCsid == null) {
789 String newChildRefName = inboundItem.getSubject().getRefName();
790 if(newChildRefName==null) {
791 throw new RuntimeException("Child with no CSID or refName!");
793 if (logger.isTraceEnabled()) {
794 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
796 DocumentModel newChildDocModel =
797 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
798 newChildRefName, getServiceContext().getResourceMap());
799 newChildCsid = getCsid(newChildDocModel);
801 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
804 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
805 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
806 //then this is an item that says we have a parent. inboundItem is that parent.
807 RelationsCommonList.RelationListItem parentItem =
808 (parentList == null) ? null : findInList(parentList, inboundItem);
809 if (parentItem != null) {
810 removeFromList(parentList, parentItem); //exists, just take it off delete list
812 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
815 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
818 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
821 if (logger.isTraceEnabled()) {
822 String dump = dumpLists(itemCSID, parentList, childList, actionList);
823 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
826 if (logger.isTraceEnabled()) {
827 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
828 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
830 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
831 deleteRelations(childList, ctx, "childList");
833 if (logger.isTraceEnabled()) {
834 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
835 + actionList.size() + " new parents and children.");
837 createRelations(actionList, ctx);
838 if (logger.isTraceEnabled()) {
839 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
841 //We return all elements on the inbound list, since we have just worked to make them exist in the system
842 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
843 return relationsCommonListBody;
846 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
847 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
848 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
849 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
850 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
851 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
852 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
853 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
854 deleteRelations(parentList, ctx, "parentList-delete");
858 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
860 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
862 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
864 sb.append(item.getPredicate());
866 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
870 private String dumpLists(String itemCSID,
871 List<RelationsCommonList.RelationListItem> parentList,
872 List<RelationsCommonList.RelationListItem> childList,
873 List<RelationsCommonList.RelationListItem> actionList) {
874 StringBuilder sb = new StringBuilder();
875 sb.append("itemCSID: " + itemCSID + CR);
876 if(parentList!=null) {
877 sb.append(dumpList(parentList, "parentList"));
879 if(childList!=null) {
880 sb.append(dumpList(childList, "childList"));
882 if(actionList!=null) {
883 sb.append(dumpList(actionList, "actionList"));
885 return sb.toString();
887 private final static String CR = "\r\n";
888 private final static String T = " ";
890 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
891 StringBuilder sb = new StringBuilder();
893 if (list.size() > 0) {
894 sb.append("=========== " + label + " ==========" + CR);
896 for (RelationsCommonList.RelationListItem item : list) {
897 itemToString(sb, "== ", item);
900 return sb.toString();
903 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
904 * and sets URI correctly for related items.
905 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
907 protected void fixupInboundListItems(ServiceContext ctx,
908 List<RelationsCommonList.RelationListItem> inboundList,
909 DocumentModel docModel,
910 String itemCSID) throws Exception {
911 String thisURI = this.getUri(docModel);
912 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
913 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
914 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
915 RelationsDocListItem inboundItemObject = inboundItem.getObject();
916 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
918 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
919 inboundItem.setObjectCsid(itemCSID);
920 inboundItemObject.setCsid(itemCSID);
921 //inboundItemObject.setUri(getUri(docModel));
924 String objectCsid = inboundItemObject.getCsid();
925 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
926 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
927 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
928 inboundItemObject.setUri(uri); //CSPACE-4037
931 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
933 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
934 inboundItem.setSubjectCsid(itemCSID);
935 inboundItemSubject.setCsid(itemCSID);
936 //inboundItemSubject.setUri(getUri(docModel));
939 String subjectCsid = inboundItemSubject.getCsid();
940 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
941 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
942 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
943 inboundItemSubject.setUri(uri); //CSPACE-4037
946 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
951 // this method calls the RelationResource to have it create the relations and persist them.
952 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
953 for (RelationsCommonList.RelationListItem item : inboundList) {
954 RelationsCommon rc = new RelationsCommon();
955 //rc.setCsid(item.getCsid());
956 //todo: assignTo(item, rc);
957 RelationsDocListItem itemSubject = item.getSubject();
958 RelationsDocListItem itemObject = item.getObject();
960 // Set at least one of CSID and refName for Subject and Object
961 // Either value might be null for for each of Subject and Object
962 String subjectCsid = itemSubject.getCsid();
963 rc.setSubjectCsid(subjectCsid);
965 String objCsid = itemObject.getCsid();
966 rc.setObjectCsid(objCsid);
968 rc.setSubjectRefName(itemSubject.getRefName());
969 rc.setObjectRefName(itemObject.getRefName());
971 rc.setRelationshipType(item.getPredicate());
972 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
973 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
975 // This is superfluous, since it will be fetched by the Relations Create logic.
976 rc.setSubjectDocumentType(itemSubject.getDocumentType());
977 rc.setObjectDocumentType(itemObject.getDocumentType());
979 // This is superfluous, since it will be fetched by the Relations Create logic.
980 rc.setSubjectUri(itemSubject.getUri());
981 rc.setObjectUri(itemObject.getUri());
982 // May not have the info here. Only really require CSID or refName.
983 // Rest is handled in the Relation create mechanism
984 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
986 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
987 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
988 payloadOut.addPart(outputPart);
989 RelationResource relationResource = new RelationResource();
990 Object res = relationResource.create(ctx.getResourceMap(),
991 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
995 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
997 for (RelationsCommonList.RelationListItem item : list) {
998 RelationResource relationResource = new RelationResource();
999 if(logger.isTraceEnabled()) {
1000 StringBuilder sb = new StringBuilder();
1001 itemToString(sb, "==== TO DELETE: ", item);
1002 logger.trace(sb.toString());
1004 Object res = relationResource.delete(item.getCsid());
1006 } catch (Throwable t) {
1007 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1012 private List<RelationsCommonList.RelationListItem> newList() {
1013 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1017 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1018 List<RelationsCommonList.RelationListItem> result = newList();
1019 for (RelationsCommonList.RelationListItem item : inboundList) {
1025 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1026 // But the list items must not be sparse
1027 private RelationsCommonList.RelationListItem findInList(
1028 List<RelationsCommonList.RelationListItem> list,
1029 RelationsCommonList.RelationListItem item) {
1030 RelationsCommonList.RelationListItem foundItem = null;
1031 for (RelationsCommonList.RelationListItem listItem : list) {
1032 if (itemsEqual(listItem, item)) { //equals must be defined, else
1033 foundItem = listItem;
1040 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1041 // But item1 must not be sparse
1042 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1043 if (item1 == null || item2 == null) {
1046 RelationsDocListItem subj1 = item1.getSubject();
1047 RelationsDocListItem subj2 = item2.getSubject();
1048 RelationsDocListItem obj1 = item1.getObject();
1049 RelationsDocListItem obj2 = item2.getObject();
1050 String subj1Csid = subj1.getCsid();
1051 String subj2Csid = subj2.getCsid();
1052 String subj1RefName = subj1.getRefName();
1053 String subj2RefName = subj2.getRefName();
1055 String obj1Csid = obj1.getCsid();
1056 String obj2Csid = obj2.getCsid();
1057 String obj1RefName = obj1.getRefName();
1058 String obj2RefName = obj2.getRefName();
1061 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1062 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1063 // predicate is proper, but still allow relationshipType
1064 && (item1.getPredicate().equals(item2.getPredicate())
1065 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1066 // Allow missing docTypes, so long as they do not conflict
1067 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1068 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1072 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1076 /* don't even THINK of re-using this method.
1077 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1079 private String extractInAuthorityCSID(String uri) {
1080 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1081 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1082 Matcher m = p.matcher(uri);
1084 if (m.groupCount() < 3) {
1085 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1088 //String service = m.group(1);
1089 String inauth = m.group(2);
1090 //String theRest = m.group(3);
1092 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1095 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1100 //ensures CSPACE-4042
1101 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1102 String authorityCSID = extractInAuthorityCSID(thisURI);
1103 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1104 if (Tools.isBlank(authorityCSID)
1105 || Tools.isBlank(authorityCSIDForInbound)
1106 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1107 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1111 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1112 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1113 ServiceContext ctx = getServiceContext();
1114 MultivaluedMap queryParams = ctx.getQueryParams();
1115 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1116 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1117 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1119 RelationResource relationResource = new RelationResource();
1120 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1121 return relationsCommonList;
1123 //============================= END TODO refactor ==========================
1125 public String getItemTermInfoGroupXPathBase() {
1126 return this.authorityItemTermGroupXPathBase;
1129 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1130 this.authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;
1133 protected String getAuthorityItemCommonSchemaName() {
1134 return authorityItemCommonSchemaName;