2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common.vocabulary.nuxeo;
26 import org.collectionspace.services.client.AuthorityClient;
27 import org.collectionspace.services.client.PayloadInputPart;
28 import org.collectionspace.services.client.PayloadOutputPart;
29 import org.collectionspace.services.client.PoxPayloadIn;
30 import org.collectionspace.services.client.PoxPayloadOut;
31 import org.collectionspace.services.client.RelationClient;
32 import org.collectionspace.services.common.ResourceBase;
33 import org.collectionspace.services.common.ServiceMessages;
34 import org.collectionspace.services.common.api.CommonAPI;
35 import org.collectionspace.services.common.api.RefName;
36 import org.collectionspace.services.common.api.Tools;
37 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
38 import org.collectionspace.services.common.context.MultipartServiceContext;
39 import org.collectionspace.services.common.context.ServiceBindingUtils;
40 import org.collectionspace.services.common.context.ServiceContext;
41 import org.collectionspace.services.common.document.DocumentException;
42 import org.collectionspace.services.common.document.DocumentFilter;
43 import org.collectionspace.services.common.document.DocumentWrapper;
44 import org.collectionspace.services.common.document.DocumentWrapperImpl;
45 import org.collectionspace.services.common.relation.IRelationsManager;
46 import org.collectionspace.services.common.repository.RepositoryClient;
47 import org.collectionspace.services.common.repository.RepositoryClientFactory;
48 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
49 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
50 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils;
51 import org.collectionspace.services.config.service.ListResultField;
52 import org.collectionspace.services.config.service.ObjectPartType;
53 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
54 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
55 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
56 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
57 import org.collectionspace.services.relation.RelationResource;
58 import org.collectionspace.services.relation.RelationsCommon;
59 import org.collectionspace.services.relation.RelationsCommonList;
60 import org.collectionspace.services.relation.RelationsDocListItem;
61 import org.collectionspace.services.relation.RelationshipType;
62 import org.nuxeo.ecm.core.api.ClientException;
63 import org.nuxeo.ecm.core.api.DocumentModel;
64 import org.nuxeo.ecm.core.api.model.PropertyException;
65 import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
66 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
67 import org.nuxeo.runtime.transaction.TransactionHelper;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
71 import javax.ws.rs.PathParam;
72 import javax.ws.rs.WebApplicationException;
73 import javax.ws.rs.core.Context;
74 import javax.ws.rs.core.MultivaluedMap;
75 import javax.ws.rs.core.Response;
76 import javax.ws.rs.core.UriInfo;
77 import java.util.ArrayList;
78 import java.util.List;
80 import java.util.regex.Matcher;
81 import java.util.regex.Pattern;
82 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
84 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
86 * AuthorityItemDocumentModelHandler
88 * $LastChangedRevision: $
91 public abstract class AuthorityItemDocumentModelHandler<AICommon>
92 extends DocHandlerBase<AICommon> {
94 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
95 private String authorityItemCommonSchemaName;
96 private String authorityItemTermGroupXPathBase;
98 * inVocabulary is the parent Authority for this context
100 protected String inAuthority = null;
101 protected String authorityRefNameBase = null;
102 // Used to determine when the displayName changes as part of the update.
103 protected String oldDisplayNameOnUpdate = null;
104 protected String oldRefNameOnUpdate = null;
105 protected String newRefNameOnUpdate = null;
107 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
108 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
111 public void setInAuthority(String inAuthority) {
112 this.inAuthority = inAuthority;
115 /** Subclasses may override this to customize the URI segment. */
116 public String getAuthorityServicePath() {
117 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
121 public String getUri(DocumentModel docModel) {
122 // Laramie20110510 CSPACE-3932
123 String authorityServicePath = getAuthorityServicePath();
124 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
126 inAuthority = (String) docModel.getProperty(authorityItemCommonSchemaName,
127 AuthorityItemJAXBSchema.IN_AUTHORITY);
128 } catch (ClientException pe) {
129 throw new RuntimeException("Could not get parent specifier for item!");
132 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
135 protected String getAuthorityRefNameBase() {
136 return this.authorityRefNameBase;
139 public void setAuthorityRefNameBase(String value) {
140 this.authorityRefNameBase = value;
144 * Note: the Vocabulary service's VocabularyItemDocumentModelHandler class overrides this method.
146 protected ListResultField getListResultsDisplayNameField() {
147 ListResultField result = new ListResultField();
148 // Per CSPACE-5132, the name of this element remains 'displayName'
149 // for backwards compatibility, although its value is obtained
150 // from the termDisplayName field.
152 // In CSPACE-5134, these list results will change substantially
153 // to return display names for both the preferred term and for
154 // each non-preferred term (if any).
155 result.setElement(AuthorityItemJAXBSchema.DISPLAY_NAME);
156 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
157 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
163 * Note: the Vocabulary service's VocabularyItemDocumentModelHandler class overrides this method.
165 protected ListResultField getListResultsTermStatusField() {
166 ListResultField result = new ListResultField();
168 result.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
169 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
170 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
176 public List<ListResultField> getListItemsArray() throws DocumentException {
177 List<ListResultField> list = super.getListItemsArray();
178 int nFields = list.size();
179 // Ensure that each item in a list of Authority items includes
180 // a set of common fields, so we do not depend upon configuration
181 // for general logic.
182 boolean hasDisplayName = false;
183 boolean hasShortId = false;
184 boolean hasRefName = false;
185 boolean hasTermStatus = false;
186 for (int i = 0; i < nFields; i++) {
187 ListResultField field = list.get(i);
188 String elName = field.getElement();
189 if (AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName) || AuthorityItemJAXBSchema.DISPLAY_NAME.equals(elName)) {
190 hasDisplayName = true;
191 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
193 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
195 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
196 hasTermStatus = true;
199 ListResultField field;
200 if (!hasDisplayName) {
201 field = getListResultsDisplayNameField();
205 field = new ListResultField();
206 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
207 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
211 field = new ListResultField();
212 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
213 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
216 if (!hasTermStatus) {
217 field = getListResultsTermStatusField();
226 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
229 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
230 // first fill all the parts of the document
231 super.handleCreate(wrapDoc);
232 // Ensure we have required fields set properly
233 handleInAuthority(wrapDoc.getWrappedObject());
236 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
237 // refName includes displayName, so we force a correct value here.
238 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
242 * Note that the Vocabulary service's document-model for items overrides this method.
244 protected String getPrimaryDisplayName(DocumentModel docModel, String schema,
245 String complexPropertyName, String fieldName) {
246 String result = null;
248 result = getStringValueInPrimaryRepeatingComplexProperty(docModel, schema, complexPropertyName, fieldName);
254 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
257 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
258 // First, get a copy of the old displayName
259 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
260 // AuthorityItemJAXBSchema.DISPLAY_NAME);
261 oldDisplayNameOnUpdate = getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
262 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
263 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
264 AuthorityItemJAXBSchema.REF_NAME);
265 super.handleUpdate(wrapDoc);
267 // Now, check the new display and handle the refname update.
268 String newDisplayName = (String) getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
269 authorityItemTermGroupXPathBase,
270 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
271 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
272 // Need to update the refName, and then fix all references.
273 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
275 // Mark as not needing attention in completeUpdate phase.
276 newRefNameOnUpdate = null;
277 oldRefNameOnUpdate = null;
282 * Handle display name.
284 * @param docModel the doc model
285 * @throws Exception the exception
287 // protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
288 // // Do nothing by default.
292 * Handle refName updates for changes to display name.
293 * Assumes refName is already correct. Just ensures it is right.
295 * @param docModel the doc model
296 * @param newDisplayName the new display name
297 * @throws Exception the exception
299 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
300 String newDisplayName) throws Exception {
301 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
302 if (authItem == null) {
303 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
305 throw new IllegalArgumentException(err);
307 authItem.displayName = newDisplayName;
308 String updatedRefName = authItem.toString();
309 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
310 return updatedRefName;
313 protected String getRefPropName() {
314 return ServiceBindingUtils.AUTH_REF_PROP;
318 * Checks to see if the refName has changed, and if so,
319 * uses utilities to find all references and update them.
322 protected void handleItemRefNameReferenceUpdate() throws Exception {
323 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
324 // We have work to do.
325 if (logger.isDebugEnabled()) {
326 String eol = System.getProperty("line.separator");
327 logger.debug("Need to find and update references to Item." + eol
328 + " Old refName" + oldRefNameOnUpdate + eol
329 + " New refName" + newRefNameOnUpdate);
331 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
332 RepositoryClient repoClient = getRepositoryClient(ctx);
333 String refNameProp = getRefPropName();
335 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
336 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
337 if (logger.isDebugEnabled()) {
338 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
344 * If no short identifier was provided in the input payload, generate a
345 * short identifier from the preferred term display name or term name.
347 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel,
348 String schemaName) throws Exception {
349 String shortIdentifier = (String) docModel.getProperty(schemaName,
350 AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
352 String termDisplayName = getPrimaryDisplayName(
353 docModel, authorityItemCommonSchemaName,
354 getItemTermInfoGroupXPathBase(),
355 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
357 String termName = getPrimaryDisplayName(
358 docModel, authorityItemCommonSchemaName,
359 getItemTermInfoGroupXPathBase(),
360 AuthorityItemJAXBSchema.TERM_NAME);
362 if (Tools.isEmpty(shortIdentifier)) {
363 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName,
365 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER,
366 generatedShortIdentifier);
371 * Generate a refName for the authority item from the short identifier
374 * All refNames for authority items are generated. If a client supplies
375 * a refName, it will be overwritten during create (per this method)
376 * or discarded during update (per filterReadOnlyPropertiesForPart).
378 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
381 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
383 String authorityRefBaseName) throws Exception {
384 DocumentModel docModel = wrapDoc.getWrappedObject();
385 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
386 String displayName = getPrimaryDisplayName(docModel, authorityItemCommonSchemaName,
387 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
389 if (Tools.isEmpty(authorityRefBaseName)) {
390 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
393 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
394 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
395 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
399 * Check the logic around the parent pointer. Note that we only need do this on
400 * create, since we have logic to make this read-only on update.
404 * @throws Exception the exception
406 private void handleInAuthority(DocumentModel docModel) throws Exception {
407 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
408 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
410 docModel.setProperty(authorityItemCommonSchemaName,
411 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
415 public AuthorityRefDocList getReferencingObjects(
416 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
417 List<String> serviceTypes,
419 String itemcsid) throws Exception {
420 AuthorityRefDocList authRefDocList = null;
421 RepositoryInstance repoSession = null;
422 boolean releaseRepoSession = false;
425 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
426 repoSession = this.getRepositorySession();
427 if (repoSession == null) {
428 repoSession = repoClient.getRepositorySession();
429 releaseRepoSession = true;
431 DocumentFilter myFilter = getDocumentFilter();
434 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
435 DocumentModel docModel = wrapper.getWrappedObject();
436 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
437 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
438 repoSession, ctx, repoClient,
442 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
443 } catch (PropertyException pe) {
445 } catch (DocumentException de) {
447 } catch (Exception e) {
448 if (logger.isDebugEnabled()) {
449 logger.debug("Caught exception ", e);
451 throw new DocumentException(e);
453 if (releaseRepoSession && repoSession != null) {
454 repoClient.releaseRepositorySession(repoSession);
457 } catch (Exception e) {
458 if (logger.isDebugEnabled()) {
459 logger.debug("Caught exception ", e);
461 throw new DocumentException(e);
463 return authRefDocList;
470 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
473 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
475 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
477 // Add the CSID to the common part, since they may have fetched via the shortId.
478 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
479 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
480 unQObjectProperties.put("csid", csid);
483 return unQObjectProperties;
487 * Filters out selected values supplied in an update request.
489 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
490 * that the link to the item's parent remains untouched.
492 * @param objectProps the properties filtered out from the update payload
493 * @param partMeta metadata for the object to fill
496 public void filterReadOnlyPropertiesForPart(
497 Map<String, Object> objectProps, ObjectPartType partMeta) {
498 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
499 String commonPartLabel = getServiceContext().getCommonPartLabel();
500 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
501 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
502 objectProps.remove(AuthorityItemJAXBSchema.CSID);
503 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
504 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
509 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
510 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
511 super.extractAllParts(wrapDoc);
513 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
514 if (Tools.isTrue(showSiblings)) {
515 showSiblings(wrapDoc, ctx);
516 return; // actual result is returned on ctx.addOutputPart();
519 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
520 if (Tools.isTrue(showRelations)) {
521 showRelations(wrapDoc, ctx);
522 return; // actual result is returned on ctx.addOutputPart();
525 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
526 if (Tools.isTrue(showAllRelations)) {
527 showAllRelations(wrapDoc, ctx);
528 return; // actual result is returned on ctx.addOutputPart();
532 /** @return null on parent not found
534 protected String getParentCSID(String thisCSID) throws Exception {
535 String parentCSID = null;
537 String predicate = RelationshipType.HAS_BROADER.value();
538 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
539 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
540 if (parentList != null) {
541 if (parentList.size() == 0) {
544 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
545 parentCSID = relationListItem.getObjectCsid();
548 } catch (Exception e) {
549 logger.error("Could not find parent for this: " + thisCSID, e);
554 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
555 MultipartServiceContext ctx) throws Exception {
556 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
558 String predicate = RelationshipType.HAS_BROADER.value();
559 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
560 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
562 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
563 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
565 if(logger.isTraceEnabled()) {
566 String dump = dumpLists(thisCSID, parentList, childrenList, null);
567 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
570 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
571 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
572 //Not optimal, but that's the current design spec.
574 for (RelationsCommonList.RelationListItem parent : parentList) {
575 childrenList.add(parent);
578 long childrenSize = childrenList.size();
579 childrenListOuter.setTotalItems(childrenSize);
580 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
582 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
583 ctx.addOutputPart(relationsPart);
586 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
587 MultipartServiceContext ctx) throws Exception {
588 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
589 String parentCSID = getParentCSID(thisCSID);
590 if (parentCSID == null) {
591 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
595 String predicate = RelationshipType.HAS_BROADER.value();
596 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
597 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
599 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
602 RelationsCommonList.RelationListItem item = null;
603 for (RelationsCommonList.RelationListItem sibling : siblingList) {
604 if (thisCSID.equals(sibling.getSubjectCsid())) {
605 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.
608 //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.
609 for (RelationsCommonList.RelationListItem self : toRemoveList) {
610 removeFromList(siblingList, self);
613 long siblingSize = siblingList.size();
614 siblingListOuter.setTotalItems(siblingSize);
615 siblingListOuter.setItemsInPage(siblingSize);
616 if(logger.isTraceEnabled()) {
617 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
618 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
621 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
622 ctx.addOutputPart(relationsPart);
625 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
626 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
628 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
629 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
631 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
632 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
634 if(logger.isTraceEnabled()) {
635 String dump = dumpLists(thisCSID, subjectList, objectList, null);
636 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
639 subjectList.addAll(objectList);
641 //now subjectList actually has records BOTH where thisCSID is subject and object.
642 long relatedSize = subjectList.size();
643 subjectListOuter.setTotalItems(relatedSize);
644 subjectListOuter.setItemsInPage(relatedSize);
646 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
647 ctx.addOutputPart(relationsPart);
650 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
651 super.fillAllParts(wrapDoc, action);
653 ServiceContext ctx = getServiceContext();
654 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
655 DocumentModel documentModel = (wrapDoc.getWrappedObject());
656 String itemCsid = documentModel.getName();
658 //UPDATE and CREATE will call. Updates relations part
659 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
661 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
662 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
666 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
667 super.completeCreate(wrapDoc);
668 handleRelationsPayload(wrapDoc, false);
671 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
672 super.completeUpdate(wrapDoc);
673 handleRelationsPayload(wrapDoc, true);
674 handleItemRefNameReferenceUpdate();
677 // Note that we must do this after we have completed the Update, so that the repository has the
678 // info for the item itself. The relations code must call into the repo to get info for each end.
679 // This could be optimized to pass in the parent docModel, since it will often be one end.
680 // Nevertheless, we should complete the item save before we do work on the relations, especially
681 // since a save on Create might fail, and we would not want to create relations for something
682 // that may not be created...
683 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
684 ServiceContext ctx = getServiceContext();
685 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
686 DocumentModel documentModel = (wrapDoc.getWrappedObject());
687 String itemCsid = documentModel.getName();
689 //Updates relations part
690 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
692 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
693 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
695 //now we add part for relations list
696 //ServiceContext ctx = getServiceContext();
697 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
698 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
701 /** updateRelations strategy:
703 go through inboundList, remove anything from childList that matches from childList
704 go through inboundList, remove anything from parentList that matches from parentList
705 go through parentList, delete all remaining
706 go through childList, delete all remaining
707 go through actionList, add all remaining.
708 check for duplicate children
709 check for more than one parent.
711 inboundList parentList childList actionList
712 ---------------- --------------- ---------------- ----------------
713 child-a parent-c child-a child-b
714 child-b parent-d child-c
717 private RelationsCommonList updateRelations(
718 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
720 if (logger.isTraceEnabled()) {
721 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
723 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
725 return null; //nothing to do--they didn't send a list of relations.
727 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
728 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
729 List<RelationsCommonList.RelationListItem> actionList = newList();
730 List<RelationsCommonList.RelationListItem> childList = null;
731 List<RelationsCommonList.RelationListItem> parentList = null;
732 DocumentModel docModel = wrapDoc.getWrappedObject();
733 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
735 ServiceContext ctx = getServiceContext();
736 //Do magic replacement of ${itemCSID} and fix URI's.
737 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
739 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
740 UriInfo uriInfo = ctx.getUriInfo();
741 MultivaluedMap queryParams = uriInfo.getQueryParameters();
744 //Run getList() once as sent to get childListOuter:
745 String predicate = RelationshipType.HAS_BROADER.value();
746 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
747 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
748 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
749 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
750 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
751 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
753 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
754 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
755 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
756 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
757 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
760 childList = childListOuter.getRelationListItem();
761 parentList = parentListOuter.getRelationListItem();
763 if (parentList.size() > 1) {
764 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
767 if (logger.isTraceEnabled()) {
768 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
773 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
774 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
775 // and so the CSID for those may be null
776 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
777 // Look for parents and children
778 if(itemCSID.equals(inboundItem.getObject().getCsid())
779 || itemRefName.equals(inboundItem.getObject().getRefName())) {
780 //then this is an item that says we have a child. That child is inboundItem
781 RelationsCommonList.RelationListItem childItem =
782 (childList == null) ? null : findInList(childList, inboundItem);
783 if (childItem != null) {
784 if (logger.isTraceEnabled()) {
785 StringBuilder sb = new StringBuilder();
786 itemToString(sb, "== Child: ", childItem);
787 logger.trace("Found inboundChild in current child list: " + sb.toString());
789 removeFromList(childList, childItem); //exists, just take it off delete list
791 if (logger.isTraceEnabled()) {
792 StringBuilder sb = new StringBuilder();
793 itemToString(sb, "== Child: ", inboundItem);
794 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
796 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
797 String newChildCsid = inboundItem.getSubject().getCsid();
798 if(newChildCsid == null) {
799 String newChildRefName = inboundItem.getSubject().getRefName();
800 if(newChildRefName==null) {
801 throw new RuntimeException("Child with no CSID or refName!");
803 if (logger.isTraceEnabled()) {
804 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
806 DocumentModel newChildDocModel =
807 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
808 newChildRefName, getServiceContext().getResourceMap());
809 newChildCsid = getCsid(newChildDocModel);
811 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
814 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
815 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
816 //then this is an item that says we have a parent. inboundItem is that parent.
817 RelationsCommonList.RelationListItem parentItem =
818 (parentList == null) ? null : findInList(parentList, inboundItem);
819 if (parentItem != null) {
820 removeFromList(parentList, parentItem); //exists, just take it off delete list
822 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
825 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
828 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
831 if (logger.isTraceEnabled()) {
832 String dump = dumpLists(itemCSID, parentList, childList, actionList);
833 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
836 if (logger.isTraceEnabled()) {
837 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
838 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
840 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
841 deleteRelations(childList, ctx, "childList");
843 if (logger.isTraceEnabled()) {
844 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
845 + actionList.size() + " new parents and children.");
847 createRelations(actionList, ctx);
848 if (logger.isTraceEnabled()) {
849 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
851 //We return all elements on the inbound list, since we have just worked to make them exist in the system
852 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
853 return relationsCommonListBody;
856 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
857 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
858 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
859 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
860 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
861 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
862 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
863 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
864 deleteRelations(parentList, ctx, "parentList-delete");
868 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
870 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
872 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
874 sb.append(item.getPredicate());
876 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
880 private String dumpLists(String itemCSID,
881 List<RelationsCommonList.RelationListItem> parentList,
882 List<RelationsCommonList.RelationListItem> childList,
883 List<RelationsCommonList.RelationListItem> actionList) {
884 StringBuilder sb = new StringBuilder();
885 sb.append("itemCSID: " + itemCSID + CR);
886 if(parentList!=null) {
887 sb.append(dumpList(parentList, "parentList"));
889 if(childList!=null) {
890 sb.append(dumpList(childList, "childList"));
892 if(actionList!=null) {
893 sb.append(dumpList(actionList, "actionList"));
895 return sb.toString();
897 private final static String CR = "\r\n";
898 private final static String T = " ";
900 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
901 StringBuilder sb = new StringBuilder();
903 if (list.size() > 0) {
904 sb.append("=========== " + label + " ==========" + CR);
906 for (RelationsCommonList.RelationListItem item : list) {
907 itemToString(sb, "== ", item);
910 return sb.toString();
913 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
914 * and sets URI correctly for related items.
915 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
917 protected void fixupInboundListItems(ServiceContext ctx,
918 List<RelationsCommonList.RelationListItem> inboundList,
919 DocumentModel docModel,
920 String itemCSID) throws Exception {
921 String thisURI = this.getUri(docModel);
922 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
923 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
924 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
925 RelationsDocListItem inboundItemObject = inboundItem.getObject();
926 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
928 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
929 inboundItem.setObjectCsid(itemCSID);
930 inboundItemObject.setCsid(itemCSID);
931 //inboundItemObject.setUri(getUri(docModel));
934 String objectCsid = inboundItemObject.getCsid();
935 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
936 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
937 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
938 inboundItemObject.setUri(uri); //CSPACE-4037
941 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
943 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
944 inboundItem.setSubjectCsid(itemCSID);
945 inboundItemSubject.setCsid(itemCSID);
946 //inboundItemSubject.setUri(getUri(docModel));
949 String subjectCsid = inboundItemSubject.getCsid();
950 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
951 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
952 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
953 inboundItemSubject.setUri(uri); //CSPACE-4037
956 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
961 // this method calls the RelationResource to have it create the relations and persist them.
962 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
963 for (RelationsCommonList.RelationListItem item : inboundList) {
964 RelationsCommon rc = new RelationsCommon();
965 //rc.setCsid(item.getCsid());
966 //todo: assignTo(item, rc);
967 RelationsDocListItem itemSubject = item.getSubject();
968 RelationsDocListItem itemObject = item.getObject();
970 // Set at least one of CSID and refName for Subject and Object
971 // Either value might be null for for each of Subject and Object
972 String subjectCsid = itemSubject.getCsid();
973 rc.setSubjectCsid(subjectCsid);
975 String objCsid = itemObject.getCsid();
976 rc.setObjectCsid(objCsid);
978 rc.setSubjectRefName(itemSubject.getRefName());
979 rc.setObjectRefName(itemObject.getRefName());
981 rc.setRelationshipType(item.getPredicate());
982 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
983 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
985 // This is superfluous, since it will be fetched by the Relations Create logic.
986 rc.setSubjectDocumentType(itemSubject.getDocumentType());
987 rc.setObjectDocumentType(itemObject.getDocumentType());
989 // This is superfluous, since it will be fetched by the Relations Create logic.
990 rc.setSubjectUri(itemSubject.getUri());
991 rc.setObjectUri(itemObject.getUri());
992 // May not have the info here. Only really require CSID or refName.
993 // Rest is handled in the Relation create mechanism
994 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
996 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
997 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
998 payloadOut.addPart(outputPart);
999 RelationResource relationResource = new RelationResource();
1000 Object res = relationResource.create(ctx.getResourceMap(),
1001 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
1005 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
1007 for (RelationsCommonList.RelationListItem item : list) {
1008 RelationResource relationResource = new RelationResource();
1009 if(logger.isTraceEnabled()) {
1010 StringBuilder sb = new StringBuilder();
1011 itemToString(sb, "==== TO DELETE: ", item);
1012 logger.trace(sb.toString());
1014 Object res = relationResource.delete(item.getCsid());
1016 } catch (Throwable t) {
1017 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1022 private List<RelationsCommonList.RelationListItem> newList() {
1023 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1027 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1028 List<RelationsCommonList.RelationListItem> result = newList();
1029 for (RelationsCommonList.RelationListItem item : inboundList) {
1035 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1036 // But the list items must not be sparse
1037 private RelationsCommonList.RelationListItem findInList(
1038 List<RelationsCommonList.RelationListItem> list,
1039 RelationsCommonList.RelationListItem item) {
1040 RelationsCommonList.RelationListItem foundItem = null;
1041 for (RelationsCommonList.RelationListItem listItem : list) {
1042 if (itemsEqual(listItem, item)) { //equals must be defined, else
1043 foundItem = listItem;
1050 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1051 // But item1 must not be sparse
1052 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1053 if (item1 == null || item2 == null) {
1056 RelationsDocListItem subj1 = item1.getSubject();
1057 RelationsDocListItem subj2 = item2.getSubject();
1058 RelationsDocListItem obj1 = item1.getObject();
1059 RelationsDocListItem obj2 = item2.getObject();
1060 String subj1Csid = subj1.getCsid();
1061 String subj2Csid = subj2.getCsid();
1062 String subj1RefName = subj1.getRefName();
1063 String subj2RefName = subj2.getRefName();
1065 String obj1Csid = obj1.getCsid();
1066 String obj2Csid = obj2.getCsid();
1067 String obj1RefName = obj1.getRefName();
1068 String obj2RefName = obj2.getRefName();
1071 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1072 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1073 // predicate is proper, but still allow relationshipType
1074 && (item1.getPredicate().equals(item2.getPredicate())
1075 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1076 // Allow missing docTypes, so long as they do not conflict
1077 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1078 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1082 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1086 /* don't even THINK of re-using this method.
1087 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1089 private String extractInAuthorityCSID(String uri) {
1090 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1091 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1092 Matcher m = p.matcher(uri);
1094 if (m.groupCount() < 3) {
1095 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1098 //String service = m.group(1);
1099 String inauth = m.group(2);
1100 //String theRest = m.group(3);
1102 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1105 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1110 //ensures CSPACE-4042
1111 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1112 String authorityCSID = extractInAuthorityCSID(thisURI);
1113 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1114 if (Tools.isBlank(authorityCSID)
1115 || Tools.isBlank(authorityCSIDForInbound)
1116 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1117 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1121 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1122 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1123 ServiceContext ctx = getServiceContext();
1124 MultivaluedMap queryParams = ctx.getQueryParams();
1125 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1126 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1127 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1129 RelationResource relationResource = new RelationResource();
1130 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1131 return relationsCommonList;
1133 //============================= END TODO refactor ==========================
1135 public String getItemTermInfoGroupXPathBase() {
1136 return authorityItemTermGroupXPathBase;
1139 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1140 authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;
1143 protected String getAuthorityItemCommonSchemaName() {
1144 return authorityItemCommonSchemaName;