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);
660 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
661 super.fillAllParts(wrapDoc, action);
663 ServiceContext ctx = getServiceContext();
664 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
665 DocumentModel documentModel = (wrapDoc.getWrappedObject());
666 String itemCsid = documentModel.getName();
668 //UPDATE and CREATE will call. Updates relations part
669 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
671 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
672 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
676 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
677 super.completeCreate(wrapDoc);
678 handleRelationsPayload(wrapDoc, false);
681 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
682 super.completeUpdate(wrapDoc);
683 handleRelationsPayload(wrapDoc, true);
684 handleItemRefNameReferenceUpdate();
687 // Note that we must do this after we have completed the Update, so that the repository has the
688 // info for the item itself. The relations code must call into the repo to get info for each end.
689 // This could be optimized to pass in the parent docModel, since it will often be one end.
690 // Nevertheless, we should complete the item save before we do work on the relations, especially
691 // since a save on Create might fail, and we would not want to create relations for something
692 // that may not be created...
693 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
694 ServiceContext ctx = getServiceContext();
695 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
696 DocumentModel documentModel = (wrapDoc.getWrappedObject());
697 String itemCsid = documentModel.getName();
699 //Updates relations part
700 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
702 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
703 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
705 //now we add part for relations list
706 //ServiceContext ctx = getServiceContext();
707 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
708 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
711 /** updateRelations strategy:
713 go through inboundList, remove anything from childList that matches from childList
714 go through inboundList, remove anything from parentList that matches from parentList
715 go through parentList, delete all remaining
716 go through childList, delete all remaining
717 go through actionList, add all remaining.
718 check for duplicate children
719 check for more than one parent.
721 inboundList parentList childList actionList
722 ---------------- --------------- ---------------- ----------------
723 child-a parent-c child-a child-b
724 child-b parent-d child-c
727 private RelationsCommonList updateRelations(
728 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
730 if (logger.isTraceEnabled()) {
731 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
733 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
735 return null; //nothing to do--they didn't send a list of relations.
737 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
738 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
739 List<RelationsCommonList.RelationListItem> actionList = newList();
740 List<RelationsCommonList.RelationListItem> childList = null;
741 List<RelationsCommonList.RelationListItem> parentList = null;
742 DocumentModel docModel = wrapDoc.getWrappedObject();
743 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
745 ServiceContext ctx = getServiceContext();
746 //Do magic replacement of ${itemCSID} and fix URI's.
747 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
749 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
750 UriInfo uriInfo = ctx.getUriInfo();
751 MultivaluedMap queryParams = uriInfo.getQueryParameters();
754 //Run getList() once as sent to get childListOuter:
755 String predicate = RelationshipType.HAS_BROADER.value();
756 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
757 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
758 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
759 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
760 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
761 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
763 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
764 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
765 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
766 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
767 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
770 childList = childListOuter.getRelationListItem();
771 parentList = parentListOuter.getRelationListItem();
773 if (parentList.size() > 1) {
774 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
777 if (logger.isTraceEnabled()) {
778 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
783 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
784 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
785 // and so the CSID for those may be null
786 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
787 // Look for parents and children
788 if(itemCSID.equals(inboundItem.getObject().getCsid())
789 || itemRefName.equals(inboundItem.getObject().getRefName())) {
790 //then this is an item that says we have a child. That child is inboundItem
791 RelationsCommonList.RelationListItem childItem =
792 (childList == null) ? null : findInList(childList, inboundItem);
793 if (childItem != null) {
794 if (logger.isTraceEnabled()) {
795 StringBuilder sb = new StringBuilder();
796 itemToString(sb, "== Child: ", childItem);
797 logger.trace("Found inboundChild in current child list: " + sb.toString());
799 removeFromList(childList, childItem); //exists, just take it off delete list
801 if (logger.isTraceEnabled()) {
802 StringBuilder sb = new StringBuilder();
803 itemToString(sb, "== Child: ", inboundItem);
804 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
806 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
807 String newChildCsid = inboundItem.getSubject().getCsid();
808 if(newChildCsid == null) {
809 String newChildRefName = inboundItem.getSubject().getRefName();
810 if(newChildRefName==null) {
811 throw new RuntimeException("Child with no CSID or refName!");
813 if (logger.isTraceEnabled()) {
814 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
816 DocumentModel newChildDocModel =
817 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
818 newChildRefName, getServiceContext().getResourceMap());
819 newChildCsid = getCsid(newChildDocModel);
821 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
824 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
825 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
826 //then this is an item that says we have a parent. inboundItem is that parent.
827 RelationsCommonList.RelationListItem parentItem =
828 (parentList == null) ? null : findInList(parentList, inboundItem);
829 if (parentItem != null) {
830 removeFromList(parentList, parentItem); //exists, just take it off delete list
832 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
835 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
838 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
841 if (logger.isTraceEnabled()) {
842 String dump = dumpLists(itemCSID, parentList, childList, actionList);
843 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
846 if (logger.isTraceEnabled()) {
847 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
848 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
850 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
851 deleteRelations(childList, ctx, "childList");
853 if (logger.isTraceEnabled()) {
854 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
855 + actionList.size() + " new parents and children.");
857 createRelations(actionList, ctx);
858 if (logger.isTraceEnabled()) {
859 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
861 //We return all elements on the inbound list, since we have just worked to make them exist in the system
862 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
863 return relationsCommonListBody;
866 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
867 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
868 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
869 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
870 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
871 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
872 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
873 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
874 deleteRelations(parentList, ctx, "parentList-delete");
878 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
880 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
882 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
884 sb.append(item.getPredicate());
886 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
890 private String dumpLists(String itemCSID,
891 List<RelationsCommonList.RelationListItem> parentList,
892 List<RelationsCommonList.RelationListItem> childList,
893 List<RelationsCommonList.RelationListItem> actionList) {
894 StringBuilder sb = new StringBuilder();
895 sb.append("itemCSID: " + itemCSID + CR);
896 if(parentList!=null) {
897 sb.append(dumpList(parentList, "parentList"));
899 if(childList!=null) {
900 sb.append(dumpList(childList, "childList"));
902 if(actionList!=null) {
903 sb.append(dumpList(actionList, "actionList"));
905 return sb.toString();
907 private final static String CR = "\r\n";
908 private final static String T = " ";
910 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
911 StringBuilder sb = new StringBuilder();
913 if (list.size() > 0) {
914 sb.append("=========== " + label + " ==========" + CR);
916 for (RelationsCommonList.RelationListItem item : list) {
917 itemToString(sb, "== ", item);
920 return sb.toString();
923 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
924 * and sets URI correctly for related items.
925 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
927 protected void fixupInboundListItems(ServiceContext ctx,
928 List<RelationsCommonList.RelationListItem> inboundList,
929 DocumentModel docModel,
930 String itemCSID) throws Exception {
931 String thisURI = this.getUri(docModel);
932 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
933 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
934 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
935 RelationsDocListItem inboundItemObject = inboundItem.getObject();
936 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
938 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
939 inboundItem.setObjectCsid(itemCSID);
940 inboundItemObject.setCsid(itemCSID);
941 //inboundItemObject.setUri(getUri(docModel));
944 String objectCsid = inboundItemObject.getCsid();
945 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
946 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
947 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
948 inboundItemObject.setUri(uri); //CSPACE-4037
951 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
953 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
954 inboundItem.setSubjectCsid(itemCSID);
955 inboundItemSubject.setCsid(itemCSID);
956 //inboundItemSubject.setUri(getUri(docModel));
959 String subjectCsid = inboundItemSubject.getCsid();
960 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
961 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
962 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
963 inboundItemSubject.setUri(uri); //CSPACE-4037
966 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
971 // this method calls the RelationResource to have it create the relations and persist them.
972 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
973 for (RelationsCommonList.RelationListItem item : inboundList) {
974 RelationsCommon rc = new RelationsCommon();
975 //rc.setCsid(item.getCsid());
976 //todo: assignTo(item, rc);
977 RelationsDocListItem itemSubject = item.getSubject();
978 RelationsDocListItem itemObject = item.getObject();
980 // Set at least one of CSID and refName for Subject and Object
981 // Either value might be null for for each of Subject and Object
982 String subjectCsid = itemSubject.getCsid();
983 rc.setSubjectCsid(subjectCsid);
985 String objCsid = itemObject.getCsid();
986 rc.setObjectCsid(objCsid);
988 rc.setSubjectRefName(itemSubject.getRefName());
989 rc.setObjectRefName(itemObject.getRefName());
991 rc.setRelationshipType(item.getPredicate());
992 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
993 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
995 // This is superfluous, since it will be fetched by the Relations Create logic.
996 rc.setSubjectDocumentType(itemSubject.getDocumentType());
997 rc.setObjectDocumentType(itemObject.getDocumentType());
999 // This is superfluous, since it will be fetched by the Relations Create logic.
1000 rc.setSubjectUri(itemSubject.getUri());
1001 rc.setObjectUri(itemObject.getUri());
1002 // May not have the info here. Only really require CSID or refName.
1003 // Rest is handled in the Relation create mechanism
1004 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
1006 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
1007 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
1008 payloadOut.addPart(outputPart);
1009 RelationResource relationResource = new RelationResource();
1010 Object res = relationResource.create(ctx.getResourceMap(),
1011 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
1015 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
1017 for (RelationsCommonList.RelationListItem item : list) {
1018 RelationResource relationResource = new RelationResource();
1019 if(logger.isTraceEnabled()) {
1020 StringBuilder sb = new StringBuilder();
1021 itemToString(sb, "==== TO DELETE: ", item);
1022 logger.trace(sb.toString());
1024 Object res = relationResource.delete(item.getCsid());
1026 } catch (Throwable t) {
1027 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1032 private List<RelationsCommonList.RelationListItem> newList() {
1033 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1037 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1038 List<RelationsCommonList.RelationListItem> result = newList();
1039 for (RelationsCommonList.RelationListItem item : inboundList) {
1045 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1046 // But the list items must not be sparse
1047 private RelationsCommonList.RelationListItem findInList(
1048 List<RelationsCommonList.RelationListItem> list,
1049 RelationsCommonList.RelationListItem item) {
1050 RelationsCommonList.RelationListItem foundItem = null;
1051 for (RelationsCommonList.RelationListItem listItem : list) {
1052 if (itemsEqual(listItem, item)) { //equals must be defined, else
1053 foundItem = listItem;
1060 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1061 // But item1 must not be sparse
1062 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1063 if (item1 == null || item2 == null) {
1066 RelationsDocListItem subj1 = item1.getSubject();
1067 RelationsDocListItem subj2 = item2.getSubject();
1068 RelationsDocListItem obj1 = item1.getObject();
1069 RelationsDocListItem obj2 = item2.getObject();
1070 String subj1Csid = subj1.getCsid();
1071 String subj2Csid = subj2.getCsid();
1072 String subj1RefName = subj1.getRefName();
1073 String subj2RefName = subj2.getRefName();
1075 String obj1Csid = obj1.getCsid();
1076 String obj2Csid = obj2.getCsid();
1077 String obj1RefName = obj1.getRefName();
1078 String obj2RefName = obj2.getRefName();
1081 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1082 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1083 // predicate is proper, but still allow relationshipType
1084 && (item1.getPredicate().equals(item2.getPredicate())
1085 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1086 // Allow missing docTypes, so long as they do not conflict
1087 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1088 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1092 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1096 /* don't even THINK of re-using this method.
1097 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1099 private String extractInAuthorityCSID(String uri) {
1100 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1101 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1102 Matcher m = p.matcher(uri);
1104 if (m.groupCount() < 3) {
1105 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1108 //String service = m.group(1);
1109 String inauth = m.group(2);
1110 //String theRest = m.group(3);
1112 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1115 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1120 //ensures CSPACE-4042
1121 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1122 String authorityCSID = extractInAuthorityCSID(thisURI);
1123 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1124 if (Tools.isBlank(authorityCSID)
1125 || Tools.isBlank(authorityCSIDForInbound)
1126 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1127 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1131 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1132 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1133 ServiceContext ctx = getServiceContext();
1134 MultivaluedMap queryParams = ctx.getQueryParams();
1135 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1136 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1137 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1139 RelationResource relationResource = new RelationResource();
1140 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1141 return relationsCommonList;
1143 //============================= END TODO refactor ==========================
1145 public String getItemTermInfoGroupXPathBase() {
1146 return authorityItemTermGroupXPathBase;
1149 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1150 authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;
1153 protected String getAuthorityItemCommonSchemaName() {
1154 return authorityItemCommonSchemaName;