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 some common fields so do not depend upon config for general logic
148 boolean hasDisplayName = false;
149 boolean hasShortId = false;
150 boolean hasRefName = false;
151 boolean hasTermStatus = false;
152 for (int i = 0; i < nFields; i++) {
153 ListResultField field = list.get(i);
154 String elName = field.getElement();
155 if (AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName)) {
156 hasDisplayName = true;
157 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
159 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
161 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
162 hasTermStatus = true;
165 ListResultField field;
166 if (!hasDisplayName) {
167 field = new ListResultField();
168 field.setElement(AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
169 field.setXpath(AuthorityItemJAXBSchema.DISPLAY_NAME);
173 field = new ListResultField();
174 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
175 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
179 field = new ListResultField();
180 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
181 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
184 if (!hasTermStatus) {
185 field = new ListResultField();
186 field.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
187 field.setXpath(AuthorityItemJAXBSchema.TERM_STATUS);
196 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
199 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
200 // first fill all the parts of the document
201 super.handleCreate(wrapDoc);
202 // Ensure we have required fields set properly
203 handleInAuthority(wrapDoc.getWrappedObject());
207 handleComputedDisplayNames(wrapDoc.getWrappedObject());
208 String displayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
209 AuthorityItemJAXBSchema.DISPLAY_NAME);
210 if (Tools.isEmpty(displayName)) {
211 logger.warn("Creating Authority Item with no displayName!");
216 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
217 // refName includes displayName, so we force a correct value here.
218 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
222 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
225 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
226 // First, get a copy of the old displayName
227 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
228 // AuthorityItemJAXBSchema.DISPLAY_NAME);
229 oldDisplayNameOnUpdate = (String) getStringValueInPrimaryRepeatingComplexProperty(
230 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
231 this.authorityItemTermGroupXPathBase,
232 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
233 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
234 AuthorityItemJAXBSchema.REF_NAME);
235 super.handleUpdate(wrapDoc);
236 // handleComputedDisplayNames(wrapDoc.getWrappedObject());
237 // String newDisplayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
238 // AuthorityItemJAXBSchema.DISPLAY_NAME);
239 String newDisplayName = (String) getStringValueInPrimaryRepeatingComplexProperty(
240 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
241 this.authorityItemTermGroupXPathBase,
242 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
243 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
244 // Need to update the refName, and then fix all references.
245 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
247 // Mark as not needing attention in completeUpdate phase.
248 newRefNameOnUpdate = null;
249 oldRefNameOnUpdate = null;
254 * Handle display name.
256 * @param docModel the doc model
257 * @throws Exception the exception
259 protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
260 // Do nothing by default.
264 * Handle refName updates for changes to display name.
265 * Assumes refName is already correct. Just ensures it is right.
267 * @param docModel the doc model
268 * @param newDisplayName the new display name
269 * @throws Exception the exception
271 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
272 String newDisplayName) throws Exception {
273 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
274 if (authItem == null) {
275 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
277 throw new IllegalArgumentException(err);
279 authItem.displayName = newDisplayName;
280 String updatedRefName = authItem.toString();
281 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
282 return updatedRefName;
285 protected String getRefPropName() {
286 return ServiceBindingUtils.AUTH_REF_PROP;
290 * Checks to see if the refName has changed, and if so,
291 * uses utilities to find all references and update them.
294 protected void handleItemRefNameReferenceUpdate() throws Exception {
295 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
296 // We have work to do.
297 if (logger.isDebugEnabled()) {
298 String eol = System.getProperty("line.separator");
299 logger.debug("Need to find and update references to Item." + eol
300 + " Old refName" + oldRefNameOnUpdate + eol
301 + " New refName" + newRefNameOnUpdate);
303 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
304 RepositoryClient repoClient = getRepositoryClient(ctx);
305 String refNameProp = getRefPropName();
307 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
308 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
309 if (logger.isDebugEnabled()) {
310 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
316 * If no short identifier was provided in the input payload, generate a
317 * short identifier from the preferred term display name or term name.
319 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
320 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
321 String termDisplayName =
322 (String) getStringValueInPrimaryRepeatingComplexProperty(
323 docModel, authorityItemCommonSchemaName,
324 this.authorityItemTermGroupXPathBase,
325 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
327 (String) getStringValueInPrimaryRepeatingComplexProperty(
328 docModel, authorityItemCommonSchemaName,
329 this.authorityItemTermGroupXPathBase,
330 AuthorityItemJAXBSchema.TERM_NAME);
331 if (Tools.isEmpty(shortIdentifier)) {
332 String generatedShortIdentifier =
333 AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName, termName);
334 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER, generatedShortIdentifier);
339 * Generate a refName for the authority item from the short identifier
342 * All refNames for authority items are generated. If a client supplies
343 * a refName, it will be overwritten during create (per this method)
344 * or discarded during update (per filterReadOnlyPropertiesForPart).
346 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
349 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
351 String authorityRefBaseName) throws Exception {
352 DocumentModel docModel = wrapDoc.getWrappedObject();
353 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
355 (String) getStringValueInPrimaryRepeatingComplexProperty(
356 docModel, authorityItemCommonSchemaName,
357 this.authorityItemTermGroupXPathBase,
358 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
359 if (Tools.isEmpty(authorityRefBaseName)) {
360 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
362 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
363 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
364 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
368 * Check the logic around the parent pointer. Note that we only need do this on
369 * create, since we have logic to make this read-only on update.
373 * @throws Exception the exception
375 private void handleInAuthority(DocumentModel docModel) throws Exception {
376 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
377 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
379 docModel.setProperty(authorityItemCommonSchemaName,
380 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
384 public AuthorityRefDocList getReferencingObjects(
385 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
386 List<String> serviceTypes,
388 String itemcsid) throws Exception {
389 AuthorityRefDocList authRefDocList = null;
390 RepositoryInstance repoSession = null;
391 boolean releaseRepoSession = false;
394 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
395 repoSession = this.getRepositorySession();
396 if (repoSession == null) {
397 repoSession = repoClient.getRepositorySession();
398 releaseRepoSession = true;
400 DocumentFilter myFilter = getDocumentFilter();
403 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
404 DocumentModel docModel = wrapper.getWrappedObject();
405 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
406 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
407 repoSession, ctx, repoClient,
411 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
412 } catch (PropertyException pe) {
414 } catch (DocumentException de) {
416 } catch (Exception e) {
417 if (logger.isDebugEnabled()) {
418 logger.debug("Caught exception ", e);
420 throw new DocumentException(e);
422 if (releaseRepoSession && repoSession != null) {
423 repoClient.releaseRepositorySession(repoSession);
426 } catch (Exception e) {
427 if (logger.isDebugEnabled()) {
428 logger.debug("Caught exception ", e);
430 throw new DocumentException(e);
432 return authRefDocList;
439 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
442 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
444 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
446 // Add the CSID to the common part, since they may have fetched via the shortId.
447 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
448 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
449 unQObjectProperties.put("csid", csid);
452 return unQObjectProperties;
456 * Filters out selected values supplied in an update request.
458 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
459 * that the link to the item's parent remains untouched.
461 * @param objectProps the properties filtered out from the update payload
462 * @param partMeta metadata for the object to fill
465 public void filterReadOnlyPropertiesForPart(
466 Map<String, Object> objectProps, ObjectPartType partMeta) {
467 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
468 String commonPartLabel = getServiceContext().getCommonPartLabel();
469 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
470 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
471 objectProps.remove(AuthorityItemJAXBSchema.CSID);
472 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
473 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
478 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
479 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
480 super.extractAllParts(wrapDoc);
482 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
483 if (Tools.isTrue(showSiblings)) {
484 showSiblings(wrapDoc, ctx);
485 return; // actual result is returned on ctx.addOutputPart();
488 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
489 if (Tools.isTrue(showRelations)) {
490 showRelations(wrapDoc, ctx);
491 return; // actual result is returned on ctx.addOutputPart();
494 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
495 if (Tools.isTrue(showAllRelations)) {
496 showAllRelations(wrapDoc, ctx);
497 return; // actual result is returned on ctx.addOutputPart();
501 /** @return null on parent not found
503 protected String getParentCSID(String thisCSID) throws Exception {
504 String parentCSID = null;
506 String predicate = RelationshipType.HAS_BROADER.value();
507 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
508 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
509 if (parentList != null) {
510 if (parentList.size() == 0) {
513 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
514 parentCSID = relationListItem.getObjectCsid();
517 } catch (Exception e) {
518 logger.error("Could not find parent for this: " + thisCSID, e);
523 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
524 MultipartServiceContext ctx) throws Exception {
525 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
527 String predicate = RelationshipType.HAS_BROADER.value();
528 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
529 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
531 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
532 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
534 if(logger.isTraceEnabled()) {
535 String dump = dumpLists(thisCSID, parentList, childrenList, null);
536 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
539 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
540 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
541 //Not optimal, but that's the current design spec.
543 for (RelationsCommonList.RelationListItem parent : parentList) {
544 childrenList.add(parent);
547 long childrenSize = childrenList.size();
548 childrenListOuter.setTotalItems(childrenSize);
549 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
551 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
552 ctx.addOutputPart(relationsPart);
555 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
556 MultipartServiceContext ctx) throws Exception {
557 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
558 String parentCSID = getParentCSID(thisCSID);
559 if (parentCSID == null) {
560 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
564 String predicate = RelationshipType.HAS_BROADER.value();
565 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
566 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
568 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
571 RelationsCommonList.RelationListItem item = null;
572 for (RelationsCommonList.RelationListItem sibling : siblingList) {
573 if (thisCSID.equals(sibling.getSubjectCsid())) {
574 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.
577 //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.
578 for (RelationsCommonList.RelationListItem self : toRemoveList) {
579 removeFromList(siblingList, self);
582 long siblingSize = siblingList.size();
583 siblingListOuter.setTotalItems(siblingSize);
584 siblingListOuter.setItemsInPage(siblingSize);
585 if(logger.isTraceEnabled()) {
586 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
587 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
590 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
591 ctx.addOutputPart(relationsPart);
594 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
595 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
597 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
598 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
600 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
601 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
603 if(logger.isTraceEnabled()) {
604 String dump = dumpLists(thisCSID, subjectList, objectList, null);
605 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
608 subjectList.addAll(objectList);
610 //now subjectList actually has records BOTH where thisCSID is subject and object.
611 long relatedSize = subjectList.size();
612 subjectListOuter.setTotalItems(relatedSize);
613 subjectListOuter.setItemsInPage(relatedSize);
615 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
616 ctx.addOutputPart(relationsPart);
619 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
620 super.fillAllParts(wrapDoc, action);
622 ServiceContext ctx = getServiceContext();
623 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
624 DocumentModel documentModel = (wrapDoc.getWrappedObject());
625 String itemCsid = documentModel.getName();
627 //UPDATE and CREATE will call. Updates relations part
628 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
630 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
631 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
635 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
636 super.completeCreate(wrapDoc);
637 handleRelationsPayload(wrapDoc, false);
640 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
641 super.completeUpdate(wrapDoc);
642 handleRelationsPayload(wrapDoc, true);
643 handleItemRefNameReferenceUpdate();
646 // Note that we must do this after we have completed the Update, so that the repository has the
647 // info for the item itself. The relations code must call into the repo to get info for each end.
648 // This could be optimized to pass in the parent docModel, since it will often be one end.
649 // Nevertheless, we should complete the item save before we do work on the relations, especially
650 // since a save on Create might fail, and we would not want to create relations for something
651 // that may not be created...
652 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
653 ServiceContext ctx = getServiceContext();
654 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
655 DocumentModel documentModel = (wrapDoc.getWrappedObject());
656 String itemCsid = documentModel.getName();
658 //Updates relations part
659 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
661 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
662 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
664 //now we add part for relations list
665 //ServiceContext ctx = getServiceContext();
666 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
667 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
670 /** updateRelations strategy:
672 go through inboundList, remove anything from childList that matches from childList
673 go through inboundList, remove anything from parentList that matches from parentList
674 go through parentList, delete all remaining
675 go through childList, delete all remaining
676 go through actionList, add all remaining.
677 check for duplicate children
678 check for more than one parent.
680 inboundList parentList childList actionList
681 ---------------- --------------- ---------------- ----------------
682 child-a parent-c child-a child-b
683 child-b parent-d child-c
686 private RelationsCommonList updateRelations(
687 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
689 if (logger.isTraceEnabled()) {
690 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
692 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
694 return null; //nothing to do--they didn't send a list of relations.
696 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
697 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
698 List<RelationsCommonList.RelationListItem> actionList = newList();
699 List<RelationsCommonList.RelationListItem> childList = null;
700 List<RelationsCommonList.RelationListItem> parentList = null;
701 DocumentModel docModel = wrapDoc.getWrappedObject();
702 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
704 ServiceContext ctx = getServiceContext();
705 //Do magic replacement of ${itemCSID} and fix URI's.
706 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
708 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
709 UriInfo uriInfo = ctx.getUriInfo();
710 MultivaluedMap queryParams = uriInfo.getQueryParameters();
713 //Run getList() once as sent to get childListOuter:
714 String predicate = RelationshipType.HAS_BROADER.value();
715 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
716 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
717 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
718 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
719 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
720 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
722 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
723 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
724 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
725 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
726 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
729 childList = childListOuter.getRelationListItem();
730 parentList = parentListOuter.getRelationListItem();
732 if (parentList.size() > 1) {
733 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
736 if (logger.isTraceEnabled()) {
737 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
742 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
743 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
744 // and so the CSID for those may be null
745 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
746 // Look for parents and children
747 if(itemCSID.equals(inboundItem.getObject().getCsid())
748 || itemRefName.equals(inboundItem.getObject().getRefName())) {
749 //then this is an item that says we have a child. That child is inboundItem
750 RelationsCommonList.RelationListItem childItem =
751 (childList == null) ? null : findInList(childList, inboundItem);
752 if (childItem != null) {
753 if (logger.isTraceEnabled()) {
754 StringBuilder sb = new StringBuilder();
755 itemToString(sb, "== Child: ", childItem);
756 logger.trace("Found inboundChild in current child list: " + sb.toString());
758 removeFromList(childList, childItem); //exists, just take it off delete list
760 if (logger.isTraceEnabled()) {
761 StringBuilder sb = new StringBuilder();
762 itemToString(sb, "== Child: ", inboundItem);
763 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
765 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
766 String newChildCsid = inboundItem.getSubject().getCsid();
767 if(newChildCsid == null) {
768 String newChildRefName = inboundItem.getSubject().getRefName();
769 if(newChildRefName==null) {
770 throw new RuntimeException("Child with no CSID or refName!");
772 if (logger.isTraceEnabled()) {
773 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
775 DocumentModel newChildDocModel =
776 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
777 newChildRefName, getServiceContext().getResourceMap());
778 newChildCsid = getCsid(newChildDocModel);
780 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
783 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
784 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
785 //then this is an item that says we have a parent. inboundItem is that parent.
786 RelationsCommonList.RelationListItem parentItem =
787 (parentList == null) ? null : findInList(parentList, inboundItem);
788 if (parentItem != null) {
789 removeFromList(parentList, parentItem); //exists, just take it off delete list
791 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
794 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
797 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
800 if (logger.isTraceEnabled()) {
801 String dump = dumpLists(itemCSID, parentList, childList, actionList);
802 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
805 if (logger.isTraceEnabled()) {
806 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
807 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
809 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
810 deleteRelations(childList, ctx, "childList");
812 if (logger.isTraceEnabled()) {
813 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
814 + actionList.size() + " new parents and children.");
816 createRelations(actionList, ctx);
817 if (logger.isTraceEnabled()) {
818 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
820 //We return all elements on the inbound list, since we have just worked to make them exist in the system
821 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
822 return relationsCommonListBody;
825 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
826 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
827 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
828 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
829 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
830 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
831 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
832 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
833 deleteRelations(parentList, ctx, "parentList-delete");
837 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
839 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
841 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
843 sb.append(item.getPredicate());
845 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
849 private String dumpLists(String itemCSID,
850 List<RelationsCommonList.RelationListItem> parentList,
851 List<RelationsCommonList.RelationListItem> childList,
852 List<RelationsCommonList.RelationListItem> actionList) {
853 StringBuilder sb = new StringBuilder();
854 sb.append("itemCSID: " + itemCSID + CR);
855 if(parentList!=null) {
856 sb.append(dumpList(parentList, "parentList"));
858 if(childList!=null) {
859 sb.append(dumpList(childList, "childList"));
861 if(actionList!=null) {
862 sb.append(dumpList(actionList, "actionList"));
864 return sb.toString();
866 private final static String CR = "\r\n";
867 private final static String T = " ";
869 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
870 StringBuilder sb = new StringBuilder();
872 if (list.size() > 0) {
873 sb.append("=========== " + label + " ==========" + CR);
875 for (RelationsCommonList.RelationListItem item : list) {
876 itemToString(sb, "== ", item);
879 return sb.toString();
882 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
883 * and sets URI correctly for related items.
884 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
886 protected void fixupInboundListItems(ServiceContext ctx,
887 List<RelationsCommonList.RelationListItem> inboundList,
888 DocumentModel docModel,
889 String itemCSID) throws Exception {
890 String thisURI = this.getUri(docModel);
891 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
892 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
893 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
894 RelationsDocListItem inboundItemObject = inboundItem.getObject();
895 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
897 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
898 inboundItem.setObjectCsid(itemCSID);
899 inboundItemObject.setCsid(itemCSID);
900 //inboundItemObject.setUri(getUri(docModel));
903 String objectCsid = inboundItemObject.getCsid();
904 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
905 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
906 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
907 inboundItemObject.setUri(uri); //CSPACE-4037
910 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
912 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
913 inboundItem.setSubjectCsid(itemCSID);
914 inboundItemSubject.setCsid(itemCSID);
915 //inboundItemSubject.setUri(getUri(docModel));
918 String subjectCsid = inboundItemSubject.getCsid();
919 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
920 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
921 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
922 inboundItemSubject.setUri(uri); //CSPACE-4037
925 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
930 // this method calls the RelationResource to have it create the relations and persist them.
931 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
932 for (RelationsCommonList.RelationListItem item : inboundList) {
933 RelationsCommon rc = new RelationsCommon();
934 //rc.setCsid(item.getCsid());
935 //todo: assignTo(item, rc);
936 RelationsDocListItem itemSubject = item.getSubject();
937 RelationsDocListItem itemObject = item.getObject();
939 // Set at least one of CSID and refName for Subject and Object
940 // Either value might be null for for each of Subject and Object
941 String subjectCsid = itemSubject.getCsid();
942 rc.setSubjectCsid(subjectCsid);
944 String objCsid = itemObject.getCsid();
945 rc.setObjectCsid(objCsid);
947 rc.setSubjectRefName(itemSubject.getRefName());
948 rc.setObjectRefName(itemObject.getRefName());
950 rc.setRelationshipType(item.getPredicate());
951 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
952 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
954 // This is superfluous, since it will be fetched by the Relations Create logic.
955 rc.setSubjectDocumentType(itemSubject.getDocumentType());
956 rc.setObjectDocumentType(itemObject.getDocumentType());
958 // This is superfluous, since it will be fetched by the Relations Create logic.
959 rc.setSubjectUri(itemSubject.getUri());
960 rc.setObjectUri(itemObject.getUri());
961 // May not have the info here. Only really require CSID or refName.
962 // Rest is handled in the Relation create mechanism
963 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
965 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
966 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
967 payloadOut.addPart(outputPart);
968 RelationResource relationResource = new RelationResource();
969 Object res = relationResource.create(ctx.getResourceMap(),
970 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
974 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
976 for (RelationsCommonList.RelationListItem item : list) {
977 RelationResource relationResource = new RelationResource();
978 if(logger.isTraceEnabled()) {
979 StringBuilder sb = new StringBuilder();
980 itemToString(sb, "==== TO DELETE: ", item);
981 logger.trace(sb.toString());
983 Object res = relationResource.delete(item.getCsid());
985 } catch (Throwable t) {
986 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
991 private List<RelationsCommonList.RelationListItem> newList() {
992 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
996 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
997 List<RelationsCommonList.RelationListItem> result = newList();
998 for (RelationsCommonList.RelationListItem item : inboundList) {
1004 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1005 // But the list items must not be sparse
1006 private RelationsCommonList.RelationListItem findInList(
1007 List<RelationsCommonList.RelationListItem> list,
1008 RelationsCommonList.RelationListItem item) {
1009 RelationsCommonList.RelationListItem foundItem = null;
1010 for (RelationsCommonList.RelationListItem listItem : list) {
1011 if (itemsEqual(listItem, item)) { //equals must be defined, else
1012 foundItem = listItem;
1019 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1020 // But item1 must not be sparse
1021 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1022 if (item1 == null || item2 == null) {
1025 RelationsDocListItem subj1 = item1.getSubject();
1026 RelationsDocListItem subj2 = item2.getSubject();
1027 RelationsDocListItem obj1 = item1.getObject();
1028 RelationsDocListItem obj2 = item2.getObject();
1029 String subj1Csid = subj1.getCsid();
1030 String subj2Csid = subj2.getCsid();
1031 String subj1RefName = subj1.getRefName();
1032 String subj2RefName = subj2.getRefName();
1034 String obj1Csid = obj1.getCsid();
1035 String obj2Csid = obj2.getCsid();
1036 String obj1RefName = obj1.getRefName();
1037 String obj2RefName = obj2.getRefName();
1040 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1041 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1042 // predicate is proper, but still allow relationshipType
1043 && (item1.getPredicate().equals(item2.getPredicate())
1044 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1045 // Allow missing docTypes, so long as they do not conflict
1046 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1047 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1051 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1055 /* don't even THINK of re-using this method.
1056 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1058 private String extractInAuthorityCSID(String uri) {
1059 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1060 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1061 Matcher m = p.matcher(uri);
1063 if (m.groupCount() < 3) {
1064 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1067 //String service = m.group(1);
1068 String inauth = m.group(2);
1069 //String theRest = m.group(3);
1071 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1074 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1079 //ensures CSPACE-4042
1080 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1081 String authorityCSID = extractInAuthorityCSID(thisURI);
1082 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1083 if (Tools.isBlank(authorityCSID)
1084 || Tools.isBlank(authorityCSIDForInbound)
1085 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1086 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1090 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1091 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1092 ServiceContext ctx = getServiceContext();
1093 MultivaluedMap queryParams = ctx.getQueryParams();
1094 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1095 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1096 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1098 RelationResource relationResource = new RelationResource();
1099 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1100 return relationsCommonList;
1102 //============================= END TODO refactor ==========================
1104 public String getItemTermInfoGroupXPathBase() {
1105 return this.authorityItemTermGroupXPathBase;
1108 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1109 this.authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;