From: Richard Millet Date: Thu, 30 Aug 2012 00:01:18 +0000 (-0700) Subject: CSPACE-5492: Cleaning up some of the tangled dependency issues related to refactoring... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=be44be0eb6dbe5771a245f035991e89ab21a4b0d;p=tmp%2Fjakarta-migration.git CSPACE-5492: Cleaning up some of the tangled dependency issues related to refactoring the relations hierarchy code from authority items to a more general case usage. --- diff --git a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java index 567fa0580..0d22a5bfd 100644 --- a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java +++ b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java @@ -46,6 +46,7 @@ import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.document.DocumentNotFoundException; import org.collectionspace.services.common.document.DocumentWrapper; +import org.collectionspace.services.common.document.Hierarchy; import org.collectionspace.services.common.query.QueryManager; import org.collectionspace.services.common.vocabulary.RefNameServiceUtils; import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler; diff --git a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java index 22919c7aa..2202b1603 100644 --- a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java +++ b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java @@ -25,25 +25,18 @@ package org.collectionspace.services.common.vocabulary.nuxeo; import org.collectionspace.services.client.AuthorityClient; import org.collectionspace.services.client.IQueryManager; -import org.collectionspace.services.client.PayloadInputPart; -import org.collectionspace.services.client.PayloadOutputPart; import org.collectionspace.services.client.PoxPayloadIn; import org.collectionspace.services.client.PoxPayloadOut; -import org.collectionspace.services.client.RelationClient; -import org.collectionspace.services.common.ResourceBase; import org.collectionspace.services.common.api.CommonAPI; import org.collectionspace.services.common.api.RefName; import org.collectionspace.services.common.api.Tools; import org.collectionspace.services.common.authorityref.AuthorityRefDocList; import org.collectionspace.services.common.context.MultipartServiceContext; -import org.collectionspace.services.common.context.ServiceBindingUtils; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.document.DocumentException; import org.collectionspace.services.common.document.DocumentFilter; import org.collectionspace.services.common.document.DocumentWrapper; -import org.collectionspace.services.common.relation.IRelationsManager; -import org.collectionspace.services.common.repository.RepositoryClient; import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema; import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema; import org.collectionspace.services.common.vocabulary.RefNameServiceUtils; @@ -55,11 +48,8 @@ import org.collectionspace.services.nuxeo.client.java.DocHandlerBase; import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl; import org.collectionspace.services.nuxeo.util.NuxeoUtils; -import org.collectionspace.services.relation.RelationResource; -import org.collectionspace.services.relation.RelationsCommon; import org.collectionspace.services.relation.RelationsCommonList; import org.collectionspace.services.relation.RelationsDocListItem; -import org.collectionspace.services.relation.RelationshipType; import org.collectionspace.services.vocabulary.VocabularyItemJAXBSchema; @@ -72,8 +62,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; import java.util.ArrayList; import java.util.HashMap; @@ -102,8 +90,6 @@ public abstract class AuthorityItemDocumentModelHandler protected String authorityRefNameBase = null; // Used to determine when the displayName changes as part of the update. protected String oldDisplayNameOnUpdate = null; - protected String oldRefNameOnUpdate = null; - protected String newRefNameOnUpdate = null; public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) { this.authorityItemCommonSchemaName = authorityItemCommonSchemaName; @@ -315,16 +301,6 @@ public abstract class AuthorityItemDocumentModelHandler } } - /** - * Handle display name. - * - * @param docModel the doc model - * @throws Exception the exception - */ -// protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception { -// // Do nothing by default. -// } - /** * Handle refName updates for changes to display name. * Assumes refName is already correct. Just ensures it is right. @@ -347,39 +323,6 @@ public abstract class AuthorityItemDocumentModelHandler return updatedRefName; } - /* - * Note: The Vocabulary document handler overrides this method. - */ - protected String getRefPropName() { - return ServiceBindingUtils.AUTH_REF_PROP; - } - - /** - * Checks to see if the refName has changed, and if so, - * uses utilities to find all references and update them. - * @throws Exception - */ - protected void handleItemRefNameReferenceUpdate() throws Exception { - if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) { - // We have work to do. - if (logger.isDebugEnabled()) { - String eol = System.getProperty("line.separator"); - logger.debug("Need to find and update references to Item." + eol - + " Old refName" + oldRefNameOnUpdate + eol - + " New refName" + newRefNameOnUpdate); - } - ServiceContext ctx = getServiceContext(); - RepositoryClient repoClient = getRepositoryClient(ctx); - String refNameProp = getRefPropName(); - - int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(), - oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp); - if (logger.isDebugEnabled()) { - logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName"); - } - } - } - /** * If no short identifier was provided in the input payload, generate a * short identifier from the preferred term display name or term name. @@ -451,7 +394,6 @@ public abstract class AuthorityItemDocumentModelHandler AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority); } - public AuthorityRefDocList getReferencingObjects( ServiceContext ctx, List serviceTypes, @@ -505,7 +447,6 @@ public abstract class AuthorityItemDocumentModelHandler return authRefDocList; } - /* (non-Javadoc) * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType) */ @@ -642,124 +583,6 @@ public abstract class AuthorityItemDocumentModelHandler } } - /** @return null on parent not found - */ - protected String getParentCSID(String thisCSID) throws Exception { - String parentCSID = null; - try { - String predicate = RelationshipType.HAS_BROADER.value(); - RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate); - List parentList = parentListOuter.getRelationListItem(); - if (parentList != null) { - if (parentList.size() == 0) { - return null; - } - RelationsCommonList.RelationListItem relationListItem = parentList.get(0); - parentCSID = relationListItem.getObjectCsid(); - } - return parentCSID; - } catch (Exception e) { - logger.error("Could not find parent for this: " + thisCSID, e); - return null; - } - } - - public void showRelations(DocumentWrapper wrapDoc, - MultipartServiceContext ctx) throws Exception { - String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject()); - - String predicate = RelationshipType.HAS_BROADER.value(); - RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate); - List parentList = parentListOuter.getRelationListItem(); - - RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate); - List childrenList = childrenListOuter.getRelationListItem(); - - if(logger.isTraceEnabled()) { - String dump = dumpLists(thisCSID, parentList, childrenList, null); - logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); - } - - //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations. - //Now add all parents to our childrenList, to be able to return just one list of consolidated results. - //Not optimal, but that's the current design spec. - long added = 0; - for (RelationsCommonList.RelationListItem parent : parentList) { - childrenList.add(parent); - added++; - } - long childrenSize = childrenList.size(); - childrenListOuter.setTotalItems(childrenSize); - childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added); - - PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter); - ctx.addOutputPart(relationsPart); - } - - public void showSiblings(DocumentWrapper wrapDoc, - MultipartServiceContext ctx) throws Exception { - String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject()); - String parentCSID = getParentCSID(thisCSID); - if (parentCSID == null) { - logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID); - return; - } - - String predicate = RelationshipType.HAS_BROADER.value(); - RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate); - List siblingList = siblingListOuter.getRelationListItem(); - - List toRemoveList = newList(); - - - RelationsCommonList.RelationListItem item = null; - for (RelationsCommonList.RelationListItem sibling : siblingList) { - if (thisCSID.equals(sibling.getSubjectCsid())) { - 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. - } - } - //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. - for (RelationsCommonList.RelationListItem self : toRemoveList) { - removeFromList(siblingList, self); - } - - long siblingSize = siblingList.size(); - siblingListOuter.setTotalItems(siblingSize); - siblingListOuter.setItemsInPage(siblingSize); - if(logger.isTraceEnabled()) { - String dump = dumpList(siblingList, "Siblings of: "+thisCSID); - logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); - } - - PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter); - ctx.addOutputPart(relationsPart); - } - - public void showAllRelations(DocumentWrapper wrapDoc, MultipartServiceContext ctx) throws Exception { - String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject()); - - RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=* - List subjectList = subjectListOuter.getRelationListItem(); - - RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=* - List objectList = objectListOuter.getRelationListItem(); - - if(logger.isTraceEnabled()) { - String dump = dumpLists(thisCSID, subjectList, objectList, null); - logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); - } - // MERGE LISTS: - subjectList.addAll(objectList); - - //now subjectList actually has records BOTH where thisCSID is subject and object. - long relatedSize = subjectList.size(); - subjectListOuter.setTotalItems(relatedSize); - subjectListOuter.setItemsInPage(relatedSize); - - PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter); - ctx.addOutputPart(relationsPart); - } - @Override public void fillAllParts(DocumentWrapper wrapDoc, Action action) throws Exception { // @@ -769,401 +592,14 @@ public abstract class AuthorityItemDocumentModelHandler super.fillAllParts(wrapDoc, action); } - @Override - public void completeCreate(DocumentWrapper wrapDoc) throws Exception { - super.completeCreate(wrapDoc); - handleRelationsPayload(wrapDoc, false); - } - - @Override - public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { - super.completeUpdate(wrapDoc); - handleRelationsPayload(wrapDoc, true); - handleItemRefNameReferenceUpdate(); - } - - // Note that we must do this after we have completed the Update, so that the repository has the - // info for the item itself. The relations code must call into the repo to get info for each end. - // This could be optimized to pass in the parent docModel, since it will often be one end. - // Nevertheless, we should complete the item save before we do work on the relations, especially - // since a save on Create might fail, and we would not want to create relations for something - // that may not be created... - private void handleRelationsPayload(DocumentWrapper wrapDoc, boolean fUpdate) throws Exception { - ServiceContext ctx = getServiceContext(); - PoxPayloadIn input = (PoxPayloadIn) ctx.getInput(); - DocumentModel documentModel = (wrapDoc.getWrappedObject()); - String itemCsid = documentModel.getName(); - - //Updates relations part - RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate); - - 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 - ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart); - - //now we add part for relations list - //ServiceContext ctx = getServiceContext(); - //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME); - ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart); - } - - /** updateRelations strategy: - - go through inboundList, remove anything from childList that matches from childList - go through inboundList, remove anything from parentList that matches from parentList - go through parentList, delete all remaining - go through childList, delete all remaining - go through actionList, add all remaining. - check for duplicate children - check for more than one parent. - - inboundList parentList childList actionList - ---------------- --------------- ---------------- ---------------- - child-a parent-c child-a child-b - child-b parent-d child-c - parent-a - */ - private RelationsCommonList updateRelations( - String itemCSID, PoxPayloadIn input, DocumentWrapper wrapDoc, boolean fUpdate) - throws Exception { - if (logger.isTraceEnabled()) { - logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID); - } - PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common"); - if (part == null) { - return null; //nothing to do--they didn't send a list of relations. - } - RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody(); - List inboundList = relationsCommonListBody.getRelationListItem(); - List actionList = newList(); - List childList = null; - List parentList = null; - DocumentModel docModel = wrapDoc.getWrappedObject(); - String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME); - - ServiceContext ctx = getServiceContext(); - //Do magic replacement of ${itemCSID} and fix URI's. - fixupInboundListItems(ctx, inboundList, docModel, itemCSID); - - String HAS_BROADER = RelationshipType.HAS_BROADER.value(); - UriInfo uriInfo = ctx.getUriInfo(); - MultivaluedMap queryParams = uriInfo.getQueryParameters(); - - if (fUpdate) { - //Run getList() once as sent to get childListOuter: - String predicate = RelationshipType.HAS_BROADER.value(); - queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate); - queryParams.putSingle(IRelationsManager.SUBJECT_QP, null); - queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null); - queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID); - queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null); - - RelationResource relationResource = new RelationResource(); - RelationsCommonList childListOuter = relationResource.getList(ctx); // Knows all query params because they are in the context. - - //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter. - queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate); - queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID); - queryParams.putSingle(IRelationsManager.OBJECT_QP, null); - RelationsCommonList parentListOuter = relationResource.getList(ctx); - - - childList = childListOuter.getRelationListItem(); - parentList = parentListOuter.getRelationListItem(); - - if (parentList.size() > 1) { - throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList")); - } - - if (logger.isTraceEnabled()) { - logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations."); - } - } - - for (RelationsCommonList.RelationListItem inboundItem : inboundList) { - // Note that the relations may specify the other (non-item) bit with a refName, not a CSID, - // and so the CSID for those may be null - if(inboundItem.getPredicate().equals(HAS_BROADER)) { - // Look for parents and children - if(itemCSID.equals(inboundItem.getObject().getCsid()) - || itemRefName.equals(inboundItem.getObject().getRefName())) { - //then this is an item that says we have a child. That child is inboundItem - RelationsCommonList.RelationListItem childItem = - (childList == null) ? null : findInList(childList, inboundItem); - if (childItem != null) { - if (logger.isTraceEnabled()) { - StringBuilder sb = new StringBuilder(); - itemToString(sb, "== Child: ", childItem); - logger.trace("Found inboundChild in current child list: " + sb.toString()); - } - removeFromList(childList, childItem); //exists, just take it off delete list - } else { - if (logger.isTraceEnabled()) { - StringBuilder sb = new StringBuilder(); - itemToString(sb, "== Child: ", inboundItem); - logger.trace("inboundChild not in current child list, will add: " + sb.toString()); - } - actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list - String newChildCsid = inboundItem.getSubject().getCsid(); - if(newChildCsid == null) { - String newChildRefName = inboundItem.getSubject().getRefName(); - if(newChildRefName==null) { - throw new RuntimeException("Child with no CSID or refName!"); - } - if (logger.isTraceEnabled()) { - logger.trace("Fetching CSID for child with only refname: "+newChildRefName); - } - DocumentModel newChildDocModel = - ResourceBase.getDocModelForRefName(this.getRepositorySession(), - newChildRefName, getServiceContext().getResourceMap()); - newChildCsid = getCsid(newChildDocModel); - } - ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid); - } - - } else if (itemCSID.equals(inboundItem.getSubject().getCsid()) - || itemRefName.equals(inboundItem.getSubject().getRefName())) { - //then this is an item that says we have a parent. inboundItem is that parent. - RelationsCommonList.RelationListItem parentItem = - (parentList == null) ? null : findInList(parentList, inboundItem); - if (parentItem != null) { - removeFromList(parentList, parentItem); //exists, just take it off delete list - } else { - actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list - } - } else { - logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem); - } - } else { - logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem); - } - } - if (logger.isTraceEnabled()) { - String dump = dumpLists(itemCSID, parentList, childList, actionList); - logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); - } - if (fUpdate) { - if (logger.isTraceEnabled()) { - logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting " - + parentList.size() + " existing parents and " + childList.size() + " existing children."); - } - deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20. - deleteRelations(childList, ctx, "childList"); - } - if (logger.isTraceEnabled()) { - logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding " - + actionList.size() + " new parents and children."); - } - createRelations(actionList, ctx); - if (logger.isTraceEnabled()) { - logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done."); - } - //We return all elements on the inbound list, since we have just worked to make them exist in the system - // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back. - return relationsCommonListBody; - } - - private void ensureChildHasNoOtherParents(ServiceContext ctx, - MultivaluedMap queryParams, String childCSID) { - logger.trace("ensureChildHasNoOtherParents for: " + childCSID ); - queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID); - queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value()); - queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY - - RelationResource relationResource = new RelationResource(); - RelationsCommonList parentListOuter = relationResource.getList(ctx); - List parentList = parentListOuter.getRelationListItem(); - //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list")); - deleteRelations(parentList, ctx, "parentList-delete"); - } - - - private void itemToString(StringBuilder sb, String prefix, RelationsCommonList.RelationListItem item ) { - sb.append(prefix); - sb.append((item.getCsid()!= null)?item.getCsid():"NO CSID"); - sb.append(": ["); - sb.append((item.getSubject().getCsid()!=null)?item.getSubject().getCsid():item.getSubject().getRefName()); - sb.append("]--"); - sb.append(item.getPredicate()); - sb.append("-->["); - sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName()); - sb.append("]"); - } - - private String dumpLists(String itemCSID, - List parentList, - List childList, - List actionList) { - StringBuilder sb = new StringBuilder(); - sb.append("itemCSID: " + itemCSID + CR); - if(parentList!=null) { - sb.append(dumpList(parentList, "parentList")); - } - if(childList!=null) { - sb.append(dumpList(childList, "childList")); - } - if(actionList!=null) { - sb.append(dumpList(actionList, "actionList")); - } - return sb.toString(); - } - private final static String CR = "\r\n"; - - private String dumpList(List list, String label) { - StringBuilder sb = new StringBuilder(); - String s; - if (list.size() > 0) { - sb.append("=========== " + label + " ==========" + CR); - } - for (RelationsCommonList.RelationListItem item : list) { - itemToString(sb, "== ", item); - sb.append(CR); - } - return sb.toString(); - } - - /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant) - * and sets URI correctly for related items. - * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items. - */ - protected void fixupInboundListItems(ServiceContext ctx, - List inboundList, - DocumentModel docModel, - String itemCSID) throws Exception { - String thisURI = this.getUri(docModel); - // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method. - // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks. - for (RelationsCommonList.RelationListItem inboundItem : inboundList) { - RelationsDocListItem inboundItemObject = inboundItem.getObject(); - RelationsDocListItem inboundItemSubject = inboundItem.getSubject(); - - if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) { - inboundItem.setObjectCsid(itemCSID); - inboundItemObject.setCsid(itemCSID); - //inboundItemObject.setUri(getUri(docModel)); - } else { - /* - String objectCsid = inboundItemObject.getCsid(); - DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found. - DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel); - String uri = this.getRepositoryClient(ctx).getDocURI(wrapper); - inboundItemObject.setUri(uri); //CSPACE-4037 - */ - } - //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042 - - if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) { - inboundItem.setSubjectCsid(itemCSID); - inboundItemSubject.setCsid(itemCSID); - //inboundItemSubject.setUri(getUri(docModel)); - } else { - /* - String subjectCsid = inboundItemSubject.getCsid(); - DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found. - DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel); - String uri = this.getRepositoryClient(ctx).getDocURI(wrapper); - inboundItemSubject.setUri(uri); //CSPACE-4037 - */ - } - //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042 - - } - } - - // this method calls the RelationResource to have it create the relations and persist them. - private void createRelations(List inboundList, - ServiceContext ctx) throws Exception { - for (RelationsCommonList.RelationListItem item : inboundList) { - RelationsCommon rc = new RelationsCommon(); - //rc.setCsid(item.getCsid()); - //todo: assignTo(item, rc); - RelationsDocListItem itemSubject = item.getSubject(); - RelationsDocListItem itemObject = item.getObject(); - - // Set at least one of CSID and refName for Subject and Object - // Either value might be null for for each of Subject and Object - String subjectCsid = itemSubject.getCsid(); - rc.setSubjectCsid(subjectCsid); - - String objCsid = itemObject.getCsid(); - rc.setObjectCsid(objCsid); - - rc.setSubjectRefName(itemSubject.getRefName()); - rc.setObjectRefName(itemObject.getRefName()); - - rc.setRelationshipType(item.getPredicate()); - //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ; - //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd - - // This is superfluous, since it will be fetched by the Relations Create logic. - rc.setSubjectDocumentType(itemSubject.getDocumentType()); - rc.setObjectDocumentType(itemObject.getDocumentType()); - - // This is superfluous, since it will be fetched by the Relations Create logic. - rc.setSubjectUri(itemSubject.getUri()); - rc.setObjectUri(itemObject.getUri()); - // May not have the info here. Only really require CSID or refName. - // Rest is handled in the Relation create mechanism - //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri()); - - PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME); - PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc); - payloadOut.addPart(outputPart); - RelationResource relationResource = new RelationResource(); - Response res = relationResource.create(ctx, ctx.getResourceMap(), - ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params. - } - } - - private void deleteRelations(List list, - ServiceContext ctx, - String listName) { - try { - for (RelationsCommonList.RelationListItem item : list) { - RelationResource relationResource = new RelationResource(); - if(logger.isTraceEnabled()) { - StringBuilder sb = new StringBuilder(); - itemToString(sb, "==== TO DELETE: ", item); - logger.trace(sb.toString()); - } - Response res = relationResource.deleteWithParentCtx(ctx, item.getCsid()); - if (logger.isDebugEnabled()) { - logger.debug("Status of authority item deleteRelations method call was: " + res.getStatus()); - } - } - } catch (Throwable t) { - String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true); - logger.error(msg); - } - } - - private List newList() { - List result = new ArrayList(); - return result; - } - protected List cloneList(List inboundList) { - List result = newList(); + List result = newRelationsCommonList(); for (RelationsCommonList.RelationListItem item : inboundList) { result.add(item); } return result; } - // Note that the item argument may be sparse (only refName, no CSID for subject or object) - // But the list items must not be sparse - private RelationsCommonList.RelationListItem findInList( - List list, - RelationsCommonList.RelationListItem item) { - RelationsCommonList.RelationListItem foundItem = null; - for (RelationsCommonList.RelationListItem listItem : list) { - if (itemsEqual(listItem, item)) { //equals must be defined, else - foundItem = listItem; - break; - } - } - return foundItem; - } - // Note that item2 may be sparse (only refName, no CSID for subject or object) // But item1 must not be sparse private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) { @@ -1196,9 +632,6 @@ public abstract class AuthorityItemDocumentModelHandler return isEqual; } - private void removeFromList(List list, RelationsCommonList.RelationListItem item) { - list.remove(item); - } /* don't even THINK of re-using this method. * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05"; @@ -1235,20 +668,6 @@ public abstract class AuthorityItemDocumentModelHandler } } - //================= TODO: move this to common, refactoring this and CollectionObjectResource.java - public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception { - ServiceContext ctx = getServiceContext(); - MultivaluedMap queryParams = ctx.getQueryParams(); - queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate); - queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID); - queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID); - - RelationResource relationResource = new RelationResource(); //is this still acting like a singleton as it should be? - RelationsCommonList relationsCommonList = relationResource.getList(ctx); - return relationsCommonList; - } - //============================= END TODO refactor ========================== - public String getItemTermInfoGroupXPathBase() { return authorityItemTermGroupXPathBase; } diff --git a/services/blob/client/src/test/java/org/collectionspace/services/client/test/BlobScaleTest.java b/services/blob/client/src/test/java/org/collectionspace/services/client/test/BlobScaleTest.java index 3324e73b3..0007f5631 100644 --- a/services/blob/client/src/test/java/org/collectionspace/services/client/test/BlobScaleTest.java +++ b/services/blob/client/src/test/java/org/collectionspace/services/client/test/BlobScaleTest.java @@ -15,7 +15,7 @@ import javax.ws.rs.core.Response; import org.collectionspace.services.client.BlobClient; import org.collectionspace.services.client.CollectionSpaceClient; -import org.collectionspace.services.common.profile.Profiler; +import org.collectionspace.services.client.Profiler; import org.collectionspace.services.jaxb.AbstractCommonList; import org.jboss.resteasy.client.ClientResponse; import org.slf4j.Logger; diff --git a/services/client/src/main/java/org/collectionspace/services/client/IRelationsManager.java b/services/client/src/main/java/org/collectionspace/services/client/IRelationsManager.java index a2086e0c9..a4c73960b 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/IRelationsManager.java +++ b/services/client/src/main/java/org/collectionspace/services/client/IRelationsManager.java @@ -17,5 +17,20 @@ public interface IRelationsManager { + "." + SERVICE_COMMONPART_NAME + ":objectDocumentType"; public final static String CMIS_CSPACE_RELATIONS_TITLE = IQueryManager.CMIS_RELATIONS_PREFIX + "." + IQueryManager.CMIS_NUXEO_TITLE; - + + /** The Constant SUBJECT. */ + static public final String SUBJECT = "subjectCsid"; + static public final String SUBJECT_QP = "sbj"; + static public final String SUBJECT_TYPE = "subjectType"; + static public final String SUBJECT_TYPE_QP = SUBJECT_QP + "Type"; + + /** The Constant PREDICATE. */ + static public final String PREDICATE = "predicate"; + static public final String PREDICATE_QP = "prd"; + + /** The Constant OBJECT. */ + static public final String OBJECT = "objectCsid"; + static public final String OBJECT_QP = "obj"; + static public final String OBJECT_TYPE = "objectType"; + static public final String OBJECT_TYPE_QP = OBJECT_QP + "Type"; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/profile/Profiler.java b/services/client/src/main/java/org/collectionspace/services/client/Profiler.java similarity index 95% rename from services/common/src/main/java/org/collectionspace/services/common/profile/Profiler.java rename to services/client/src/main/java/org/collectionspace/services/client/Profiler.java index 4f82e784f..91554eac9 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/profile/Profiler.java +++ b/services/client/src/main/java/org/collectionspace/services/client/Profiler.java @@ -14,7 +14,7 @@ * You may obtain a copy of the ECL 2.0 License at * https://source.collectionspace.org/collection-space/LICENSE.txt */ -package org.collectionspace.services.common.profile; +package org.collectionspace.services.client; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/services/common/pom.xml b/services/common/pom.xml index a42734778..3c205463c 100644 --- a/services/common/pom.xml +++ b/services/common/pom.xml @@ -33,6 +33,11 @@ org.collectionspace.services.authorization-mgt.client ${project.version} + + org.collectionspace.services + org.collectionspace.services.relation.client + ${project.version} + ["); + sb.append((item.getObject().getCsid()!=null)?item.getObject().getCsid():item.getObject().getRefName()); + sb.append("]"); + } + + private String dumpList(List list, String label) { + StringBuilder sb = new StringBuilder(); + String s; + if (list.size() > 0) { + sb.append("=========== " + label + " ==========" + CR); + } + for (RelationsCommonList.RelationListItem item : list) { + itemToString(sb, "== ", item); + sb.append(CR); + } + return sb.toString(); + } + + /** @return null on parent not found + */ + protected String getParentCSID(String thisCSID) throws Exception { + String parentCSID = null; + try { + String predicate = RelationshipType.HAS_BROADER.value(); + RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate); + List parentList = parentListOuter.getRelationListItem(); + if (parentList != null) { + if (parentList.size() == 0) { + return null; + } + RelationsCommonList.RelationListItem relationListItem = parentList.get(0); + parentCSID = relationListItem.getObjectCsid(); + } + return parentCSID; + } catch (Exception e) { + logger.error("Could not find parent for this: " + thisCSID, e); + return null; + } + } + + protected List newRelationsCommonList() { + List result = new ArrayList(); + return result; + } + + public void showSiblings(DocumentWrapper wrapDoc, + MultipartServiceContext ctx) throws Exception { + String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject()); + String parentCSID = getParentCSID(thisCSID); + if (parentCSID == null) { + logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID); + return; + } + + String predicate = RelationshipType.HAS_BROADER.value(); + RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate); + List siblingList = siblingListOuter.getRelationListItem(); + + List toRemoveList = newRelationsCommonList(); + + + RelationsCommonList.RelationListItem item = null; + for (RelationsCommonList.RelationListItem sibling : siblingList) { + if (thisCSID.equals(sibling.getSubjectCsid())) { + 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. + } + } + //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. + for (RelationsCommonList.RelationListItem self : toRemoveList) { + removeFromList(siblingList, self); + } + + long siblingSize = siblingList.size(); + siblingListOuter.setTotalItems(siblingSize); + siblingListOuter.setItemsInPage(siblingSize); + if(logger.isTraceEnabled()) { + String dump = dumpList(siblingList, "Siblings of: "+thisCSID); + logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showSiblings ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); + } + + PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter); + ctx.addOutputPart(relationsPart); + } + + public void showRelations(DocumentWrapper wrapDoc, + MultipartServiceContext ctx) throws Exception { + String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject()); + + String predicate = RelationshipType.HAS_BROADER.value(); + RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate); + List parentList = parentListOuter.getRelationListItem(); + + RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate); + List childrenList = childrenListOuter.getRelationListItem(); + + if(logger.isTraceEnabled()) { + String dump = dumpLists(thisCSID, parentList, childrenList, null); + logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); + } + + //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations. + //Now add all parents to our childrenList, to be able to return just one list of consolidated results. + //Not optimal, but that's the current design spec. + long added = 0; + for (RelationsCommonList.RelationListItem parent : parentList) { + childrenList.add(parent); + added++; + } + long childrenSize = childrenList.size(); + childrenListOuter.setTotalItems(childrenSize); + childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added); + + PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter); + ctx.addOutputPart(relationsPart); + } + + public void showAllRelations(DocumentWrapper wrapDoc, MultipartServiceContext ctx) throws Exception { + String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject()); + + RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=* + List subjectList = subjectListOuter.getRelationListItem(); + + RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=* + List objectList = objectListOuter.getRelationListItem(); + + if(logger.isTraceEnabled()) { + String dump = dumpLists(thisCSID, subjectList, objectList, null); + logger.trace("~~~~~~~~~~~~~~~~~~~~~~ showAllRelations ~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); + } + // MERGE LISTS: + subjectList.addAll(objectList); + + //now subjectList actually has records BOTH where thisCSID is subject and object. + long relatedSize = subjectList.size(); + subjectListOuter.setTotalItems(relatedSize); + subjectListOuter.setItemsInPage(relatedSize); + + PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter); + ctx.addOutputPart(relationsPart); + } + + private String dumpLists(String itemCSID, + List parentList, + List childList, + List actionList) { + StringBuilder sb = new StringBuilder(); + sb.append("itemCSID: " + itemCSID + CR); + if(parentList!=null) { + sb.append(dumpList(parentList, "parentList")); + } + if(childList!=null) { + sb.append(dumpList(childList, "childList")); + } + if(actionList!=null) { + sb.append(dumpList(actionList, "actionList")); + } + return sb.toString(); + } + + //================= TODO: move this to common, refactoring this and CollectionObjectResource.java + public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception { + ServiceContext ctx = getServiceContext(); + MultivaluedMap queryParams = ctx.getQueryParams(); + queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate); + queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID); + queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID); + + RelationResource relationResource = new RelationResource(); //is this still acting like a singleton as it should be? + RelationsCommonList relationsCommonList = relationResource.getList(ctx); + return relationsCommonList; + } + //============================= END TODO refactor ========================== + + // this method calls the RelationResource to have it create the relations and persist them. + private void createRelations(List inboundList, + ServiceContext ctx) throws Exception { + for (RelationsCommonList.RelationListItem item : inboundList) { + RelationsCommon rc = new RelationsCommon(); + //rc.setCsid(item.getCsid()); + //todo: assignTo(item, rc); + RelationsDocListItem itemSubject = item.getSubject(); + RelationsDocListItem itemObject = item.getObject(); + + // Set at least one of CSID and refName for Subject and Object + // Either value might be null for for each of Subject and Object + String subjectCsid = itemSubject.getCsid(); + rc.setSubjectCsid(subjectCsid); + + String objCsid = itemObject.getCsid(); + rc.setObjectCsid(objCsid); + + rc.setSubjectRefName(itemSubject.getRefName()); + rc.setObjectRefName(itemObject.getRefName()); + + rc.setRelationshipType(item.getPredicate()); + //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ; + //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd + + // This is superfluous, since it will be fetched by the Relations Create logic. + rc.setSubjectDocumentType(itemSubject.getDocumentType()); + rc.setObjectDocumentType(itemObject.getDocumentType()); + + // This is superfluous, since it will be fetched by the Relations Create logic. + rc.setSubjectUri(itemSubject.getUri()); + rc.setObjectUri(itemObject.getUri()); + // May not have the info here. Only really require CSID or refName. + // Rest is handled in the Relation create mechanism + //uriPointsToSameAuthority(itemSubject.getUri(), itemObject.getUri()); + + PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME); + PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc); + payloadOut.addPart(outputPart); + RelationResource relationResource = new RelationResource(); + Response res = relationResource.create(ctx, ctx.getResourceMap(), + ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params. + } + } + + // Note that item2 may be sparse (only refName, no CSID for subject or object) + // But item1 must not be sparse + private boolean itemsEqual(RelationsCommonList.RelationListItem item1, RelationsCommonList.RelationListItem item2) { + if (item1 == null || item2 == null) { + return false; + } + RelationsDocListItem subj1 = item1.getSubject(); + RelationsDocListItem subj2 = item2.getSubject(); + RelationsDocListItem obj1 = item1.getObject(); + RelationsDocListItem obj2 = item2.getObject(); + String subj1Csid = subj1.getCsid(); + String subj2Csid = subj2.getCsid(); + String subj1RefName = subj1.getRefName(); + String subj2RefName = subj2.getRefName(); + + String obj1Csid = obj1.getCsid(); + String obj2Csid = obj2.getCsid(); + String obj1RefName = obj1.getRefName(); + String obj2RefName = obj2.getRefName(); + + boolean isEqual = + (subj1Csid.equals(subj2Csid) || ((subj2Csid==null) && subj1RefName.equals(subj2RefName))) + && (obj1Csid.equals(obj1Csid) || ((obj2Csid==null) && obj1RefName.equals(obj2RefName))) + // predicate is proper, but still allow relationshipType + && (item1.getPredicate().equals(item2.getPredicate()) + || ((item2.getPredicate()==null) && item1.getRelationshipType().equals(item2.getRelationshipType()))) + // Allow missing docTypes, so long as they do not conflict + && (obj1.getDocumentType().equals(obj2.getDocumentType()) || obj2.getDocumentType()==null) + && (subj1.getDocumentType().equals(subj2.getDocumentType()) || subj2.getDocumentType()==null); + return isEqual; + } + + // Note that the item argument may be sparse (only refName, no CSID for subject or object) + // But the list items must not be sparse + private RelationsCommonList.RelationListItem findInList( + List list, + RelationsCommonList.RelationListItem item) { + RelationsCommonList.RelationListItem foundItem = null; + for (RelationsCommonList.RelationListItem listItem : list) { + if (itemsEqual(listItem, item)) { //equals must be defined, else + foundItem = listItem; + break; + } + } + return foundItem; + } + + /** updateRelations strategy: + * + * + go through inboundList, remove anything from childList that matches from childList + go through inboundList, remove anything from parentList that matches from parentList + go through parentList, delete all remaining + go through childList, delete all remaining + go through actionList, add all remaining. + check for duplicate children + check for more than one parent. + + inboundList parentList childList actionList + ---------------- --------------- ---------------- ---------------- + child-a parent-c child-a child-b + child-b parent-d child-c + parent-a + * + * + */ + private RelationsCommonList updateRelations( + String itemCSID, PoxPayloadIn input, DocumentWrapper wrapDoc, boolean fUpdate) + throws Exception { + if (logger.isTraceEnabled()) { + logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID); + } + PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common"); + if (part == null) { + return null; //nothing to do--they didn't send a list of relations. + } + RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody(); + List inboundList = relationsCommonListBody.getRelationListItem(); + List actionList = newRelationsCommonList(); + List childList = null; + List parentList = null; + DocumentModel docModel = wrapDoc.getWrappedObject(); + String itemRefName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME); + + ServiceContext ctx = getServiceContext(); + //Do magic replacement of ${itemCSID} and fix URI's. + fixupInboundListItems(ctx, inboundList, docModel, itemCSID); + + String HAS_BROADER = RelationshipType.HAS_BROADER.value(); + UriInfo uriInfo = ctx.getUriInfo(); + MultivaluedMap queryParams = uriInfo.getQueryParameters(); + + if (fUpdate) { + //Run getList() once as sent to get childListOuter: + String predicate = RelationshipType.HAS_BROADER.value(); + queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate); + queryParams.putSingle(IRelationsManager.SUBJECT_QP, null); + queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null); + queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID); + queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null); + + RelationResource relationResource = new RelationResource(); + RelationsCommonList childListOuter = relationResource.getList(ctx); // Knows all query params because they are in the context. + + //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter. + queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate); + queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID); + queryParams.putSingle(IRelationsManager.OBJECT_QP, null); + RelationsCommonList parentListOuter = relationResource.getList(ctx); + + + childList = childListOuter.getRelationListItem(); + parentList = parentListOuter.getRelationListItem(); + + if (parentList.size() > 1) { + throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList")); + } + + if (logger.isTraceEnabled()) { + logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations."); + } + } + + for (RelationsCommonList.RelationListItem inboundItem : inboundList) { + // Note that the relations may specify the other (non-item) bit with a refName, not a CSID, + // and so the CSID for those may be null + if(inboundItem.getPredicate().equals(HAS_BROADER)) { + // Look for parents and children + if(itemCSID.equals(inboundItem.getObject().getCsid()) + || itemRefName.equals(inboundItem.getObject().getRefName())) { + //then this is an item that says we have a child. That child is inboundItem + RelationsCommonList.RelationListItem childItem = + (childList == null) ? null : findInList(childList, inboundItem); + if (childItem != null) { + if (logger.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + itemToString(sb, "== Child: ", childItem); + logger.trace("Found inboundChild in current child list: " + sb.toString()); + } + removeFromList(childList, childItem); //exists, just take it off delete list + } else { + if (logger.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + itemToString(sb, "== Child: ", inboundItem); + logger.trace("inboundChild not in current child list, will add: " + sb.toString()); + } + actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list + String newChildCsid = inboundItem.getSubject().getCsid(); + if(newChildCsid == null) { + String newChildRefName = inboundItem.getSubject().getRefName(); + if(newChildRefName==null) { + throw new RuntimeException("Child with no CSID or refName!"); + } + if (logger.isTraceEnabled()) { + logger.trace("Fetching CSID for child with only refname: "+newChildRefName); + } + DocumentModel newChildDocModel = + ResourceBase.getDocModelForRefName(this.getRepositorySession(), + newChildRefName, getServiceContext().getResourceMap()); + newChildCsid = getCsid(newChildDocModel); + } + ensureChildHasNoOtherParents(ctx, queryParams, newChildCsid); + } + + } else if (itemCSID.equals(inboundItem.getSubject().getCsid()) + || itemRefName.equals(inboundItem.getSubject().getRefName())) { + //then this is an item that says we have a parent. inboundItem is that parent. + RelationsCommonList.RelationListItem parentItem = + (parentList == null) ? null : findInList(parentList, inboundItem); + if (parentItem != null) { + removeFromList(parentList, parentItem); //exists, just take it off delete list + } else { + actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list + } + } else { + logger.error("Parent/Child Element didn't link to this item. inboundItem: " + inboundItem); + } + } else { + logger.warn("Non-parent relation ignored. inboundItem: " + inboundItem); + } + } + if (logger.isTraceEnabled()) { + String dump = dumpLists(itemCSID, parentList, childList, actionList); + logger.trace("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump); + } + if (fUpdate) { + if (logger.isTraceEnabled()) { + logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " deleting " + + parentList.size() + " existing parents and " + childList.size() + " existing children."); + } + deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20. + deleteRelations(childList, ctx, "childList"); + } + if (logger.isTraceEnabled()) { + logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " adding " + + actionList.size() + " new parents and children."); + } + createRelations(actionList, ctx); + if (logger.isTraceEnabled()) { + logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done."); + } + //We return all elements on the inbound list, since we have just worked to make them exist in the system + // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back. + return relationsCommonListBody; + } + + /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant) + * and sets URI correctly for related items. + * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items. + */ + protected void fixupInboundListItems(ServiceContext ctx, + List inboundList, + DocumentModel docModel, + String itemCSID) throws Exception { + String thisURI = this.getUri(docModel); + // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method. + // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks. + for (RelationsCommonList.RelationListItem inboundItem : inboundList) { + RelationsDocListItem inboundItemObject = inboundItem.getObject(); + RelationsDocListItem inboundItemSubject = inboundItem.getSubject(); + + if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemObject.getCsid())) { + inboundItem.setObjectCsid(itemCSID); + inboundItemObject.setCsid(itemCSID); + //inboundItemObject.setUri(getUri(docModel)); + } else { + /* + String objectCsid = inboundItemObject.getCsid(); + DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found. + DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel); + String uri = this.getRepositoryClient(ctx).getDocURI(wrapper); + inboundItemObject.setUri(uri); //CSPACE-4037 + */ + } + //uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042 + + if (CommonAPI.AuthorityItemCSID_REPLACE.equalsIgnoreCase(inboundItemSubject.getCsid())) { + inboundItem.setSubjectCsid(itemCSID); + inboundItemSubject.setCsid(itemCSID); + //inboundItemSubject.setUri(getUri(docModel)); + } else { + /* + String subjectCsid = inboundItemSubject.getCsid(); + DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found. + DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel); + String uri = this.getRepositoryClient(ctx).getDocURI(wrapper); + inboundItemSubject.setUri(uri); //CSPACE-4037 + */ + } + //uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042 + + } + } + + private void ensureChildHasNoOtherParents(ServiceContext ctx, + MultivaluedMap queryParams, String childCSID) { + logger.trace("ensureChildHasNoOtherParents for: " + childCSID ); + queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID); + queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value()); + queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY + + RelationResource relationResource = new RelationResource(); + RelationsCommonList parentListOuter = relationResource.getList(ctx); + List parentList = parentListOuter.getRelationListItem(); + //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list")); + deleteRelations(parentList, ctx, "parentList-delete"); + } + + private void deleteRelations(List list, + ServiceContext ctx, + String listName) { + try { + for (RelationsCommonList.RelationListItem item : list) { + RelationResource relationResource = new RelationResource(); + if(logger.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + itemToString(sb, "==== TO DELETE: ", item); + logger.trace(sb.toString()); + } + Response res = relationResource.deleteWithParentCtx(ctx, item.getCsid()); + if (logger.isDebugEnabled()) { + logger.debug("Status of authority item deleteRelations method call was: " + res.getStatus()); + } + } + } catch (Throwable t) { + String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true); + logger.error(msg); + } + } + + // Note that we must do this after we have completed the Update, so that the repository has the + // info for the item itself. The relations code must call into the repo to get info for each end. + // This could be optimized to pass in the parent docModel, since it will often be one end. + // Nevertheless, we should complete the item save before we do work on the relations, especially + // since a save on Create might fail, and we would not want to create relations for something + // that may not be created... + private void handleRelationsPayload(DocumentWrapper wrapDoc, boolean fUpdate) throws Exception { + ServiceContext ctx = getServiceContext(); + PoxPayloadIn input = (PoxPayloadIn) ctx.getInput(); + DocumentModel documentModel = (wrapDoc.getWrappedObject()); + String itemCsid = documentModel.getName(); + + //Updates relations part + RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc, fUpdate); + + 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 + ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart); + + //now we add part for relations list + //ServiceContext ctx = getServiceContext(); + //PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME); + ((PoxPayloadOut) ctx.getOutput()).addPart(payloadOutputPart); + } + + /** + * Checks to see if the refName has changed, and if so, + * uses utilities to find all references and update them. + * @throws Exception + */ + protected void handleItemRefNameReferenceUpdate() throws Exception { + if (newRefNameOnUpdate != null && oldRefNameOnUpdate != null) { + // We have work to do. + if (logger.isDebugEnabled()) { + String eol = System.getProperty("line.separator"); + logger.debug("Need to find and update references to Item." + eol + + " Old refName" + oldRefNameOnUpdate + eol + + " New refName" + newRefNameOnUpdate); + } + ServiceContext ctx = getServiceContext(); + RepositoryClient repoClient = getRepositoryClient(ctx); + String refNameProp = getRefPropName(); + + int nUpdated = RefNameServiceUtils.updateAuthorityRefDocs(ctx, repoClient, this.getRepositorySession(), + oldRefNameOnUpdate, newRefNameOnUpdate, refNameProp); + if (logger.isDebugEnabled()) { + logger.debug("Updated " + nUpdated + " instances of oldRefName to newRefName"); + } + } + } + + /* + * Note: The Vocabulary document handler overrides this method. + */ + protected String getRefPropName() { + return ServiceBindingUtils.AUTH_REF_PROP; + } + + + } diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java index 3cb71c65d..58e9a8300 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java @@ -31,11 +31,11 @@ import org.collectionspace.services.client.CollectionSpaceClient; import org.collectionspace.services.client.IQueryManager; import org.collectionspace.services.client.PoxPayloadIn; import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.client.Profiler; import org.collectionspace.services.client.workflow.WorkflowClient; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.query.QueryContext; import org.collectionspace.services.common.repository.RepositoryClient; -import org.collectionspace.services.common.profile.Profiler; import org.collectionspace.services.lifecycle.TransitionDef; import org.collectionspace.services.nuxeo.util.NuxeoUtils; diff --git a/services/contact/client/pom.xml b/services/contact/client/pom.xml index 3ed7fae50..62392329d 100644 --- a/services/contact/client/pom.xml +++ b/services/contact/client/pom.xml @@ -34,11 +34,6 @@ org.collectionspace.services.client ${project.version} - - org.collectionspace.services - org.collectionspace.services.common - ${project.version} - dom4j diff --git a/services/person/client/pom.xml b/services/person/client/pom.xml index a64f3ef87..1a5cf24a8 100644 --- a/services/person/client/pom.xml +++ b/services/person/client/pom.xml @@ -33,13 +33,7 @@ org.collectionspace.services org.collectionspace.services.authority.jaxb ${project.version} - - - org.collectionspace.services - org.collectionspace.services.common - true - ${project.version} - + org.collectionspace.services org.collectionspace.services.person.jaxb diff --git a/services/person/jaxb/pom.xml b/services/person/jaxb/pom.xml index 2ab35427d..993def9db 100644 --- a/services/person/jaxb/pom.xml +++ b/services/person/jaxb/pom.xml @@ -14,11 +14,6 @@ services.person.jaxb - - org.collectionspace.services - org.collectionspace.services.common - ${project.version} - org.collectionspace.services org.collectionspace.services.jaxb diff --git a/services/relation/client/pom.xml b/services/relation/client/pom.xml index 8d6bddd14..5c7a3bb1c 100644 --- a/services/relation/client/pom.xml +++ b/services/relation/client/pom.xml @@ -40,23 +40,21 @@ org.collectionspace.services org.collectionspace.services.person.client ${project.version} + test org.collectionspace.services org.collectionspace.services.authority.jaxb true ${project.version} - - - org.collectionspace.services - org.collectionspace.services.common - true - ${project.version} - + + + org.testng testng + test org.jboss.resteasy diff --git a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java index 7e3f5aef1..c070fdf2f 100644 --- a/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java +++ b/services/relation/client/src/main/java/org/collectionspace/services/client/RelationClient.java @@ -40,9 +40,7 @@ public class RelationClient extends AbstractPoxServiceClientImpl