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.collectionspace.services.vocabulary.VocabularyItemJAXBSchema;
63 import org.nuxeo.ecm.core.api.ClientException;
64 import org.nuxeo.ecm.core.api.DocumentModel;
65 import org.nuxeo.ecm.core.api.model.PropertyException;
66 import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
67 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
68 import org.nuxeo.runtime.transaction.TransactionHelper;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 import javax.ws.rs.PathParam;
73 import javax.ws.rs.WebApplicationException;
74 import javax.ws.rs.core.Context;
75 import javax.ws.rs.core.MultivaluedMap;
76 import javax.ws.rs.core.Response;
77 import javax.ws.rs.core.UriInfo;
78 import java.util.ArrayList;
79 import java.util.List;
81 import java.util.regex.Matcher;
82 import java.util.regex.Pattern;
83 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
85 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
87 * AuthorityItemDocumentModelHandler
89 * $LastChangedRevision: $
92 public abstract class AuthorityItemDocumentModelHandler<AICommon>
93 extends DocHandlerBase<AICommon> {
95 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
96 private String authorityItemCommonSchemaName;
97 private String authorityItemTermGroupXPathBase;
99 * inVocabulary is the parent Authority for this context
101 protected String inAuthority = null;
102 protected String authorityRefNameBase = null;
103 // Used to determine when the displayName changes as part of the update.
104 protected String oldDisplayNameOnUpdate = null;
105 protected String oldRefNameOnUpdate = null;
106 protected String newRefNameOnUpdate = null;
108 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
109 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
112 public void setInAuthority(String inAuthority) {
113 this.inAuthority = inAuthority;
116 /** Subclasses may override this to customize the URI segment. */
117 public String getAuthorityServicePath() {
118 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
122 public String getUri(DocumentModel docModel) {
123 // Laramie20110510 CSPACE-3932
124 String authorityServicePath = getAuthorityServicePath();
125 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
127 inAuthority = (String) docModel.getProperty(authorityItemCommonSchemaName,
128 AuthorityItemJAXBSchema.IN_AUTHORITY);
129 } catch (ClientException pe) {
130 throw new RuntimeException("Could not get parent specifier for item!");
133 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
136 protected String getAuthorityRefNameBase() {
137 return this.authorityRefNameBase;
140 public void setAuthorityRefNameBase(String value) {
141 this.authorityRefNameBase = value;
145 * Note: the Vocabulary service's VocabularyItemDocumentModelHandler class overrides this method.
147 protected ListResultField getListResultsDisplayNameField() {
148 ListResultField result = new ListResultField();
149 // Per CSPACE-5132, the name of this element remains 'displayName'
150 // for backwards compatibility, although its value is obtained
151 // from the termDisplayName field.
153 // In CSPACE-5134, these list results will change substantially
154 // to return display names for both the preferred term and for
155 // each non-preferred term (if any).
156 result.setElement(AuthorityItemJAXBSchema.DISPLAY_NAME);
157 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
158 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
164 * Note: the Vocabulary service's VocabularyItemDocumentModelHandler class overrides this method.
166 protected ListResultField getListResultsTermStatusField() {
167 ListResultField result = new ListResultField();
169 result.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
170 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
171 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
177 public List<ListResultField> getListItemsArray() throws DocumentException {
178 List<ListResultField> list = super.getListItemsArray();
179 int nFields = list.size();
180 // Ensure that each item in a list of Authority items includes
181 // a set of common fields, so we do not depend upon configuration
182 // for general logic.
183 boolean hasDisplayName = false;
184 boolean hasShortId = false;
185 boolean hasRefName = false;
186 boolean hasTermStatus = false;
187 for (int i = 0; i < nFields; i++) {
188 ListResultField field = list.get(i);
189 String elName = field.getElement();
190 if (AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName) || VocabularyItemJAXBSchema.DISPLAY_NAME.equals(elName)) {
191 hasDisplayName = true;
192 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
194 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
196 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
197 hasTermStatus = true;
200 ListResultField field;
201 if (!hasDisplayName) {
202 field = getListResultsDisplayNameField();
203 list.add(field); //Note: We're updating the "global" service and tenant bindings instance here -the list instance here is a reference to the tenant bindings instance in the singleton ServiceMain.
206 field = new ListResultField();
207 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
208 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
212 field = new ListResultField();
213 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
214 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
217 if (!hasTermStatus) {
218 field = getListResultsTermStatusField();
227 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
230 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
231 // first fill all the parts of the document
232 super.handleCreate(wrapDoc);
233 // Ensure we have required fields set properly
234 handleInAuthority(wrapDoc.getWrappedObject());
236 // FIXME: This call to synthesize a shortIdentifier from the termDisplayName
237 // of the preferred term may have been commented out, in the course of
238 // adding support for preferred / non-preferred terms, in CSPACE-4813
239 // and linked issues. Revisit this to determine whether we want to
243 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
244 // refName includes displayName, so we force a correct value here.
245 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
249 * Note that the Vocabulary service's document-model for items overrides this method.
251 protected String getPrimaryDisplayName(DocumentModel docModel, String schema,
252 String complexPropertyName, String fieldName) {
253 String result = null;
255 result = getStringValueInPrimaryRepeatingComplexProperty(docModel, schema, complexPropertyName, fieldName);
261 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
264 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
265 // First, get a copy of the old displayName
266 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
267 // AuthorityItemJAXBSchema.DISPLAY_NAME);
268 oldDisplayNameOnUpdate = getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
269 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
270 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
271 AuthorityItemJAXBSchema.REF_NAME);
272 super.handleUpdate(wrapDoc);
274 // Now, check the new display and handle the refname update.
275 String newDisplayName = (String) getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
276 authorityItemTermGroupXPathBase,
277 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
278 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
279 // Need to update the refName, and then fix all references.
280 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
282 // Mark as not needing attention in completeUpdate phase.
283 newRefNameOnUpdate = null;
284 oldRefNameOnUpdate = null;
289 * Handle display name.
291 * @param docModel the doc model
292 * @throws Exception the exception
294 // protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
295 // // Do nothing by default.
299 * Handle refName updates for changes to display name.
300 * Assumes refName is already correct. Just ensures it is right.
302 * @param docModel the doc model
303 * @param newDisplayName the new display name
304 * @throws Exception the exception
306 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
307 String newDisplayName) throws Exception {
308 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
309 if (authItem == null) {
310 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
312 throw new IllegalArgumentException(err);
314 authItem.displayName = newDisplayName;
315 String updatedRefName = authItem.toString();
316 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
317 return updatedRefName;
321 * Note: The Vocabulary document handler overrides this method.
323 protected String getRefPropName() {
324 return ServiceBindingUtils.AUTH_REF_PROP;
328 * Checks to see if the refName has changed, and if so,
329 * uses utilities to find all references and update them.
332 protected void handleItemRefNameReferenceUpdate() throws Exception {
333 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
334 // We have work to do.
335 if (logger.isDebugEnabled()) {
336 String eol = System.getProperty("line.separator");
337 logger.debug("Need to find and update references to Item." + eol
338 + " Old refName" + oldRefNameOnUpdate + eol
339 + " New refName" + newRefNameOnUpdate);
341 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
342 RepositoryClient repoClient = getRepositoryClient(ctx);
343 String refNameProp = getRefPropName();
345 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
346 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
347 if (logger.isDebugEnabled()) {
348 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
354 * If no short identifier was provided in the input payload, generate a
355 * short identifier from the preferred term display name or term name.
357 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel,
358 String schemaName) throws Exception {
359 String shortIdentifier = (String) docModel.getProperty(schemaName,
360 AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
362 String termDisplayName = getPrimaryDisplayName(
363 docModel, authorityItemCommonSchemaName,
364 getItemTermInfoGroupXPathBase(),
365 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
367 String termName = getPrimaryDisplayName(
368 docModel, authorityItemCommonSchemaName,
369 getItemTermInfoGroupXPathBase(),
370 AuthorityItemJAXBSchema.TERM_NAME);
372 if (Tools.isEmpty(shortIdentifier)) {
373 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName,
375 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER,
376 generatedShortIdentifier);
381 * Generate a refName for the authority item from the short identifier
384 * All refNames for authority items are generated. If a client supplies
385 * a refName, it will be overwritten during create (per this method)
386 * or discarded during update (per filterReadOnlyPropertiesForPart).
388 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
391 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
393 String authorityRefBaseName) throws Exception {
394 DocumentModel docModel = wrapDoc.getWrappedObject();
395 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
396 String displayName = getPrimaryDisplayName(docModel, authorityItemCommonSchemaName,
397 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
399 if (Tools.isEmpty(authorityRefBaseName)) {
400 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
403 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
404 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
405 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
409 * Check the logic around the parent pointer. Note that we only need do this on
410 * create, since we have logic to make this read-only on update.
414 * @throws Exception the exception
416 private void handleInAuthority(DocumentModel docModel) throws Exception {
417 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
418 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
420 docModel.setProperty(authorityItemCommonSchemaName,
421 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
425 public AuthorityRefDocList getReferencingObjects(
426 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
427 List<String> serviceTypes,
429 String itemcsid) throws Exception {
430 AuthorityRefDocList authRefDocList = null;
431 RepositoryInstance repoSession = null;
432 boolean releaseRepoSession = false;
435 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
436 repoSession = this.getRepositorySession();
437 if (repoSession == null) {
438 repoSession = repoClient.getRepositorySession();
439 releaseRepoSession = true;
441 DocumentFilter myFilter = getDocumentFilter();
444 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
445 DocumentModel docModel = wrapper.getWrappedObject();
446 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
447 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
448 repoSession, ctx, repoClient,
452 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
453 } catch (PropertyException pe) {
455 } catch (DocumentException de) {
457 } catch (Exception e) {
458 if (logger.isDebugEnabled()) {
459 logger.debug("Caught exception ", e);
461 throw new DocumentException(e);
463 if (releaseRepoSession && repoSession != null) {
464 repoClient.releaseRepositorySession(repoSession);
467 } catch (Exception e) {
468 if (logger.isDebugEnabled()) {
469 logger.debug("Caught exception ", e);
471 throw new DocumentException(e);
473 return authRefDocList;
480 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
483 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
485 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
487 // Add the CSID to the common part, since they may have fetched via the shortId.
488 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
489 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
490 unQObjectProperties.put("csid", csid);
493 return unQObjectProperties;
497 * Filters out selected values supplied in an update request.
499 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
500 * that the link to the item's parent remains untouched.
502 * @param objectProps the properties filtered out from the update payload
503 * @param partMeta metadata for the object to fill
506 public void filterReadOnlyPropertiesForPart(
507 Map<String, Object> objectProps, ObjectPartType partMeta) {
508 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
509 String commonPartLabel = getServiceContext().getCommonPartLabel();
510 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
511 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
512 objectProps.remove(AuthorityItemJAXBSchema.CSID);
513 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
514 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
519 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
520 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
521 super.extractAllParts(wrapDoc);
523 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
524 if (Tools.isTrue(showSiblings)) {
525 showSiblings(wrapDoc, ctx);
526 return; // actual result is returned on ctx.addOutputPart();
529 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
530 if (Tools.isTrue(showRelations)) {
531 showRelations(wrapDoc, ctx);
532 return; // actual result is returned on ctx.addOutputPart();
535 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
536 if (Tools.isTrue(showAllRelations)) {
537 showAllRelations(wrapDoc, ctx);
538 return; // actual result is returned on ctx.addOutputPart();
542 /** @return null on parent not found
544 protected String getParentCSID(String thisCSID) throws Exception {
545 String parentCSID = null;
547 String predicate = RelationshipType.HAS_BROADER.value();
548 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
549 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
550 if (parentList != null) {
551 if (parentList.size() == 0) {
554 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
555 parentCSID = relationListItem.getObjectCsid();
558 } catch (Exception e) {
559 logger.error("Could not find parent for this: " + thisCSID, e);
564 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
565 MultipartServiceContext ctx) throws Exception {
566 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
568 String predicate = RelationshipType.HAS_BROADER.value();
569 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
570 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
572 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
573 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
575 if(logger.isTraceEnabled()) {
576 String dump = dumpLists(thisCSID, parentList, childrenList, null);
577 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
580 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
581 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
582 //Not optimal, but that's the current design spec.
584 for (RelationsCommonList.RelationListItem parent : parentList) {
585 childrenList.add(parent);
588 long childrenSize = childrenList.size();
589 childrenListOuter.setTotalItems(childrenSize);
590 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
592 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
593 ctx.addOutputPart(relationsPart);
596 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
597 MultipartServiceContext ctx) throws Exception {
598 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
599 String parentCSID = getParentCSID(thisCSID);
600 if (parentCSID == null) {
601 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
605 String predicate = RelationshipType.HAS_BROADER.value();
606 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
607 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
609 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
612 RelationsCommonList.RelationListItem item = null;
613 for (RelationsCommonList.RelationListItem sibling : siblingList) {
614 if (thisCSID.equals(sibling.getSubjectCsid())) {
615 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.
618 //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.
619 for (RelationsCommonList.RelationListItem self : toRemoveList) {
620 removeFromList(siblingList, self);
623 long siblingSize = siblingList.size();
624 siblingListOuter.setTotalItems(siblingSize);
625 siblingListOuter.setItemsInPage(siblingSize);
626 if(logger.isTraceEnabled()) {
627 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
628 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
631 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
632 ctx.addOutputPart(relationsPart);
635 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
636 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
638 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
639 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
641 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
642 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
644 if(logger.isTraceEnabled()) {
645 String dump = dumpLists(thisCSID, subjectList, objectList, null);
646 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
649 subjectList.addAll(objectList);
651 //now subjectList actually has records BOTH where thisCSID is subject and object.
652 long relatedSize = subjectList.size();
653 subjectListOuter.setTotalItems(relatedSize);
654 subjectListOuter.setItemsInPage(relatedSize);
656 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
657 ctx.addOutputPart(relationsPart);
661 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
663 // We currently don't override this method with any AuthorityItemDocumentModelHandler specific functionality, so
664 // we could remove this method.
666 super.fillAllParts(wrapDoc, action);
670 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
671 super.completeCreate(wrapDoc);
672 handleRelationsPayload(wrapDoc, false);
676 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
677 super.completeUpdate(wrapDoc);
678 handleRelationsPayload(wrapDoc, true);
679 handleItemRefNameReferenceUpdate();
682 // Note that we must do this after we have completed the Update, so that the repository has the
683 // info for the item itself. The relations code must call into the repo to get info for each end.
684 // This could be optimized to pass in the parent docModel, since it will often be one end.
685 // Nevertheless, we should complete the item save before we do work on the relations, especially
686 // since a save on Create might fail, and we would not want to create relations for something
687 // that may not be created...
688 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
689 ServiceContext ctx = getServiceContext();
690 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
691 DocumentModel documentModel = (wrapDoc.getWrappedObject());
692 String itemCsid = documentModel.getName();
694 //Updates relations part
695 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
697 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList); //FIXME: REM - We should check for a null relationsCommonList and not create the new common list payload
698 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
700 //now we add part for relations list
701 //ServiceContext ctx = getServiceContext();
702 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
703 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
706 /** updateRelations strategy:
708 go through inboundList, remove anything from childList that matches from childList
709 go through inboundList, remove anything from parentList that matches from parentList
710 go through parentList, delete all remaining
711 go through childList, delete all remaining
712 go through actionList, add all remaining.
713 check for duplicate children
714 check for more than one parent.
716 inboundList parentList childList actionList
717 ---------------- --------------- ---------------- ----------------
718 child-a parent-c child-a child-b
719 child-b parent-d child-c
722 private RelationsCommonList updateRelations(
723 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
725 if (logger.isTraceEnabled()) {
726 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
728 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
730 return null; //nothing to do--they didn't send a list of relations.
732 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
733 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
734 List<RelationsCommonList.RelationListItem> actionList = newList();
735 List<RelationsCommonList.RelationListItem> childList = null;
736 List<RelationsCommonList.RelationListItem> parentList = null;
737 DocumentModel docModel = wrapDoc.getWrappedObject();
738 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
740 ServiceContext ctx = getServiceContext();
741 //Do magic replacement of ${itemCSID} and fix URI's.
742 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
744 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
745 UriInfo uriInfo = ctx.getUriInfo();
746 MultivaluedMap queryParams = uriInfo.getQueryParameters();
749 //Run getList() once as sent to get childListOuter:
750 String predicate = RelationshipType.HAS_BROADER.value();
751 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
752 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
753 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
754 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
755 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
756 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
758 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
759 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
760 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
761 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
762 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
765 childList = childListOuter.getRelationListItem();
766 parentList = parentListOuter.getRelationListItem();
768 if (parentList.size() > 1) {
769 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
772 if (logger.isTraceEnabled()) {
773 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
778 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
779 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
780 // and so the CSID for those may be null
781 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
782 // Look for parents and children
783 if(itemCSID.equals(inboundItem.getObject().getCsid())
784 || itemRefName.equals(inboundItem.getObject().getRefName())) {
785 //then this is an item that says we have a child. That child is inboundItem
786 RelationsCommonList.RelationListItem childItem =
787 (childList == null) ? null : findInList(childList, inboundItem);
788 if (childItem != null) {
789 if (logger.isTraceEnabled()) {
790 StringBuilder sb = new StringBuilder();
791 itemToString(sb, "== Child: ", childItem);
792 logger.trace("Found inboundChild in current child list: " + sb.toString());
794 removeFromList(childList, childItem); //exists, just take it off delete list
796 if (logger.isTraceEnabled()) {
797 StringBuilder sb = new StringBuilder();
798 itemToString(sb, "== Child: ", inboundItem);
799 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
801 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
802 String newChildCsid = inboundItem.getSubject().getCsid();
803 if(newChildCsid == null) {
804 String newChildRefName = inboundItem.getSubject().getRefName();
805 if(newChildRefName==null) {
806 throw new RuntimeException("Child with no CSID or refName!");
808 if (logger.isTraceEnabled()) {
809 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
811 DocumentModel newChildDocModel =
812 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
813 newChildRefName, getServiceContext().getResourceMap());
814 newChildCsid = getCsid(newChildDocModel);
816 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
819 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
820 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
821 //then this is an item that says we have a parent. inboundItem is that parent.
822 RelationsCommonList.RelationListItem parentItem =
823 (parentList == null) ? null : findInList(parentList, inboundItem);
824 if (parentItem != null) {
825 removeFromList(parentList, parentItem); //exists, just take it off delete list
827 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
830 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
833 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
836 if (logger.isTraceEnabled()) {
837 String dump = dumpLists(itemCSID, parentList, childList, actionList);
838 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
841 if (logger.isTraceEnabled()) {
842 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
843 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
845 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
846 deleteRelations(childList, ctx, "childList");
848 if (logger.isTraceEnabled()) {
849 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
850 + actionList.size() + " new parents and children.");
852 createRelations(actionList, ctx);
853 if (logger.isTraceEnabled()) {
854 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
856 //We return all elements on the inbound list, since we have just worked to make them exist in the system
857 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
858 return relationsCommonListBody;
861 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
862 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
863 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
864 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
865 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
866 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
867 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
868 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
869 deleteRelations(parentList, ctx, "parentList-delete");
873 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
875 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
877 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
879 sb.append(item.getPredicate());
881 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
885 private String dumpLists(String itemCSID,
886 List<RelationsCommonList.RelationListItem> parentList,
887 List<RelationsCommonList.RelationListItem> childList,
888 List<RelationsCommonList.RelationListItem> actionList) {
889 StringBuilder sb = new StringBuilder();
890 sb.append("itemCSID: " + itemCSID + CR);
891 if(parentList!=null) {
892 sb.append(dumpList(parentList, "parentList"));
894 if(childList!=null) {
895 sb.append(dumpList(childList, "childList"));
897 if(actionList!=null) {
898 sb.append(dumpList(actionList, "actionList"));
900 return sb.toString();
902 private final static String CR = "\r\n";
903 private final static String T = " ";
905 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
906 StringBuilder sb = new StringBuilder();
908 if (list.size() > 0) {
909 sb.append("=========== " + label + " ==========" + CR);
911 for (RelationsCommonList.RelationListItem item : list) {
912 itemToString(sb, "== ", item);
915 return sb.toString();
918 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
919 * and sets URI correctly for related items.
920 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
922 protected void fixupInboundListItems(ServiceContext ctx,
923 List<RelationsCommonList.RelationListItem> inboundList,
924 DocumentModel docModel,
925 String itemCSID) throws Exception {
926 String thisURI = this.getUri(docModel);
927 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
928 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
929 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
930 RelationsDocListItem inboundItemObject = inboundItem.getObject();
931 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
933 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
934 inboundItem.setObjectCsid(itemCSID);
935 inboundItemObject.setCsid(itemCSID);
936 //inboundItemObject.setUri(getUri(docModel));
939 String objectCsid = inboundItemObject.getCsid();
940 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
941 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
942 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
943 inboundItemObject.setUri(uri); //CSPACE-4037
946 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
948 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
949 inboundItem.setSubjectCsid(itemCSID);
950 inboundItemSubject.setCsid(itemCSID);
951 //inboundItemSubject.setUri(getUri(docModel));
954 String subjectCsid = inboundItemSubject.getCsid();
955 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
956 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
957 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
958 inboundItemSubject.setUri(uri); //CSPACE-4037
961 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
966 // this method calls the RelationResource to have it create the relations and persist them.
967 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
968 for (RelationsCommonList.RelationListItem item : inboundList) {
969 RelationsCommon rc = new RelationsCommon();
970 //rc.setCsid(item.getCsid());
971 //todo: assignTo(item, rc);
972 RelationsDocListItem itemSubject = item.getSubject();
973 RelationsDocListItem itemObject = item.getObject();
975 // Set at least one of CSID and refName for Subject and Object
976 // Either value might be null for for each of Subject and Object
977 String subjectCsid = itemSubject.getCsid();
978 rc.setSubjectCsid(subjectCsid);
980 String objCsid = itemObject.getCsid();
981 rc.setObjectCsid(objCsid);
983 rc.setSubjectRefName(itemSubject.getRefName());
984 rc.setObjectRefName(itemObject.getRefName());
986 rc.setRelationshipType(item.getPredicate());
987 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
988 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
990 // This is superfluous, since it will be fetched by the Relations Create logic.
991 rc.setSubjectDocumentType(itemSubject.getDocumentType());
992 rc.setObjectDocumentType(itemObject.getDocumentType());
994 // This is superfluous, since it will be fetched by the Relations Create logic.
995 rc.setSubjectUri(itemSubject.getUri());
996 rc.setObjectUri(itemObject.getUri());
997 // May not have the info here. Only really require CSID or refName.
998 // Rest is handled in the Relation create mechanism
999 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
1001 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
1002 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
1003 payloadOut.addPart(outputPart);
1004 RelationResource relationResource = new RelationResource();
1005 Object res = relationResource.create(ctx.getResourceMap(),
1006 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
1010 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
1012 for (RelationsCommonList.RelationListItem item : list) {
1013 RelationResource relationResource = new RelationResource();
1014 if(logger.isTraceEnabled()) {
1015 StringBuilder sb = new StringBuilder();
1016 itemToString(sb, "==== TO DELETE: ", item);
1017 logger.trace(sb.toString());
1019 Object res = relationResource.delete(item.getCsid());
1021 } catch (Throwable t) {
1022 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1027 private List<RelationsCommonList.RelationListItem> newList() {
1028 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1032 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1033 List<RelationsCommonList.RelationListItem> result = newList();
1034 for (RelationsCommonList.RelationListItem item : inboundList) {
1040 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1041 // But the list items must not be sparse
1042 private RelationsCommonList.RelationListItem findInList(
1043 List<RelationsCommonList.RelationListItem> list,
1044 RelationsCommonList.RelationListItem item) {
1045 RelationsCommonList.RelationListItem foundItem = null;
1046 for (RelationsCommonList.RelationListItem listItem : list) {
1047 if (itemsEqual(listItem, item)) { //equals must be defined, else
1048 foundItem = listItem;
1055 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1056 // But item1 must not be sparse
1057 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1058 if (item1 == null || item2 == null) {
1061 RelationsDocListItem subj1 = item1.getSubject();
1062 RelationsDocListItem subj2 = item2.getSubject();
1063 RelationsDocListItem obj1 = item1.getObject();
1064 RelationsDocListItem obj2 = item2.getObject();
1065 String subj1Csid = subj1.getCsid();
1066 String subj2Csid = subj2.getCsid();
1067 String subj1RefName = subj1.getRefName();
1068 String subj2RefName = subj2.getRefName();
1070 String obj1Csid = obj1.getCsid();
1071 String obj2Csid = obj2.getCsid();
1072 String obj1RefName = obj1.getRefName();
1073 String obj2RefName = obj2.getRefName();
1076 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1077 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1078 // predicate is proper, but still allow relationshipType
1079 && (item1.getPredicate().equals(item2.getPredicate())
1080 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1081 // Allow missing docTypes, so long as they do not conflict
1082 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1083 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1087 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1091 /* don't even THINK of re-using this method.
1092 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1094 private String extractInAuthorityCSID(String uri) {
1095 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1096 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1097 Matcher m = p.matcher(uri);
1099 if (m.groupCount() < 3) {
1100 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1103 //String service = m.group(1);
1104 String inauth = m.group(2);
1105 //String theRest = m.group(3);
1107 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1110 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1115 //ensures CSPACE-4042
1116 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1117 String authorityCSID = extractInAuthorityCSID(thisURI);
1118 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1119 if (Tools.isBlank(authorityCSID)
1120 || Tools.isBlank(authorityCSIDForInbound)
1121 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1122 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1126 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1127 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1128 ServiceContext ctx = getServiceContext();
1129 MultivaluedMap queryParams = ctx.getQueryParams();
1130 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1131 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1132 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1134 RelationResource relationResource = new RelationResource();
1135 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1136 return relationsCommonList;
1138 //============================= END TODO refactor ==========================
1140 public String getItemTermInfoGroupXPathBase() {
1141 return authorityItemTermGroupXPathBase;
1144 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1145 authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;
1148 protected String getAuthorityItemCommonSchemaName() {
1149 return authorityItemCommonSchemaName;