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());
237 // handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
238 // refName includes displayName, so we force a correct value here.
239 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
243 * Note that the Vocabulary service's document-model for items overrides this method.
245 protected String getPrimaryDisplayName(DocumentModel docModel, String schema,
246 String complexPropertyName, String fieldName) {
247 String result = null;
249 result = getStringValueInPrimaryRepeatingComplexProperty(docModel, schema, complexPropertyName, fieldName);
255 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
258 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
259 // First, get a copy of the old displayName
260 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
261 // AuthorityItemJAXBSchema.DISPLAY_NAME);
262 oldDisplayNameOnUpdate = getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
263 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
264 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
265 AuthorityItemJAXBSchema.REF_NAME);
266 super.handleUpdate(wrapDoc);
268 // Now, check the new display and handle the refname update.
269 String newDisplayName = (String) getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
270 authorityItemTermGroupXPathBase,
271 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
272 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
273 // Need to update the refName, and then fix all references.
274 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
276 // Mark as not needing attention in completeUpdate phase.
277 newRefNameOnUpdate = null;
278 oldRefNameOnUpdate = null;
283 * Handle display name.
285 * @param docModel the doc model
286 * @throws Exception the exception
288 // protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
289 // // Do nothing by default.
293 * Handle refName updates for changes to display name.
294 * Assumes refName is already correct. Just ensures it is right.
296 * @param docModel the doc model
297 * @param newDisplayName the new display name
298 * @throws Exception the exception
300 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
301 String newDisplayName) throws Exception {
302 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
303 if (authItem == null) {
304 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
306 throw new IllegalArgumentException(err);
308 authItem.displayName = newDisplayName;
309 String updatedRefName = authItem.toString();
310 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
311 return updatedRefName;
315 * Note: The Vocabulary document handler overrides this method.
317 protected String getRefPropName() {
318 return ServiceBindingUtils.AUTH_REF_PROP;
322 * Checks to see if the refName has changed, and if so,
323 * uses utilities to find all references and update them.
326 protected void handleItemRefNameReferenceUpdate() throws Exception {
327 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
328 // We have work to do.
329 if (logger.isDebugEnabled()) {
330 String eol = System.getProperty("line.separator");
331 logger.debug("Need to find and update references to Item." + eol
332 + " Old refName" + oldRefNameOnUpdate + eol
333 + " New refName" + newRefNameOnUpdate);
335 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
336 RepositoryClient repoClient = getRepositoryClient(ctx);
337 String refNameProp = getRefPropName();
339 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
340 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
341 if (logger.isDebugEnabled()) {
342 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
348 * If no short identifier was provided in the input payload, generate a
349 * short identifier from the preferred term display name or term name.
351 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel,
352 String schemaName) throws Exception {
353 String shortIdentifier = (String) docModel.getProperty(schemaName,
354 AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
356 String termDisplayName = getPrimaryDisplayName(
357 docModel, authorityItemCommonSchemaName,
358 getItemTermInfoGroupXPathBase(),
359 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
361 String termName = getPrimaryDisplayName(
362 docModel, authorityItemCommonSchemaName,
363 getItemTermInfoGroupXPathBase(),
364 AuthorityItemJAXBSchema.TERM_NAME);
366 if (Tools.isEmpty(shortIdentifier)) {
367 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName,
369 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER,
370 generatedShortIdentifier);
375 * Generate a refName for the authority item from the short identifier
378 * All refNames for authority items are generated. If a client supplies
379 * a refName, it will be overwritten during create (per this method)
380 * or discarded during update (per filterReadOnlyPropertiesForPart).
382 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
385 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
387 String authorityRefBaseName) throws Exception {
388 DocumentModel docModel = wrapDoc.getWrappedObject();
389 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
390 String displayName = getPrimaryDisplayName(docModel, authorityItemCommonSchemaName,
391 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
393 if (Tools.isEmpty(authorityRefBaseName)) {
394 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
397 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
398 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
399 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
403 * Check the logic around the parent pointer. Note that we only need do this on
404 * create, since we have logic to make this read-only on update.
408 * @throws Exception the exception
410 private void handleInAuthority(DocumentModel docModel) throws Exception {
411 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
412 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
414 docModel.setProperty(authorityItemCommonSchemaName,
415 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
419 public AuthorityRefDocList getReferencingObjects(
420 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
421 List<String> serviceTypes,
423 String itemcsid) throws Exception {
424 AuthorityRefDocList authRefDocList = null;
425 RepositoryInstance repoSession = null;
426 boolean releaseRepoSession = false;
429 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
430 repoSession = this.getRepositorySession();
431 if (repoSession == null) {
432 repoSession = repoClient.getRepositorySession();
433 releaseRepoSession = true;
435 DocumentFilter myFilter = getDocumentFilter();
438 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
439 DocumentModel docModel = wrapper.getWrappedObject();
440 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
441 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
442 repoSession, ctx, repoClient,
446 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
447 } catch (PropertyException pe) {
449 } catch (DocumentException de) {
451 } catch (Exception e) {
452 if (logger.isDebugEnabled()) {
453 logger.debug("Caught exception ", e);
455 throw new DocumentException(e);
457 if (releaseRepoSession && repoSession != null) {
458 repoClient.releaseRepositorySession(repoSession);
461 } catch (Exception e) {
462 if (logger.isDebugEnabled()) {
463 logger.debug("Caught exception ", e);
465 throw new DocumentException(e);
467 return authRefDocList;
474 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
477 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
479 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
481 // Add the CSID to the common part, since they may have fetched via the shortId.
482 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
483 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
484 unQObjectProperties.put("csid", csid);
487 return unQObjectProperties;
491 * Filters out selected values supplied in an update request.
493 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
494 * that the link to the item's parent remains untouched.
496 * @param objectProps the properties filtered out from the update payload
497 * @param partMeta metadata for the object to fill
500 public void filterReadOnlyPropertiesForPart(
501 Map<String, Object> objectProps, ObjectPartType partMeta) {
502 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
503 String commonPartLabel = getServiceContext().getCommonPartLabel();
504 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
505 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
506 objectProps.remove(AuthorityItemJAXBSchema.CSID);
507 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
508 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
513 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
514 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
515 super.extractAllParts(wrapDoc);
517 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
518 if (Tools.isTrue(showSiblings)) {
519 showSiblings(wrapDoc, ctx);
520 return; // actual result is returned on ctx.addOutputPart();
523 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
524 if (Tools.isTrue(showRelations)) {
525 showRelations(wrapDoc, ctx);
526 return; // actual result is returned on ctx.addOutputPart();
529 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
530 if (Tools.isTrue(showAllRelations)) {
531 showAllRelations(wrapDoc, ctx);
532 return; // actual result is returned on ctx.addOutputPart();
536 /** @return null on parent not found
538 protected String getParentCSID(String thisCSID) throws Exception {
539 String parentCSID = null;
541 String predicate = RelationshipType.HAS_BROADER.value();
542 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
543 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
544 if (parentList != null) {
545 if (parentList.size() == 0) {
548 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
549 parentCSID = relationListItem.getObjectCsid();
552 } catch (Exception e) {
553 logger.error("Could not find parent for this: " + thisCSID, e);
558 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
559 MultipartServiceContext ctx) throws Exception {
560 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
562 String predicate = RelationshipType.HAS_BROADER.value();
563 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
564 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
566 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
567 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
569 if(logger.isTraceEnabled()) {
570 String dump = dumpLists(thisCSID, parentList, childrenList, null);
571 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
574 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
575 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
576 //Not optimal, but that's the current design spec.
578 for (RelationsCommonList.RelationListItem parent : parentList) {
579 childrenList.add(parent);
582 long childrenSize = childrenList.size();
583 childrenListOuter.setTotalItems(childrenSize);
584 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
586 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
587 ctx.addOutputPart(relationsPart);
590 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
591 MultipartServiceContext ctx) throws Exception {
592 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
593 String parentCSID = getParentCSID(thisCSID);
594 if (parentCSID == null) {
595 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
599 String predicate = RelationshipType.HAS_BROADER.value();
600 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
601 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
603 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
606 RelationsCommonList.RelationListItem item = null;
607 for (RelationsCommonList.RelationListItem sibling : siblingList) {
608 if (thisCSID.equals(sibling.getSubjectCsid())) {
609 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.
612 //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.
613 for (RelationsCommonList.RelationListItem self : toRemoveList) {
614 removeFromList(siblingList, self);
617 long siblingSize = siblingList.size();
618 siblingListOuter.setTotalItems(siblingSize);
619 siblingListOuter.setItemsInPage(siblingSize);
620 if(logger.isTraceEnabled()) {
621 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
622 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
625 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
626 ctx.addOutputPart(relationsPart);
629 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
630 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
632 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
633 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
635 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
636 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
638 if(logger.isTraceEnabled()) {
639 String dump = dumpLists(thisCSID, subjectList, objectList, null);
640 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
643 subjectList.addAll(objectList);
645 //now subjectList actually has records BOTH where thisCSID is subject and object.
646 long relatedSize = subjectList.size();
647 subjectListOuter.setTotalItems(relatedSize);
648 subjectListOuter.setItemsInPage(relatedSize);
650 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
651 ctx.addOutputPart(relationsPart);
654 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
655 super.fillAllParts(wrapDoc, action);
657 ServiceContext ctx = getServiceContext();
658 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
659 DocumentModel documentModel = (wrapDoc.getWrappedObject());
660 String itemCsid = documentModel.getName();
662 //UPDATE and CREATE will call. Updates relations part
663 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
665 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
666 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
670 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
671 super.completeCreate(wrapDoc);
672 handleRelationsPayload(wrapDoc, false);
675 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
676 super.completeUpdate(wrapDoc);
677 handleRelationsPayload(wrapDoc, true);
678 handleItemRefNameReferenceUpdate();
681 // Note that we must do this after we have completed the Update, so that the repository has the
682 // info for the item itself. The relations code must call into the repo to get info for each end.
683 // This could be optimized to pass in the parent docModel, since it will often be one end.
684 // Nevertheless, we should complete the item save before we do work on the relations, especially
685 // since a save on Create might fail, and we would not want to create relations for something
686 // that may not be created...
687 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
688 ServiceContext ctx = getServiceContext();
689 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
690 DocumentModel documentModel = (wrapDoc.getWrappedObject());
691 String itemCsid = documentModel.getName();
693 //Updates relations part
694 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
696 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
697 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
699 //now we add part for relations list
700 //ServiceContext ctx = getServiceContext();
701 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
702 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
705 /** updateRelations strategy:
707 go through inboundList, remove anything from childList that matches from childList
708 go through inboundList, remove anything from parentList that matches from parentList
709 go through parentList, delete all remaining
710 go through childList, delete all remaining
711 go through actionList, add all remaining.
712 check for duplicate children
713 check for more than one parent.
715 inboundList parentList childList actionList
716 ---------------- --------------- ---------------- ----------------
717 child-a parent-c child-a child-b
718 child-b parent-d child-c
721 private RelationsCommonList updateRelations(
722 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
724 if (logger.isTraceEnabled()) {
725 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
727 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
729 return null; //nothing to do--they didn't send a list of relations.
731 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
732 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
733 List<RelationsCommonList.RelationListItem> actionList = newList();
734 List<RelationsCommonList.RelationListItem> childList = null;
735 List<RelationsCommonList.RelationListItem> parentList = null;
736 DocumentModel docModel = wrapDoc.getWrappedObject();
737 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
739 ServiceContext ctx = getServiceContext();
740 //Do magic replacement of ${itemCSID} and fix URI's.
741 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
743 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
744 UriInfo uriInfo = ctx.getUriInfo();
745 MultivaluedMap queryParams = uriInfo.getQueryParameters();
748 //Run getList() once as sent to get childListOuter:
749 String predicate = RelationshipType.HAS_BROADER.value();
750 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
751 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
752 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
753 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
754 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
755 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
757 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
758 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
759 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
760 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
761 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
764 childList = childListOuter.getRelationListItem();
765 parentList = parentListOuter.getRelationListItem();
767 if (parentList.size() > 1) {
768 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
771 if (logger.isTraceEnabled()) {
772 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
777 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
778 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
779 // and so the CSID for those may be null
780 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
781 // Look for parents and children
782 if(itemCSID.equals(inboundItem.getObject().getCsid())
783 || itemRefName.equals(inboundItem.getObject().getRefName())) {
784 //then this is an item that says we have a child. That child is inboundItem
785 RelationsCommonList.RelationListItem childItem =
786 (childList == null) ? null : findInList(childList, inboundItem);
787 if (childItem != null) {
788 if (logger.isTraceEnabled()) {
789 StringBuilder sb = new StringBuilder();
790 itemToString(sb, "== Child: ", childItem);
791 logger.trace("Found inboundChild in current child list: " + sb.toString());
793 removeFromList(childList, childItem); //exists, just take it off delete list
795 if (logger.isTraceEnabled()) {
796 StringBuilder sb = new StringBuilder();
797 itemToString(sb, "== Child: ", inboundItem);
798 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
800 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
801 String newChildCsid = inboundItem.getSubject().getCsid();
802 if(newChildCsid == null) {
803 String newChildRefName = inboundItem.getSubject().getRefName();
804 if(newChildRefName==null) {
805 throw new RuntimeException("Child with no CSID or refName!");
807 if (logger.isTraceEnabled()) {
808 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
810 DocumentModel newChildDocModel =
811 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
812 newChildRefName, getServiceContext().getResourceMap());
813 newChildCsid = getCsid(newChildDocModel);
815 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
818 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
819 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
820 //then this is an item that says we have a parent. inboundItem is that parent.
821 RelationsCommonList.RelationListItem parentItem =
822 (parentList == null) ? null : findInList(parentList, inboundItem);
823 if (parentItem != null) {
824 removeFromList(parentList, parentItem); //exists, just take it off delete list
826 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
829 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
832 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
835 if (logger.isTraceEnabled()) {
836 String dump = dumpLists(itemCSID, parentList, childList, actionList);
837 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
840 if (logger.isTraceEnabled()) {
841 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
842 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
844 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
845 deleteRelations(childList, ctx, "childList");
847 if (logger.isTraceEnabled()) {
848 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
849 + actionList.size() + " new parents and children.");
851 createRelations(actionList, ctx);
852 if (logger.isTraceEnabled()) {
853 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
855 //We return all elements on the inbound list, since we have just worked to make them exist in the system
856 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
857 return relationsCommonListBody;
860 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
861 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
862 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
863 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
864 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
865 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
866 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
867 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
868 deleteRelations(parentList, ctx, "parentList-delete");
872 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
874 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
876 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
878 sb.append(item.getPredicate());
880 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
884 private String dumpLists(String itemCSID,
885 List<RelationsCommonList.RelationListItem> parentList,
886 List<RelationsCommonList.RelationListItem> childList,
887 List<RelationsCommonList.RelationListItem> actionList) {
888 StringBuilder sb = new StringBuilder();
889 sb.append("itemCSID: " + itemCSID + CR);
890 if(parentList!=null) {
891 sb.append(dumpList(parentList, "parentList"));
893 if(childList!=null) {
894 sb.append(dumpList(childList, "childList"));
896 if(actionList!=null) {
897 sb.append(dumpList(actionList, "actionList"));
899 return sb.toString();
901 private final static String CR = "\r\n";
902 private final static String T = " ";
904 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
905 StringBuilder sb = new StringBuilder();
907 if (list.size() > 0) {
908 sb.append("=========== " + label + " ==========" + CR);
910 for (RelationsCommonList.RelationListItem item : list) {
911 itemToString(sb, "== ", item);
914 return sb.toString();
917 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
918 * and sets URI correctly for related items.
919 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
921 protected void fixupInboundListItems(ServiceContext ctx,
922 List<RelationsCommonList.RelationListItem> inboundList,
923 DocumentModel docModel,
924 String itemCSID) throws Exception {
925 String thisURI = this.getUri(docModel);
926 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
927 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
928 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
929 RelationsDocListItem inboundItemObject = inboundItem.getObject();
930 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
932 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
933 inboundItem.setObjectCsid(itemCSID);
934 inboundItemObject.setCsid(itemCSID);
935 //inboundItemObject.setUri(getUri(docModel));
938 String objectCsid = inboundItemObject.getCsid();
939 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
940 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
941 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
942 inboundItemObject.setUri(uri); //CSPACE-4037
945 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
947 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
948 inboundItem.setSubjectCsid(itemCSID);
949 inboundItemSubject.setCsid(itemCSID);
950 //inboundItemSubject.setUri(getUri(docModel));
953 String subjectCsid = inboundItemSubject.getCsid();
954 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
955 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
956 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
957 inboundItemSubject.setUri(uri); //CSPACE-4037
960 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
965 // this method calls the RelationResource to have it create the relations and persist them.
966 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
967 for (RelationsCommonList.RelationListItem item : inboundList) {
968 RelationsCommon rc = new RelationsCommon();
969 //rc.setCsid(item.getCsid());
970 //todo: assignTo(item, rc);
971 RelationsDocListItem itemSubject = item.getSubject();
972 RelationsDocListItem itemObject = item.getObject();
974 // Set at least one of CSID and refName for Subject and Object
975 // Either value might be null for for each of Subject and Object
976 String subjectCsid = itemSubject.getCsid();
977 rc.setSubjectCsid(subjectCsid);
979 String objCsid = itemObject.getCsid();
980 rc.setObjectCsid(objCsid);
982 rc.setSubjectRefName(itemSubject.getRefName());
983 rc.setObjectRefName(itemObject.getRefName());
985 rc.setRelationshipType(item.getPredicate());
986 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
987 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
989 // This is superfluous, since it will be fetched by the Relations Create logic.
990 rc.setSubjectDocumentType(itemSubject.getDocumentType());
991 rc.setObjectDocumentType(itemObject.getDocumentType());
993 // This is superfluous, since it will be fetched by the Relations Create logic.
994 rc.setSubjectUri(itemSubject.getUri());
995 rc.setObjectUri(itemObject.getUri());
996 // May not have the info here. Only really require CSID or refName.
997 // Rest is handled in the Relation create mechanism
998 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
1000 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
1001 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
1002 payloadOut.addPart(outputPart);
1003 RelationResource relationResource = new RelationResource();
1004 Object res = relationResource.create(ctx.getResourceMap(),
1005 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
1009 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
1011 for (RelationsCommonList.RelationListItem item : list) {
1012 RelationResource relationResource = new RelationResource();
1013 if(logger.isTraceEnabled()) {
1014 StringBuilder sb = new StringBuilder();
1015 itemToString(sb, "==== TO DELETE: ", item);
1016 logger.trace(sb.toString());
1018 Object res = relationResource.delete(item.getCsid());
1020 } catch (Throwable t) {
1021 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1026 private List<RelationsCommonList.RelationListItem> newList() {
1027 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1031 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1032 List<RelationsCommonList.RelationListItem> result = newList();
1033 for (RelationsCommonList.RelationListItem item : inboundList) {
1039 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1040 // But the list items must not be sparse
1041 private RelationsCommonList.RelationListItem findInList(
1042 List<RelationsCommonList.RelationListItem> list,
1043 RelationsCommonList.RelationListItem item) {
1044 RelationsCommonList.RelationListItem foundItem = null;
1045 for (RelationsCommonList.RelationListItem listItem : list) {
1046 if (itemsEqual(listItem, item)) { //equals must be defined, else
1047 foundItem = listItem;
1054 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1055 // But item1 must not be sparse
1056 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1057 if (item1 == null || item2 == null) {
1060 RelationsDocListItem subj1 = item1.getSubject();
1061 RelationsDocListItem subj2 = item2.getSubject();
1062 RelationsDocListItem obj1 = item1.getObject();
1063 RelationsDocListItem obj2 = item2.getObject();
1064 String subj1Csid = subj1.getCsid();
1065 String subj2Csid = subj2.getCsid();
1066 String subj1RefName = subj1.getRefName();
1067 String subj2RefName = subj2.getRefName();
1069 String obj1Csid = obj1.getCsid();
1070 String obj2Csid = obj2.getCsid();
1071 String obj1RefName = obj1.getRefName();
1072 String obj2RefName = obj2.getRefName();
1075 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1076 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1077 // predicate is proper, but still allow relationshipType
1078 && (item1.getPredicate().equals(item2.getPredicate())
1079 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1080 // Allow missing docTypes, so long as they do not conflict
1081 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1082 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1086 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1090 /* don't even THINK of re-using this method.
1091 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1093 private String extractInAuthorityCSID(String uri) {
1094 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1095 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1096 Matcher m = p.matcher(uri);
1098 if (m.groupCount() < 3) {
1099 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1102 //String service = m.group(1);
1103 String inauth = m.group(2);
1104 //String theRest = m.group(3);
1106 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1109 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1114 //ensures CSPACE-4042
1115 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1116 String authorityCSID = extractInAuthorityCSID(thisURI);
1117 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1118 if (Tools.isBlank(authorityCSID)
1119 || Tools.isBlank(authorityCSIDForInbound)
1120 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1121 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1125 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1126 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1127 ServiceContext ctx = getServiceContext();
1128 MultivaluedMap queryParams = ctx.getQueryParams();
1129 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1130 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1131 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1133 RelationResource relationResource = new RelationResource();
1134 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1135 return relationsCommonList;
1137 //============================= END TODO refactor ==========================
1139 public String getItemTermInfoGroupXPathBase() {
1140 return authorityItemTermGroupXPathBase;
1143 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1144 authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;
1147 protected String getAuthorityItemCommonSchemaName() {
1148 return authorityItemCommonSchemaName;