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.IQueryManager;
28 import org.collectionspace.services.client.PayloadInputPart;
29 import org.collectionspace.services.client.PayloadOutputPart;
30 import org.collectionspace.services.client.PoxPayloadIn;
31 import org.collectionspace.services.client.PoxPayloadOut;
32 import org.collectionspace.services.client.RelationClient;
33 import org.collectionspace.services.common.ResourceBase;
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.relation.IRelationsManager;
45 import org.collectionspace.services.common.repository.RepositoryClient;
46 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
47 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
48 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils;
49 import org.collectionspace.services.config.service.ListResultField;
50 import org.collectionspace.services.config.service.ObjectPartType;
51 import org.collectionspace.services.jaxb.AbstractCommonList;
52 import org.collectionspace.services.nuxeo.client.java.CommonList; //FIXME: REM - 5/15/2012 - CommonList should be moved out of this package and into a more "common" package
53 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
54 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
55 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
56 import org.collectionspace.services.relation.RelationResource;
57 import org.collectionspace.services.relation.RelationsCommon;
58 import org.collectionspace.services.relation.RelationsCommonList;
59 import org.collectionspace.services.relation.RelationsDocListItem;
60 import org.collectionspace.services.relation.RelationshipType;
61 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.DocumentModelList;
66 import org.nuxeo.ecm.core.api.model.PropertyException;
67 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 import javax.ws.rs.core.MultivaluedMap;
73 import javax.ws.rs.core.UriInfo;
75 import java.util.ArrayList;
76 import java.util.HashMap;
77 import java.util.List;
79 import java.util.regex.Matcher;
80 import java.util.regex.Pattern;
82 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
84 * AuthorityItemDocumentModelHandler
86 * $LastChangedRevision: $
89 public abstract class AuthorityItemDocumentModelHandler<AICommon>
90 extends DocHandlerBase<AICommon> {
92 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
93 private String authorityItemCommonSchemaName;
94 private String authorityItemTermGroupXPathBase;
96 * inVocabulary is the parent Authority for this context
98 protected String inAuthority = null;
99 protected String authorityRefNameBase = null;
100 // Used to determine when the displayName changes as part of the update.
101 protected String oldDisplayNameOnUpdate = null;
102 protected String oldRefNameOnUpdate = null;
103 protected String newRefNameOnUpdate = null;
105 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
106 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
109 public void setInAuthority(String inAuthority) {
110 this.inAuthority = inAuthority;
113 /** Subclasses may override this to customize the URI segment. */
114 public String getAuthorityServicePath() {
115 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
119 public String getUri(DocumentModel docModel) {
120 // Laramie20110510 CSPACE-3932
121 String authorityServicePath = getAuthorityServicePath();
122 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
124 inAuthority = (String) docModel.getProperty(authorityItemCommonSchemaName,
125 AuthorityItemJAXBSchema.IN_AUTHORITY);
126 } catch (ClientException pe) {
127 throw new RuntimeException("Could not get parent specifier for item!");
130 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
133 protected String getAuthorityRefNameBase() {
134 return this.authorityRefNameBase;
137 public void setAuthorityRefNameBase(String value) {
138 this.authorityRefNameBase = value;
142 * Note: the Vocabulary service's VocabularyItemDocumentModelHandler class overrides this method.
144 protected ListResultField getListResultsDisplayNameField() {
145 ListResultField result = new ListResultField();
146 // Per CSPACE-5132, the name of this element remains 'displayName'
147 // for backwards compatibility, although its value is obtained
148 // from the termDisplayName field.
150 // Update: this name is now being changed to 'termDisplayName', both
151 // because this is the actual field name and because the app layer
152 // work to convert over to this field is underway. Per Patrick, the
153 // app layer treats lists, in at least some context(s), as sparse record
154 // payloads, and thus fields in list results must all be present in
155 // (i.e. represent a strict subset of the fields in) record schemas.
159 // In CSPACE-5134, these list results will change substantially
160 // to return display names for both the preferred term and for
161 // each non-preferred term (if any).
162 result.setElement(AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
163 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
164 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME));
170 * Note: the Vocabulary service's VocabularyItemDocumentModelHandler class overrides this method.
172 protected ListResultField getListResultsTermStatusField() {
173 ListResultField result = new ListResultField();
175 result.setElement(AuthorityItemJAXBSchema.TERM_STATUS);
176 result.setXpath(NuxeoUtils.getPrimaryXPathPropertyName(
177 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_STATUS));
182 private boolean isTermDisplayName(String elName) {
183 return AuthorityItemJAXBSchema.TERM_DISPLAY_NAME.equals(elName) || VocabularyItemJAXBSchema.DISPLAY_NAME.equals(elName);
187 public List<ListResultField> getListItemsArray() throws DocumentException {
188 List<ListResultField> list = super.getListItemsArray();
189 int nFields = list.size();
190 // Ensure that each item in a list of Authority items includes
191 // a set of common fields, so we do not depend upon configuration
192 // for general logic.
193 boolean hasDisplayName = false;
194 boolean hasShortId = false;
195 boolean hasRefName = false;
196 boolean hasTermStatus = false;
197 for (int i = 0; i < nFields; i++) {
198 ListResultField field = list.get(i);
199 String elName = field.getElement();
200 if (isTermDisplayName(elName) == true) {
201 hasDisplayName = true;
202 } else if (AuthorityItemJAXBSchema.SHORT_IDENTIFIER.equals(elName)) {
204 } else if (AuthorityItemJAXBSchema.REF_NAME.equals(elName)) {
206 } else if (AuthorityItemJAXBSchema.TERM_STATUS.equals(elName)) {
207 hasTermStatus = true;
210 ListResultField field;
211 if (!hasDisplayName) {
212 field = getListResultsDisplayNameField();
213 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.
216 field = new ListResultField();
217 field.setElement(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
218 field.setXpath(AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
222 field = new ListResultField();
223 field.setElement(AuthorityItemJAXBSchema.REF_NAME);
224 field.setXpath(AuthorityItemJAXBSchema.REF_NAME);
227 if (!hasTermStatus) {
228 field = getListResultsTermStatusField();
236 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
239 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
240 // first fill all the parts of the document
241 super.handleCreate(wrapDoc);
242 // Ensure we have required fields set properly
243 handleInAuthority(wrapDoc.getWrappedObject());
245 // FIXME: This call to synthesize a shortIdentifier from the termDisplayName
246 // of the preferred term may have been commented out, in the course of
247 // adding support for preferred / non-preferred terms, in CSPACE-4813
248 // and linked issues. Revisit this to determine whether we want to
252 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
253 // refName includes displayName, so we force a correct value here.
254 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
258 * Note that the Vocabulary service's document-model for items overrides this method.
260 protected String getPrimaryDisplayName(DocumentModel docModel, String schema,
261 String complexPropertyName, String fieldName) {
262 String result = null;
264 result = getStringValueInPrimaryRepeatingComplexProperty(docModel, schema, complexPropertyName, fieldName);
270 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
273 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
274 // First, get a copy of the old displayName
275 // oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
276 // AuthorityItemJAXBSchema.DISPLAY_NAME);
277 oldDisplayNameOnUpdate = getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
278 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
279 oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName,
280 AuthorityItemJAXBSchema.REF_NAME);
281 super.handleUpdate(wrapDoc);
283 // Now, check the new display and handle the refname update.
284 String newDisplayName = (String) getPrimaryDisplayName(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName,
285 authorityItemTermGroupXPathBase,
286 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
287 if (newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) {
288 // Need to update the refName, and then fix all references.
289 newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName);
291 // Mark as not needing attention in completeUpdate phase.
292 newRefNameOnUpdate = null;
293 oldRefNameOnUpdate = null;
298 * Handle display name.
300 * @param docModel the doc model
301 * @throws Exception the exception
303 // protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
304 // // Do nothing by default.
308 * Handle refName updates for changes to display name.
309 * Assumes refName is already correct. Just ensures it is right.
311 * @param docModel the doc model
312 * @param newDisplayName the new display name
313 * @throws Exception the exception
315 protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel,
316 String newDisplayName) throws Exception {
317 RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate);
318 if (authItem == null) {
319 String err = "Authority Item has illegal refName: " + oldRefNameOnUpdate;
321 throw new IllegalArgumentException(err);
323 authItem.displayName = newDisplayName;
324 String updatedRefName = authItem.toString();
325 docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName);
326 return updatedRefName;
330 * Note: The Vocabulary document handler overrides this method.
332 protected String getRefPropName() {
333 return ServiceBindingUtils.AUTH_REF_PROP;
337 * Checks to see if the refName has changed, and if so,
338 * uses utilities to find all references and update them.
341 protected void handleItemRefNameReferenceUpdate() throws Exception {
342 if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) {
343 // We have work to do.
344 if (logger.isDebugEnabled()) {
345 String eol = System.getProperty("line.separator");
346 logger.debug("Need to find and update references to Item." + eol
347 + " Old refName" + oldRefNameOnUpdate + eol
348 + " New refName" + newRefNameOnUpdate);
350 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
351 RepositoryClient repoClient = getRepositoryClient(ctx);
352 String refNameProp = getRefPropName();
354 int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(),
355 oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp);
356 if (logger.isDebugEnabled()) {
357 logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName");
363 * If no short identifier was provided in the input payload, generate a
364 * short identifier from the preferred term display name or term name.
366 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel,
367 String schemaName) throws Exception {
368 String shortIdentifier = (String) docModel.getProperty(schemaName,
369 AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
371 if (Tools.isEmpty(shortIdentifier)) {
372 String termDisplayName = getPrimaryDisplayName(
373 docModel, authorityItemCommonSchemaName,
374 getItemTermInfoGroupXPathBase(),
375 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
377 String termName = getPrimaryDisplayName(
378 docModel, authorityItemCommonSchemaName,
379 getItemTermInfoGroupXPathBase(),
380 AuthorityItemJAXBSchema.TERM_NAME);
382 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(termDisplayName,
384 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER,
385 generatedShortIdentifier);
390 * Generate a refName for the authority item from the short identifier
393 * All refNames for authority items are generated. If a client supplies
394 * a refName, it will be overwritten during create (per this method)
395 * or discarded during update (per filterReadOnlyPropertiesForPart).
397 * @see #filterReadOnlyPropertiesForPart(Map<String, Object>, org.collectionspace.services.common.service.ObjectPartType)
400 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
402 String authorityRefBaseName) throws Exception {
403 DocumentModel docModel = wrapDoc.getWrappedObject();
404 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
405 String displayName = getPrimaryDisplayName(docModel, authorityItemCommonSchemaName,
406 getItemTermInfoGroupXPathBase(), AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
408 if (Tools.isEmpty(authorityRefBaseName)) {
409 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
412 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
413 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
414 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
418 * Check the logic around the parent pointer. Note that we only need do this on
419 * create, since we have logic to make this read-only on update.
423 * @throws Exception the exception
425 private void handleInAuthority(DocumentModel docModel) throws Exception {
426 if(inAuthority==null) { // Only happens on queries to wildcarded authorities
427 throw new IllegalStateException("Trying to Create an object with no inAuthority value!");
429 docModel.setProperty(authorityItemCommonSchemaName,
430 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
434 public AuthorityRefDocList getReferencingObjects(
435 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
436 List<String> serviceTypes,
438 String itemcsid) throws Exception {
439 AuthorityRefDocList authRefDocList = null;
440 RepositoryInstance repoSession = null;
441 boolean releaseRepoSession = false;
444 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
445 repoSession = this.getRepositorySession();
446 if (repoSession == null) {
447 repoSession = repoClient.getRepositorySession();
448 releaseRepoSession = true;
450 DocumentFilter myFilter = getDocumentFilter();
453 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, itemcsid);
454 DocumentModel docModel = wrapper.getWrappedObject();
455 String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
456 authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(
457 repoSession, ctx, repoClient,
461 myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
462 } catch (PropertyException pe) {
464 } catch (DocumentException de) {
466 } catch (Exception e) {
467 if (logger.isDebugEnabled()) {
468 logger.debug("Caught exception ", e);
470 throw new DocumentException(e);
472 if (releaseRepoSession && repoSession != null) {
473 repoClient.releaseRepositorySession(repoSession);
476 } catch (Exception e) {
477 if (logger.isDebugEnabled()) {
478 logger.debug("Caught exception ", e);
480 throw new DocumentException(e);
482 return authRefDocList;
487 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
490 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
492 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
494 // Add the CSID to the common part, since they may have fetched via the shortId.
495 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
496 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
497 unQObjectProperties.put("csid", csid);
500 return unQObjectProperties;
504 * Filters out selected values supplied in an update request.
506 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
507 * that the link to the item's parent remains untouched.
509 * @param objectProps the properties filtered out from the update payload
510 * @param partMeta metadata for the object to fill
513 public void filterReadOnlyPropertiesForPart(
514 Map<String, Object> objectProps, ObjectPartType partMeta) {
515 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
516 String commonPartLabel = getServiceContext().getCommonPartLabel();
517 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
518 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
519 objectProps.remove(AuthorityItemJAXBSchema.CSID);
520 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
521 objectProps.remove(AuthorityItemJAXBSchema.REF_NAME);
526 protected Object getXPathValue(DocumentModel docModel, // REM - CSPACE-5133
527 String schema, ListResultField field) {
528 Object result = null;
530 result = NuxeoUtils.getXPathValue(docModel, schema, field.getXpath());
531 String elName = field.getElement();
532 if (isTermDisplayName(elName) == true) {
533 MultivaluedMap<String, String> queryParams = this.getServiceContext().getQueryParams();
534 String partialTerm = queryParams != null ? queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM) : null;
535 if (partialTerm != null && partialTerm.trim().isEmpty() == false) {
536 List<String> strList = new ArrayList<String>();
537 strList.add((String)result);
539 strList.add("Tucker");
549 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
550 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
551 super.extractAllParts(wrapDoc);
553 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
554 if (Tools.isTrue(showSiblings)) {
555 showSiblings(wrapDoc, ctx);
556 return; // actual result is returned on ctx.addOutputPart();
559 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
560 if (Tools.isTrue(showRelations)) {
561 showRelations(wrapDoc, ctx);
562 return; // actual result is returned on ctx.addOutputPart();
565 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
566 if (Tools.isTrue(showAllRelations)) {
567 showAllRelations(wrapDoc, ctx);
568 return; // actual result is returned on ctx.addOutputPart();
572 /** @return null on parent not found
574 protected String getParentCSID(String thisCSID) throws Exception {
575 String parentCSID = null;
577 String predicate = RelationshipType.HAS_BROADER.value();
578 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
579 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
580 if (parentList != null) {
581 if (parentList.size() == 0) {
584 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
585 parentCSID = relationListItem.getObjectCsid();
588 } catch (Exception e) {
589 logger.error("Could not find parent for this: " + thisCSID, e);
594 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
595 MultipartServiceContext ctx) throws Exception {
596 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
598 String predicate = RelationshipType.HAS_BROADER.value();
599 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
600 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
602 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
603 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
605 if(logger.isTraceEnabled()) {
606 String dump = dumpLists(thisCSID, parentList, childrenList, null);
607 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
610 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
611 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
612 //Not optimal, but that's the current design spec.
614 for (RelationsCommonList.RelationListItem parent : parentList) {
615 childrenList.add(parent);
618 long childrenSize = childrenList.size();
619 childrenListOuter.setTotalItems(childrenSize);
620 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
622 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
623 ctx.addOutputPart(relationsPart);
626 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
627 MultipartServiceContext ctx) throws Exception {
628 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
629 String parentCSID = getParentCSID(thisCSID);
630 if (parentCSID == null) {
631 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
635 String predicate = RelationshipType.HAS_BROADER.value();
636 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
637 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
639 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
642 RelationsCommonList.RelationListItem item = null;
643 for (RelationsCommonList.RelationListItem sibling : siblingList) {
644 if (thisCSID.equals(sibling.getSubjectCsid())) {
645 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.
648 //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.
649 for (RelationsCommonList.RelationListItem self : toRemoveList) {
650 removeFromList(siblingList, self);
653 long siblingSize = siblingList.size();
654 siblingListOuter.setTotalItems(siblingSize);
655 siblingListOuter.setItemsInPage(siblingSize);
656 if(logger.isTraceEnabled()) {
657 String dump = dumpList(siblingList, "Siblings of: "+thisCSID);
658 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
661 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
662 ctx.addOutputPart(relationsPart);
665 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
666 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
668 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
669 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
671 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
672 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
674 if(logger.isTraceEnabled()) {
675 String dump = dumpLists(thisCSID, subjectList, objectList, null);
676 logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
679 subjectList.addAll(objectList);
681 //now subjectList actually has records BOTH where thisCSID is subject and object.
682 long relatedSize = subjectList.size();
683 subjectListOuter.setTotalItems(relatedSize);
684 subjectListOuter.setItemsInPage(relatedSize);
686 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
687 ctx.addOutputPart(relationsPart);
691 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
693 // We currently don't override this method with any AuthorityItemDocumentModelHandler specific functionality, so
694 // we could remove this method.
696 super.fillAllParts(wrapDoc, action);
700 public void completeCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
701 super.completeCreate(wrapDoc);
702 handleRelationsPayload(wrapDoc, false);
706 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
707 super.completeUpdate(wrapDoc);
708 handleRelationsPayload(wrapDoc, true);
709 handleItemRefNameReferenceUpdate();
712 // Note that we must do this after we have completed the Update, so that the repository has the
713 // info for the item itself. The relations code must call into the repo to get info for each end.
714 // This could be optimized to pass in the parent docModel, since it will often be one end.
715 // Nevertheless, we should complete the item save before we do work on the relations, especially
716 // since a save on Create might fail, and we would not want to create relations for something
717 // that may not be created...
718 private void handleRelationsPayload(DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate) throws Exception {
719 ServiceContext ctx = getServiceContext();
720 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
721 DocumentModel documentModel = (wrapDoc.getWrappedObject());
722 String itemCsid = documentModel.getName();
724 //Updates relations part
725 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate);
727 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
728 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
730 //now we add part for relations list
731 //ServiceContext ctx = getServiceContext();
732 //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
733 ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart);
736 /** updateRelations strategy:
738 go through inboundList, remove anything from childList that matches from childList
739 go through inboundList, remove anything from parentList that matches from parentList
740 go through parentList, delete all remaining
741 go through childList, delete all remaining
742 go through actionList, add all remaining.
743 check for duplicate children
744 check for more than one parent.
746 inboundList parentList childList actionList
747 ---------------- --------------- ---------------- ----------------
748 child-a parent-c child-a child-b
749 child-b parent-d child-c
752 private RelationsCommonList updateRelations(
753 String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc, boolean fUpdate)
755 if (logger.isTraceEnabled()) {
756 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID);
758 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
760 return null; //nothing to do--they didn't send a list of relations.
762 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
763 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
764 List<RelationsCommonList.RelationListItem> actionList = newList();
765 List<RelationsCommonList.RelationListItem> childList = null;
766 List<RelationsCommonList.RelationListItem> parentList = null;
767 DocumentModel docModel = wrapDoc.getWrappedObject();
768 String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
770 ServiceContext ctx = getServiceContext();
771 //Do magic replacement of ${itemCSID} and fix URI's.
772 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
774 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
775 UriInfo uriInfo = ctx.getUriInfo();
776 MultivaluedMap queryParams = uriInfo.getQueryParameters();
779 //Run getList() once as sent to get childListOuter:
780 String predicate = RelationshipType.HAS_BROADER.value();
781 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
782 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
783 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
784 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
785 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
786 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
788 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
789 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
790 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
791 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
792 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
795 childList = childListOuter.getRelationListItem();
796 parentList = parentListOuter.getRelationListItem();
798 if (parentList.size() > 1) {
799 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
802 if (logger.isTraceEnabled()) {
803 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
808 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
809 // Note that the relations may specify the other (non-item) bit with a refName, not a CSID,
810 // and so the CSID for those may be null
811 if(inboundItem.getPredicate().equals(HAS_BROADER)) {
812 // Look for parents and children
813 if(itemCSID.equals(inboundItem.getObject().getCsid())
814 || itemRefName.equals(inboundItem.getObject().getRefName())) {
815 //then this is an item that says we have a child. That child is inboundItem
816 RelationsCommonList.RelationListItem childItem =
817 (childList == null) ? null : findInList(childList, inboundItem);
818 if (childItem != null) {
819 if (logger.isTraceEnabled()) {
820 StringBuilder sb = new StringBuilder();
821 itemToString(sb, "== Child: ", childItem);
822 logger.trace("Found inboundChild in current child list: " + sb.toString());
824 removeFromList(childList, childItem); //exists, just take it off delete list
826 if (logger.isTraceEnabled()) {
827 StringBuilder sb = new StringBuilder();
828 itemToString(sb, "== Child: ", inboundItem);
829 logger.trace("inboundChild not in current child list, will add: " + sb.toString());
831 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
832 String newChildCsid = inboundItem.getSubject().getCsid();
833 if(newChildCsid == null) {
834 String newChildRefName = inboundItem.getSubject().getRefName();
835 if(newChildRefName==null) {
836 throw new RuntimeException("Child with no CSID or refName!");
838 if (logger.isTraceEnabled()) {
839 logger.trace("Fetching CSID for child with only refname: "+newChildRefName);
841 DocumentModel newChildDocModel =
842 ResourceBase.getDocModelForRefName(this.getRepositorySession(),
843 newChildRefName, getServiceContext().getResourceMap());
844 newChildCsid = getCsid(newChildDocModel);
846 ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid);
849 } else if (itemCSID.equals(inboundItem.getSubject().getCsid())
850 || itemRefName.equals(inboundItem.getSubject().getRefName())) {
851 //then this is an item that says we have a parent. inboundItem is that parent.
852 RelationsCommonList.RelationListItem parentItem =
853 (parentList == null) ? null : findInList(parentList, inboundItem);
854 if (parentItem != null) {
855 removeFromList(parentList, parentItem); //exists, just take it off delete list
857 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
860 logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem);
863 logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem);
866 if (logger.isTraceEnabled()) {
867 String dump = dumpLists(itemCSID, parentList, childList, actionList);
868 logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
871 if (logger.isTraceEnabled()) {
872 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting "
873 + parentList.size() + " existing parents and " + childList.size() + " existing children.");
875 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
876 deleteRelations(childList, ctx, "childList");
878 if (logger.isTraceEnabled()) {
879 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding "
880 + actionList.size() + " new parents and children.");
882 createRelations(actionList, ctx);
883 if (logger.isTraceEnabled()) {
884 logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
886 //We return all elements on the inbound list, since we have just worked to make them exist in the system
887 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
888 return relationsCommonListBody;
891 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
892 logger.trace("ensureChildHasNoOtherParents for: " + childCSID );
893 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
894 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
895 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
896 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
897 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
898 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
899 deleteRelations(parentList, ctx, "parentList-delete");
903 private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) {
905 sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID");
907 sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName());
909 sb.append(item.getPredicate());
911 sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName());
915 private String dumpLists(String itemCSID,
916 List<RelationsCommonList.RelationListItem> parentList,
917 List<RelationsCommonList.RelationListItem> childList,
918 List<RelationsCommonList.RelationListItem> actionList) {
919 StringBuilder sb = new StringBuilder();
920 sb.append("itemCSID: " + itemCSID + CR);
921 if(parentList!=null) {
922 sb.append(dumpList(parentList, "parentList"));
924 if(childList!=null) {
925 sb.append(dumpList(childList, "childList"));
927 if(actionList!=null) {
928 sb.append(dumpList(actionList, "actionList"));
930 return sb.toString();
932 private final static String CR = "\r\n";
933 private final static String T = " ";
935 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
936 StringBuilder sb = new StringBuilder();
938 if (list.size() > 0) {
939 sb.append("=========== " + label + " ==========" + CR);
941 for (RelationsCommonList.RelationListItem item : list) {
942 itemToString(sb, "== ", item);
945 return sb.toString();
948 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
949 * and sets URI correctly for related items.
950 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
952 protected void fixupInboundListItems(ServiceContext ctx,
953 List<RelationsCommonList.RelationListItem> inboundList,
954 DocumentModel docModel,
955 String itemCSID) throws Exception {
956 String thisURI = this.getUri(docModel);
957 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
958 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
959 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
960 RelationsDocListItem inboundItemObject = inboundItem.getObject();
961 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
963 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) {
964 inboundItem.setObjectCsid(itemCSID);
965 inboundItemObject.setCsid(itemCSID);
966 //inboundItemObject.setUri(getUri(docModel));
969 String objectCsid = inboundItemObject.getCsid();
970 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
971 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
972 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
973 inboundItemObject.setUri(uri); //CSPACE-4037
976 //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
978 if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) {
979 inboundItem.setSubjectCsid(itemCSID);
980 inboundItemSubject.setCsid(itemCSID);
981 //inboundItemSubject.setUri(getUri(docModel));
984 String subjectCsid = inboundItemSubject.getCsid();
985 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
986 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
987 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
988 inboundItemSubject.setUri(uri); //CSPACE-4037
991 //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
996 // this method calls the RelationResource to have it create the relations and persist them.
997 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) throws Exception {
998 for (RelationsCommonList.RelationListItem item : inboundList) {
999 RelationsCommon rc = new RelationsCommon();
1000 //rc.setCsid(item.getCsid());
1001 //todo: assignTo(item, rc);
1002 RelationsDocListItem itemSubject = item.getSubject();
1003 RelationsDocListItem itemObject = item.getObject();
1005 // Set at least one of CSID and refName for Subject and Object
1006 // Either value might be null for for each of Subject and Object
1007 String subjectCsid = itemSubject.getCsid();
1008 rc.setSubjectCsid(subjectCsid);
1010 String objCsid = itemObject.getCsid();
1011 rc.setObjectCsid(objCsid);
1013 rc.setSubjectRefName(itemSubject.getRefName());
1014 rc.setObjectRefName(itemObject.getRefName());
1016 rc.setRelationshipType(item.getPredicate());
1017 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
1018 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
1020 // This is superfluous, since it will be fetched by the Relations Create logic.
1021 rc.setSubjectDocumentType(itemSubject.getDocumentType());
1022 rc.setObjectDocumentType(itemObject.getDocumentType());
1024 // This is superfluous, since it will be fetched by the Relations Create logic.
1025 rc.setSubjectUri(itemSubject.getUri());
1026 rc.setObjectUri(itemObject.getUri());
1027 // May not have the info here. Only really require CSID or refName.
1028 // Rest is handled in the Relation create mechanism
1029 //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri());
1031 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
1032 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
1033 payloadOut.addPart(outputPart);
1034 RelationResource relationResource = new RelationResource();
1035 Object res = relationResource.create(ctx.getResourceMap(),
1036 ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
1040 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
1042 for (RelationsCommonList.RelationListItem item : list) {
1043 RelationResource relationResource = new RelationResource();
1044 if(logger.isTraceEnabled()) {
1045 StringBuilder sb = new StringBuilder();
1046 itemToString(sb, "==== TO DELETE: ", item);
1047 logger.trace(sb.toString());
1049 Object res = relationResource.delete(item.getCsid());
1051 } catch (Throwable t) {
1052 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
1057 private List<RelationsCommonList.RelationListItem> newList() {
1058 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
1062 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
1063 List<RelationsCommonList.RelationListItem> result = newList();
1064 for (RelationsCommonList.RelationListItem item : inboundList) {
1070 // Note that the item argument may be sparse (only refName, no CSID for subject or object)
1071 // But the list items must not be sparse
1072 private RelationsCommonList.RelationListItem findInList(
1073 List<RelationsCommonList.RelationListItem> list,
1074 RelationsCommonList.RelationListItem item) {
1075 RelationsCommonList.RelationListItem foundItem = null;
1076 for (RelationsCommonList.RelationListItem listItem : list) {
1077 if (itemsEqual(listItem, item)) { //equals must be defined, else
1078 foundItem = listItem;
1085 // Note that item2 may be sparse (only refName, no CSID for subject or object)
1086 // But item1 must not be sparse
1087 private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) {
1088 if (item1 == null || item2 == null) {
1091 RelationsDocListItem subj1 = item1.getSubject();
1092 RelationsDocListItem subj2 = item2.getSubject();
1093 RelationsDocListItem obj1 = item1.getObject();
1094 RelationsDocListItem obj2 = item2.getObject();
1095 String subj1Csid = subj1.getCsid();
1096 String subj2Csid = subj2.getCsid();
1097 String subj1RefName = subj1.getRefName();
1098 String subj2RefName = subj2.getRefName();
1100 String obj1Csid = obj1.getCsid();
1101 String obj2Csid = obj2.getCsid();
1102 String obj1RefName = obj1.getRefName();
1103 String obj2RefName = obj2.getRefName();
1106 (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName)))
1107 && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName)))
1108 // predicate is proper, but still allow relationshipType
1109 && (item1.getPredicate().equals(item2.getPredicate())
1110 || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType())))
1111 // Allow missing docTypes, so long as they do not conflict
1112 && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null)
1113 && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null);
1117 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
1121 /* don't even THINK of re-using this method.
1122 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
1124 private String extractInAuthorityCSID(String uri) {
1125 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
1126 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
1127 Matcher m = p.matcher(uri);
1129 if (m.groupCount() < 3) {
1130 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
1133 //String service = m.group(1);
1134 String inauth = m.group(2);
1135 //String theRest = m.group(3);
1137 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
1140 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
1145 //ensures CSPACE-4042
1146 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
1147 String authorityCSID = extractInAuthorityCSID(thisURI);
1148 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
1149 if (Tools.isBlank(authorityCSID)
1150 || Tools.isBlank(authorityCSIDForInbound)
1151 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
1152 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
1156 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
1157 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
1158 ServiceContext ctx = getServiceContext();
1159 MultivaluedMap queryParams = ctx.getQueryParams();
1160 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
1161 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
1162 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
1164 RelationResource relationResource = new RelationResource();
1165 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
1166 return relationsCommonList;
1168 //============================= END TODO refactor ==========================
1170 public String getItemTermInfoGroupXPathBase() {
1171 return authorityItemTermGroupXPathBase;
1174 public void setItemTermInfoGroupXPathBase(String itemTermInfoGroupXPathBase) {
1175 authorityItemTermGroupXPathBase = itemTermInfoGroupXPathBase;
1178 protected String getAuthorityItemCommonSchemaName() {
1179 return authorityItemCommonSchemaName;