2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common.vocabulary.nuxeo;
26 import org.collectionspace.services.client.AuthorityClient;
27 import org.collectionspace.services.client.PayloadInputPart;
28 import org.collectionspace.services.client.PayloadOutputPart;
29 import org.collectionspace.services.client.PoxPayloadIn;
30 import org.collectionspace.services.client.PoxPayloadOut;
31 import org.collectionspace.services.client.RelationClient;
32 import org.collectionspace.services.common.ResourceBase;
33 import org.collectionspace.services.common.ServiceMessages;
34 import org.collectionspace.services.common.api.CommonAPI;
35 import org.collectionspace.services.common.api.RefName;
36 import org.collectionspace.services.common.api.Tools;
37 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
38 import org.collectionspace.services.common.context.MultipartServiceContext;
39 import org.collectionspace.services.common.context.ServiceBindingUtils;
40 import org.collectionspace.services.common.context.ServiceContext;
41 import org.collectionspace.services.common.document.DocumentException;
42 import org.collectionspace.services.common.document.DocumentFilter;
43 import org.collectionspace.services.common.document.DocumentWrapper;
44 import org.collectionspace.services.common.document.DocumentWrapperImpl;
45 import org.collectionspace.services.common.relation.IRelationsManager;
46 import org.collectionspace.services.common.repository.RepositoryClient;
47 import org.collectionspace.services.common.repository.RepositoryClientFactory;
48 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
49 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
50 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils;
51 import org.collectionspace.services.config.service.ListResultField;
52 import org.collectionspace.services.config.service.ObjectPartType;
53 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
54 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
55 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
56 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
57 import org.collectionspace.services.relation.RelationResource;
58 import org.collectionspace.services.relation.RelationsCommon;
59 import org.collectionspace.services.relation.RelationsCommonList;
60 import org.collectionspace.services.relation.RelationsDocListItem;
61 import org.collectionspace.services.relation.RelationshipType;
62 import org.nuxeo.ecm.core.api.ClientException;
63 import org.nuxeo.ecm.core.api.DocumentModel;
64 import org.nuxeo.ecm.core.api.model.PropertyException;
65 import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
66 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
67 import org.nuxeo.runtime.transaction.TransactionHelper;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
71 import javax.ws.rs.PathParam;
72 import javax.ws.rs.WebApplicationException;
73 import javax.ws.rs.core.Context;
74 import javax.ws.rs.core.MultivaluedMap;
75 import javax.ws.rs.core.Response;
76 import javax.ws.rs.core.UriInfo;
77 import java.util.ArrayList;
78 import java.util.List;
80 import java.util.regex.Matcher;
81 import java.util.regex.Pattern;
82 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
84 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
86 * AuthorityItemDocumentModelHandler
88 * $LastChangedRevision: $
91 public abstract class AuthorityItemDocumentModelHandler<AICommon>
92 extends DocHandlerBase<AICommon> {
94 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
95 private String authorityItemCommonSchemaName;
96 private String authorityItemTermGroupXPathBase;
98 * inVocabulary is the parent Authority for this context
100 protected String inAuthority = null;
101 protected String authorityRefNameBase = null;
102 // Used to determine when the displayName changes as part of the update.
103 protected String oldDisplayNameOnUpdate = null;
104 protected String oldRefNameOnUpdate = null;
105 protected String newRefNameOnUpdate = null;
107 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
108 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
111 public void setInAuthority(String inAuthority) {
112 this.inAuthority = inAuthority;
115 /** Subclasses may override this to customize the URI segment. */
116 public String getAuthorityServicePath() {
117 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
121 public String getUri(DocumentModel docModel) {
122 // Laramie20110510 CSPACE-3932
123 String authorityServicePath = getAuthorityServicePath();
124 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
126 inAuthority = (String) docModel.getProperty(authorityItemCommonSchemaName,
127 AuthorityItemJAXBSchema.IN_AUTHORITY);
128 } catch (ClientException pe) {
129 throw new RuntimeException("Could not get parent specifier for item!");
132 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
135 protected String getAuthorityRefNameBase() {
136 return this.authorityRefNameBase;
139 public void setAuthorityRefNameBase(String value) {
140 this.authorityRefNameBase = value;
144 public List<ListResultField> getListItemsArray() throws DocumentException {
145 List<ListResultField> list = super.getListItemsArray();
146 int nFields = list.size();
147 // Ensure that each item in a list of Authority items includes
148 // a set of common fields, so we do not depend upon configuration
149 // for general logic.
150 boolean hasDisplayName = false;
151 boolean hasShortId = false;
152 boolean hasRefName = false;
153 boolean hasTermStatus = false;
154 for (int i = 0; i < nFields; i++) {
155 ListResultField field = list.get(i);
156 String elName = field.getElement();
157 if (AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName)) {
158 hasDisplayName = true;
159 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
161 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
163 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
164 hasTermStatus = true;
167 ListResultField field;
168 if (!hasDisplayName) {
169 field = new ListResultField();
170 field.setElement(AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
171 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
172 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
176 field = new ListResultField();
177 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
178 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
182 field = new ListResultField();
183 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
184 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
187 if (!hasTermStatus) {
188 field = new ListResultField();
189 field.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
190 field.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
191 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
200 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
203 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
204 // first fill all the parts of the document
205 super.handleCreate(wrapDoc);
206 // Ensure we have required fields set properly
207 handleInAuthority(wrapDoc.getWrappedObject());
211 handleComputedDisplayNames(wrapDoc.getWrappedObject());
212 String displayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
213 AuthorityItemJAXBSchema.DISPLAY_NAME);
214 if (Tools.isEmpty(displayName)) {
215 logger.warn("Creating Authority Item with no displayName!");
221 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
222 // refName includes displayName, so we force a correct value here.
223 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
227 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
230 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
231 // First, get a copy of the old displayName
232 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
233 // AuthorityItemJAXBSchema.DISPLAY_NAME);
234 oldDisplayNameOnUpdate = (String) getStringValueInPrimaryRepeatingComplexProperty(
235 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
236 getItemTermInfoGroupXPathBase(),
237 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
238 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
239 AuthorityItemJAXBSchema.REF_NAME);
240 super.handleUpdate(wrapDoc);
241 // handleComputedDisplayNames(wrapDoc.getWrappedObject());
242 // String newDisplayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
243 // AuthorityItemJAXBSchema.DISPLAY_NAME);
244 String newDisplayName = (String) getStringValueInPrimaryRepeatingComplexProperty(
245 wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
246 this.authorityItemTermGroupXPathBase,
247 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
248 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
249 // Need to update the refName, and then fix all references.
250 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
252 // Mark as not needing attention in completeUpdate phase.
253 newRefNameOnUpdate = null;
254 oldRefNameOnUpdate = null;
259 * Handle display name.
261 * @param docModel the doc model
262 * @throws Exception the exception
264 protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
265 // Do nothing by default.
269 * Handle refName updates for changes to display name.
270 * Assumes refName is already correct. Just ensures it is right.
272 * @param docModel the doc model
273 * @param newDisplayName the new display name
274 * @throws Exception the exception
276 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
277 String newDisplayName) throws Exception {
278 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
279 if (authItem == null) {
280 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
282 throw new IllegalArgumentException(err);
284 authItem.displayName = newDisplayName;
285 String updatedRefName = authItem.toString();
286 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
287 return updatedRefName;
290 protected String getRefPropName() {
291 return ServiceBindingUtils.AUTH_REF_PROP;
295 * Checks to see if the refName has changed, and if so,
296 * uses utilities to find all references and update them.
299 protected void handleItemRefNameReferenceUpdate() throws Exception {
300 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
301 // We have work to do.
302 if (logger.isDebugEnabled()) {
303 String eol = System.getProperty("line.separator");
304 logger.debug("Need to find and update references to Item." + eol
305 + " Old refName" + oldRefNameOnUpdate + eol
306 + " New refName" + newRefNameOnUpdate);
308 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
309 RepositoryClient repoClient = getRepositoryClient(ctx);
310 String refNameProp = getRefPropName();
312 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
313 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
314 if (logger.isDebugEnabled()) {
315 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
321 * If no short identifier was provided in the input payload, generate a
322 * short identifier from the preferred term display name or term name.
324 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
325 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
326 String termDisplayName =
327 (String) getStringValueInPrimaryRepeatingComplexProperty(
328 docModel, authorityItemCommonSchemaName,
329 getItemTermInfoGroupXPathBase(),
330 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
332 (String) getStringValueInPrimaryRepeatingComplexProperty(
333 docModel, authorityItemCommonSchemaName,
334 getItemTermInfoGroupXPathBase(),
335 AuthorityItemJAXBSchema.TERM_NAME);
336 if (Tools.isEmpty(shortIdentifier)) {
337 String generatedShortIdentifier =
338 AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName, termName);
339 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER, generatedShortIdentifier);
344 * Generate a refName for the authority item from the short identifier
347 * All refNames for authority items are generated. If a client supplies
348 * a refName, it will be overwritten during create (per this method)
349 * or discarded during update (per filterReadOnlyPropertiesForPart).
351 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
354 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
356 String authorityRefBaseName) throws Exception {
357 DocumentModel docModel = wrapDoc.getWrappedObject();
358 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
360 (String) getStringValueInPrimaryRepeatingComplexProperty(
361 docModel, authorityItemCommonSchemaName,
362 getItemTermInfoGroupXPathBase(),
363 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
364 if (Tools.isEmpty(authorityRefBaseName)) {
365 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
367 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
368 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
369 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
373 * Check the logic around the parent pointer. Note that we only need do this on
374 * create, since we have logic to make this read-only on update.
378 * @throws Exception the exception
380 private void handleInAuthority(DocumentModel docModel) throws Exception {
381 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
382 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
384 docModel.setProperty(authorityItemCommonSchemaName,
385 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
389 public AuthorityRefDocList getReferencingObjects(
390 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
391 List<String> serviceTypes,
393 String itemcsid) throws Exception {
394 AuthorityRefDocList authRefDocList = null;
395 RepositoryInstance repoSession = null;
396 boolean releaseRepoSession = false;
399 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
400 repoSession = this.getRepositorySession();
401 if (repoSession == null) {
402 repoSession = repoClient.getRepositorySession();
403 releaseRepoSession = true;
405 DocumentFilter myFilter = getDocumentFilter();
408 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
409 DocumentModel docModel = wrapper.getWrappedObject();
410 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
411 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
412 repoSession, ctx, repoClient,
416 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
417 } catch (PropertyException pe) {
419 } catch (DocumentException de) {
421 } catch (Exception e) {
422 if (logger.isDebugEnabled()) {
423 logger.debug("Caught exception ", e);
425 throw new DocumentException(e);
427 if (releaseRepoSession && repoSession != null) {
428 repoClient.releaseRepositorySession(repoSession);
431 } catch (Exception e) {
432 if (logger.isDebugEnabled()) {
433 logger.debug("Caught exception ", e);
435 throw new DocumentException(e);
437 return authRefDocList;
444 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
447 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
449 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
451 // Add the CSID to the common part, since they may have fetched via the shortId.
452 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
453 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
454 unQObjectProperties.put("csid", csid);
457 return unQObjectProperties;
461 * Filters out selected values supplied in an update request.
463 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
464 * that the link to the item's parent remains untouched.
466 * @param objectProps the properties filtered out from the update payload
467 * @param partMeta metadata for the object to fill
470 public void filterReadOnlyPropertiesForPart(
471 Map<String, Object> objectProps, ObjectPartType partMeta) {
472 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
473 String commonPartLabel = getServiceContext().getCommonPartLabel();
474 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
475 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
476 objectProps.remove(AuthorityItemJAXBSchema.CSID);
477 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
478 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
483 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
484 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
485 super.extractAllParts(wrapDoc);
487 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
488 if (Tools.isTrue(showSiblings)) {
489 showSiblings(wrapDoc, ctx);
490 return; // actual result is returned on ctx.addOutputPart();
493 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
494 if (Tools.isTrue(showRelations)) {
495 showRelations(wrapDoc, ctx);
496 return; // actual result is returned on ctx.addOutputPart();
499 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
500 if (Tools.isTrue(showAllRelations)) {
501 showAllRelations(wrapDoc, ctx);
502 return; // actual result is returned on ctx.addOutputPart();
506 /** @return null on parent not found
508 protected String getParentCSID(String thisCSID) throws Exception {
509 String parentCSID = null;
511 String predicate = RelationshipType.HAS_BROADER.value();
512 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
513 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
514 if (parentList != null) {
515 if (parentList.size() == 0) {
518 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
519 parentCSID = relationListItem.getObjectCsid();
522 } catch (Exception e) {
523 logger.error("Could not find parent for this: " + thisCSID, e);
528 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
529 MultipartServiceContext ctx) throws Exception {
530 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
532 String predicate = RelationshipType.HAS_BROADER.value();
533 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
534 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
536 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
537 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
539 if(logger.isTraceEnabled()) {
540 String dump = dumpLists(thisCSID, parentList, childrenList, null);
541 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
544 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
545 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
546 //Not optimal, but that's the current design spec.
548 for (RelationsCommonList.RelationListItem parent : parentList) {
549 childrenList.add(parent);
552 long childrenSize = childrenList.size();
553 childrenListOuter.setTotalItems(childrenSize);
554 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
556 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
557 ctx.addOutputPart(relationsPart);
560 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
561 MultipartServiceContext ctx) throws Exception {
562 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
563 String parentCSID = getParentCSID(thisCSID);
564 if (parentCSID == null) {
565 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
569 String predicate = RelationshipType.HAS_BROADER.value();
570 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
571 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
573 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
576 RelationsCommonList.RelationListItem item = null;
577 for (RelationsCommonList.RelationListItem sibling : siblingList) {
578 if (thisCSID.equals(sibling.getSubjectCsid())) {
579 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.
582 //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.
583 for (RelationsCommonList.RelationListItem self : toRemoveList) {
584 removeFromList(siblingList, self);
587 long siblingSize = siblingList.size();
588 siblingListOuter.setTotalItems(siblingSize);
589 siblingListOuter.setItemsInPage(siblingSize);
590 if(logger.isTraceEnabled()) {
591 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
592 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
595 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
596 ctx.addOutputPart(relationsPart);
599 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
600 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
602 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
603 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
605 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
606 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
608 if(logger.isTraceEnabled()) {
609 String dump = dumpLists(thisCSID, subjectList, objectList, null);
610 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
613 subjectList.addAll(objectList);
615 //now subjectList actually has records BOTH where thisCSID is subject and object.
616 long relatedSize = subjectList.size();
617 subjectListOuter.setTotalItems(relatedSize);
618 subjectListOuter.setItemsInPage(relatedSize);
620 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
621 ctx.addOutputPart(relationsPart);
624 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
625 super.fillAllParts(wrapDoc, action);
627 ServiceContext ctx = getServiceContext();
628 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
629 DocumentModel documentModel = (wrapDoc.getWrappedObject());
630 String itemCsid = documentModel.getName();
632 //UPDATE and CREATE will call. Updates relations part
633 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
635 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
636 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
640 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
641 super.completeCreate(wrapDoc);
642 handleRelationsPayload(wrapDoc, false);
645 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
646 super.completeUpdate(wrapDoc);
647 handleRelationsPayload(wrapDoc, true);
648 handleItemRefNameReferenceUpdate();
651 // Note that we must do this after we have completed the Update, so that the repository has the
652 // info for the item itself. The relations code must call into the repo to get info for each end.
653 // This could be optimized to pass in the parent docModel, since it will often be one end.
654 // Nevertheless, we should complete the item save before we do work on the relations, especially
655 // since a save on Create might fail, and we would not want to create relations for something
656 // that may not be created...
657 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
658 ServiceContext ctx = getServiceContext();
659 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
660 DocumentModel documentModel = (wrapDoc.getWrappedObject());
661 String itemCsid = documentModel.getName();
663 //Updates relations part
664 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
666 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
667 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
669 //now we add part for relations list
670 //ServiceContext ctx = getServiceContext();
671 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
672 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
675 /** updateRelations strategy:
677 go through inboundList, remove anything from childList that matches from childList
678 go through inboundList, remove anything from parentList that matches from parentList
679 go through parentList, delete all remaining
680 go through childList, delete all remaining
681 go through actionList, add all remaining.
682 check for duplicate children
683 check for more than one parent.
685 inboundList parentList childList actionList
686 ---------------- --------------- ---------------- ----------------
687 child-a parent-c child-a child-b
688 child-b parent-d child-c
691 private RelationsCommonList updateRelations(
692 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
694 if (logger.isTraceEnabled()) {
695 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
697 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
699 return null; //nothing to do--they didn't send a list of relations.
701 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
702 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
703 List<RelationsCommonList.RelationListItem> actionList = newList();
704 List<RelationsCommonList.RelationListItem> childList = null;
705 List<RelationsCommonList.RelationListItem> parentList = null;
706 DocumentModel docModel = wrapDoc.getWrappedObject();
707 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
709 ServiceContext ctx = getServiceContext();
710 //Do magic replacement of ${itemCSID} and fix URI's.
711 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
713 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
714 UriInfo uriInfo = ctx.getUriInfo();
715 MultivaluedMap queryParams = uriInfo.getQueryParameters();
718 //Run getList() once as sent to get childListOuter:
719 String predicate = RelationshipType.HAS_BROADER.value();
720 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
721 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
722 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
723 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
724 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
725 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
727 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
728 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
729 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
730 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
731 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
734 childList = childListOuter.getRelationListItem();
735 parentList = parentListOuter.getRelationListItem();
737 if (parentList.size() > 1) {
738 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
741 if (logger.isTraceEnabled()) {
742 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
747 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
748 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
749 // and so the CSID for those may be null
750 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
751 // Look for parents and children
752 if(itemCSID.equals(inboundItem.getObject().getCsid())
753 || itemRefName.equals(inboundItem.getObject().getRefName())) {
754 //then this is an item that says we have a child. That child is inboundItem
755 RelationsCommonList.RelationListItem childItem =
756 (childList == null) ? null : findInList(childList, inboundItem);
757 if (childItem != null) {
758 if (logger.isTraceEnabled()) {
759 StringBuilder sb = new StringBuilder();
760 itemToString(sb, "== Child: ", childItem);
761 logger.trace("Found inboundChild in current child list: " + sb.toString());
763 removeFromList(childList, childItem); //exists, just take it off delete list
765 if (logger.isTraceEnabled()) {
766 StringBuilder sb = new StringBuilder();
767 itemToString(sb, "== Child: ", inboundItem);
768 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
770 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
771 String newChildCsid = inboundItem.getSubject().getCsid();
772 if(newChildCsid == null) {
773 String newChildRefName = inboundItem.getSubject().getRefName();
774 if(newChildRefName==null) {
775 throw new RuntimeException("Child with no CSID or refName!");
777 if (logger.isTraceEnabled()) {
778 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
780 DocumentModel newChildDocModel =
781 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
782 newChildRefName, getServiceContext().getResourceMap());
783 newChildCsid = getCsid(newChildDocModel);
785 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
788 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
789 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
790 //then this is an item that says we have a parent. inboundItem is that parent.
791 RelationsCommonList.RelationListItem parentItem =
792 (parentList == null) ? null : findInList(parentList, inboundItem);
793 if (parentItem != null) {
794 removeFromList(parentList, parentItem); //exists, just take it off delete list
796 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
799 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
802 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
805 if (logger.isTraceEnabled()) {
806 String dump = dumpLists(itemCSID, parentList, childList, actionList);
807 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
810 if (logger.isTraceEnabled()) {
811 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
812 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
814 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
815 deleteRelations(childList, ctx, "childList");
817 if (logger.isTraceEnabled()) {
818 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
819 + actionList.size() + " new parents and children.");
821 createRelations(actionList, ctx);
822 if (logger.isTraceEnabled()) {
823 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
825 //We return all elements on the inbound list, since we have just worked to make them exist in the system
826 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
827 return relationsCommonListBody;
830 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
831 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
832 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
833 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
834 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
835 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
836 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
837 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
838 deleteRelations(parentList, ctx, "parentList-delete");
842 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
844 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
846 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
848 sb.append(item.getPredicate());
850 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
854 private String dumpLists(String itemCSID,
855 List<RelationsCommonList.RelationListItem> parentList,
856 List<RelationsCommonList.RelationListItem> childList,
857 List<RelationsCommonList.RelationListItem> actionList) {
858 StringBuilder sb = new StringBuilder();
859 sb.append("itemCSID: " + itemCSID + CR);
860 if(parentList!=null) {
861 sb.append(dumpList(parentList, "parentList"));
863 if(childList!=null) {
864 sb.append(dumpList(childList, "childList"));
866 if(actionList!=null) {
867 sb.append(dumpList(actionList, "actionList"));
869 return sb.toString();
871 private final static String CR = "\r\n";
872 private final static String T = " ";
874 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
875 StringBuilder sb = new StringBuilder();
877 if (list.size() > 0) {
878 sb.append("=========== " + label + " ==========" + CR);
880 for (RelationsCommonList.RelationListItem item : list) {
881 itemToString(sb, "== ", item);
884 return sb.toString();
887 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
888 * and sets URI correctly for related items.
889 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
891 protected void fixupInboundListItems(ServiceContext ctx,
892 List<RelationsCommonList.RelationListItem> inboundList,
893 DocumentModel docModel,
894 String itemCSID) throws Exception {
895 String thisURI = this.getUri(docModel);
896 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
897 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
898 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
899 RelationsDocListItem inboundItemObject = inboundItem.getObject();
900 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
902 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
903 inboundItem.setObjectCsid(itemCSID);
904 inboundItemObject.setCsid(itemCSID);
905 //inboundItemObject.setUri(getUri(docModel));
908 String objectCsid = inboundItemObject.getCsid();
909 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
910 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
911 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
912 inboundItemObject.setUri(uri); //CSPACE-4037
915 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
917 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
918 inboundItem.setSubjectCsid(itemCSID);
919 inboundItemSubject.setCsid(itemCSID);
920 //inboundItemSubject.setUri(getUri(docModel));
923 String subjectCsid = inboundItemSubject.getCsid();
924 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
925 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
926 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
927 inboundItemSubject.setUri(uri); //CSPACE-4037
930 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
935 // this method calls the RelationResource to have it create the relations and persist them.
936 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
937 for (RelationsCommonList.RelationListItem item : inboundList) {
938 RelationsCommon rc = new RelationsCommon();
939 //rc.setCsid(item.getCsid());
940 //todo: assignTo(item, rc);
941 RelationsDocListItem itemSubject = item.getSubject();
942 RelationsDocListItem itemObject = item.getObject();
944 // Set at least one of CSID and refName for Subject and Object
945 // Either value might be null for for each of Subject and Object
946 String subjectCsid = itemSubject.getCsid();
947 rc.setSubjectCsid(subjectCsid);
949 String objCsid = itemObject.getCsid();
950 rc.setObjectCsid(objCsid);
952 rc.setSubjectRefName(itemSubject.getRefName());
953 rc.setObjectRefName(itemObject.getRefName());
955 rc.setRelationshipType(item.getPredicate());
956 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
957 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
959 // This is superfluous, since it will be fetched by the Relations Create logic.
960 rc.setSubjectDocumentType(itemSubject.getDocumentType());
961 rc.setObjectDocumentType(itemObject.getDocumentType());
963 // This is superfluous, since it will be fetched by the Relations Create logic.
964 rc.setSubjectUri(itemSubject.getUri());
965 rc.setObjectUri(itemObject.getUri());
966 // May not have the info here. Only really require CSID or refName.
967 // Rest is handled in the Relation create mechanism
968 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
970 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
971 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
972 payloadOut.addPart(outputPart);
973 RelationResource relationResource = new RelationResource();
974 Object res = relationResource.create(ctx.getResourceMap(),
975 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
979 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
981 for (RelationsCommonList.RelationListItem item : list) {
982 RelationResource relationResource = new RelationResource();
983 if(logger.isTraceEnabled()) {
984 StringBuilder sb = new StringBuilder();
985 itemToString(sb, "==== TO DELETE: ", item);
986 logger.trace(sb.toString());
988 Object res = relationResource.delete(item.getCsid());
990 } catch (Throwable t) {
991 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
996 private List<RelationsCommonList.RelationListItem> newList() {
997 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1001 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1002 List<RelationsCommonList.RelationListItem> result = newList();
1003 for (RelationsCommonList.RelationListItem item : inboundList) {
1009 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1010 // But the list items must not be sparse
1011 private RelationsCommonList.RelationListItem findInList(
1012 List<RelationsCommonList.RelationListItem> list,
1013 RelationsCommonList.RelationListItem item) {
1014 RelationsCommonList.RelationListItem foundItem = null;
1015 for (RelationsCommonList.RelationListItem listItem : list) {
1016 if (itemsEqual(listItem, item)) { //equals must be defined, else
1017 foundItem = listItem;
1024 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1025 // But item1 must not be sparse
1026 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1027 if (item1 == null || item2 == null) {
1030 RelationsDocListItem subj1 = item1.getSubject();
1031 RelationsDocListItem subj2 = item2.getSubject();
1032 RelationsDocListItem obj1 = item1.getObject();
1033 RelationsDocListItem obj2 = item2.getObject();
1034 String subj1Csid = subj1.getCsid();
1035 String subj2Csid = subj2.getCsid();
1036 String subj1RefName = subj1.getRefName();
1037 String subj2RefName = subj2.getRefName();
1039 String obj1Csid = obj1.getCsid();
1040 String obj2Csid = obj2.getCsid();
1041 String obj1RefName = obj1.getRefName();
1042 String obj2RefName = obj2.getRefName();
1045 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1046 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1047 // predicate is proper, but still allow relationshipType
1048 && (item1.getPredicate().equals(item2.getPredicate())
1049 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1050 // Allow missing docTypes, so long as they do not conflict
1051 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1052 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1056 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1060 /* don't even THINK of re-using this method.
1061 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1063 private String extractInAuthorityCSID(String uri) {
1064 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1065 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1066 Matcher m = p.matcher(uri);
1068 if (m.groupCount() < 3) {
1069 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1072 //String service = m.group(1);
1073 String inauth = m.group(2);
1074 //String theRest = m.group(3);
1076 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1079 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1084 //ensures CSPACE-4042
1085 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1086 String authorityCSID = extractInAuthorityCSID(thisURI);
1087 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1088 if (Tools.isBlank(authorityCSID)
1089 || Tools.isBlank(authorityCSIDForInbound)
1090 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1091 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1095 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1096 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1097 ServiceContext ctx = getServiceContext();
1098 MultivaluedMap queryParams = ctx.getQueryParams();
1099 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1100 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1101 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1103 RelationResource relationResource = new RelationResource();
1104 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1105 return relationsCommonList;
1107 //============================= END TODO refactor ==========================
1109 public String getItemTermInfoGroupXPathBase() {
1110 return this.authorityItemTermGroupXPathBase;
1113 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1114 this.authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;