From a31e7f9169d7d036750f0e736f5d3cc5e29713ff Mon Sep 17 00:00:00 2001 From: Patrick Schmitz Date: Mon, 10 Oct 2011 23:14:28 +0000 Subject: [PATCH] CSPACE-1927 - Refactoring and adding detection of displayName and refName changes, in preparation for final fix. --- .../vocabulary/RefNameServiceUtils.java | 112 ++++++++++++------ .../AuthorityItemDocumentModelHandler.java | 78 +++++++++++- .../services/common/api/RefName.java | 9 ++ 3 files changed, 164 insertions(+), 35 deletions(-) diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java index 004785164..0731d476b 100644 --- a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java @@ -59,7 +59,7 @@ import org.collectionspace.services.nuxeo.util.NuxeoUtils; */ public class RefNameServiceUtils { - private final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class); + private static final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class); public static AuthorityRefDocList getAuthorityRefDocs(ServiceContext ctx, RepositoryClient repoClient, @@ -70,24 +70,52 @@ public class RefNameServiceUtils { AbstractCommonList commonList = (AbstractCommonList) wrapperList; commonList.setPageNum(pageNum); commonList.setPageSize(pageSize); - - List list = wrapperList.getAuthorityRefDocItem(); + + // Get the service bindings for this tenant TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance().getTenantBindingConfigReader(); List servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceType); if (servicebindings == null || servicebindings.isEmpty()) { + logger.error("RefNameServiceUtils.getAuthorityRefDocs: No services bindings found, cannot proceed!"); return null; } + // Need to escape the quotes in the refName // TODO What if they are already escaped? String escapedRefName = refName.replaceAll("'", "\\\\'"); -// String domain = -// tReader.getTenantBinding(ctx.getTenantId()).getRepositoryDomain(); ArrayList docTypes = new ArrayList(); Map queriedServiceBindings = new HashMap(); Map> authRefFieldsByService = new HashMap>(); + + String query = computeWhereClauseForAuthorityRefDocs(escapedRefName, docTypes, servicebindings, + queriedServiceBindings, authRefFieldsByService ); + if (query == null) { // found no authRef fields - nothing to query + return wrapperList; + } + // Now we have to issue the search + DocumentWrapper docListWrapper = repoClient.findDocs(ctx, + docTypes, query, pageSize, pageNum, computeTotal); + // Now we gather the info for each document into the list and return + DocumentModelList docList = docListWrapper.getWrappedObject(); + // Set num of items in list. this is useful to our testing framework. + commonList.setItemsInPage(docList.size()); + // set the total result size + commonList.setTotalItems(docList.totalSize()); + + processRefObjsDocList(docList, refName, servicebindings, + queriedServiceBindings, authRefFieldsByService, + list, null); + return wrapperList; + } + + private static String computeWhereClauseForAuthorityRefDocs( + String escapedRefName, + ArrayList docTypes, + List servicebindings, + Map queriedServiceBindings, + Map> authRefFieldsByService ) { StringBuilder whereClause = new StringBuilder(); boolean fFirst = true; List authRefFieldPaths = new ArrayList(); @@ -133,25 +161,30 @@ public class RefNameServiceUtils { } } String whereClauseStr = whereClause.toString(); // for debugging - if (fFirst) // found no authRef fields - nothing to query - { - return wrapperList; + if (fFirst) { // found no authRef fields - nothing to query + return null; + } else { + return whereClause.toString(); } - String fullQuery = whereClause.toString(); // for debug - // Now we have to issue the search - DocumentWrapper docListWrapper = repoClient.findDocs(ctx, - docTypes, whereClause.toString(), pageSize, pageNum, computeTotal); - // Now we gather the info for each document into the list and return - DocumentModelList docList = docListWrapper.getWrappedObject(); - // Set num of items in list. this is useful to our testing framework. - commonList.setItemsInPage(docList.size()); - // set the total result size - commonList.setTotalItems(docList.totalSize()); + } + + /* + * Runs through the list of found docs, processing them. + * If list is non-null, then processing means gather the info for items. + * If list is null, and newRefName is non-null, then processing means replacing and updating. + */ + private static void processRefObjsDocList(DocumentModelList docList, + String refName, + List servicebindings, + Map queriedServiceBindings, + Map> authRefFieldsByService, + List list, + String newAuthorityRefName) { Iterator iter = docList.iterator(); while (iter.hasNext()) { DocumentModel docModel = iter.next(); - AuthorityRefDocList.AuthorityRefDocItem ilistItem = new AuthorityRefDocList.AuthorityRefDocItem(); - String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString()); + AuthorityRefDocList.AuthorityRefDocItem ilistItem; + String docType = docModel.getDocumentType().getName(); ServiceBindingType sb = queriedServiceBindings.get(docType); if (sb == null) { @@ -159,14 +192,21 @@ public class RefNameServiceUtils { "getAuthorityRefDocs: No Service Binding for docType: " + docType); } String serviceContextPath = "/" + sb.getName().toLowerCase() + "/"; - // The id and URI are the same on all doctypes - ilistItem.setDocId(csid); - ilistItem.setUri(serviceContextPath + csid); - ilistItem.setDocType(docType); - ilistItem.setDocNumber( - ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel)); - ilistItem.setDocName( - ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel)); + + if(list == null) { + ilistItem = null; + } else { + ilistItem = new AuthorityRefDocList.AuthorityRefDocItem(); + String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString()); + ilistItem.setDocId(csid); + ilistItem.setUri(serviceContextPath + csid); + // The id and URI are the same on all doctypes + ilistItem.setDocType(docType); + ilistItem.setDocNumber( + ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel)); + ilistItem.setDocName( + ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel)); + } // Now, we have to loop over the authRefFieldsByService to figure // out which field matched this. Ignore multiple matches. Map matchingAuthRefFields = authRefFieldsByService.get(docType); @@ -209,12 +249,18 @@ public class RefNameServiceUtils { // Handle multiple fields matching in one Doc. See CSPACE-2863. if(fRefFound) { // We already added ilistItem, so we need to clone that and add again - ilistItem = cloneAuthRefDocItem(ilistItem, sourceField); + if(ilistItem != null) { + ilistItem = cloneAuthRefDocItem(ilistItem, sourceField); + } } else { - ilistItem.setSourceField(sourceField); + if(ilistItem != null) { + ilistItem.setSourceField(sourceField); + } fRefFound = true; } - list.add(ilistItem); + if(ilistItem != null) { + list.add(ilistItem); + } } } catch (ClientException ce) { @@ -225,10 +271,10 @@ public class RefNameServiceUtils { if (!fRefFound) { throw new RuntimeException( "getAuthorityRefDocs: Could not find refname in object:" - + docType + ":" + csid); + + docType + ":" + NuxeoUtils.getCsid(docModel)); } } - return wrapperList; + } private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem( diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java index a0fe1b802..59cf1e37d 100644 --- a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java @@ -42,6 +42,7 @@ import org.collectionspace.services.common.repository.RepositoryClientFactory; import org.collectionspace.services.common.service.ObjectPartType; import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema; import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema; +import org.collectionspace.services.common.vocabulary.RefNameServiceUtils; import org.collectionspace.services.nuxeo.client.java.DocHandlerBase; import org.collectionspace.services.nuxeo.util.NuxeoUtils; import org.collectionspace.services.relation.RelationResource; @@ -79,6 +80,11 @@ public abstract class AuthorityItemDocumentModelHandler */ protected String inAuthority; protected String authorityRefNameBase; + + // 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; @@ -121,6 +127,11 @@ public abstract class AuthorityItemDocumentModelHandler super.handleCreate(wrapDoc); handleInAuthority(wrapDoc.getWrappedObject()); handleComputedDisplayNames(wrapDoc.getWrappedObject()); + String displayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName, + AuthorityItemJAXBSchema.DISPLAY_NAME); + if(Tools.isEmpty(displayName)) { + logger.warn("Creating Authority Item with no displayName!"); + } // CSPACE-3178: // Uncomment once debugged and App layer is read to integrate // Experimenting with these uncommented now ... @@ -133,8 +144,23 @@ public abstract class AuthorityItemDocumentModelHandler */ @Override public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { + // First, get a copy of the old displayName + oldDisplayNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName, + AuthorityItemJAXBSchema.DISPLAY_NAME); + oldRefNameOnUpdate = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName, + AuthorityItemJAXBSchema.REF_NAME); super.handleUpdate(wrapDoc); handleComputedDisplayNames(wrapDoc.getWrappedObject()); + String newDisplayName = (String) wrapDoc.getWrappedObject().getProperty(authorityItemCommonSchemaName, + AuthorityItemJAXBSchema.DISPLAY_NAME); + if(newDisplayName != null && !newDisplayName.equals(oldDisplayNameOnUpdate)) { + // Need to update the refName, and then fix all references. + newRefNameOnUpdate = handleItemRefNameUpdateForDisplayName(wrapDoc.getWrappedObject(), newDisplayName); + } else { + // Mark as not needing attention in completeUpdate phase. + newRefNameOnUpdate = null; + oldRefNameOnUpdate = null; + } } /** @@ -147,6 +173,44 @@ public abstract class AuthorityItemDocumentModelHandler // Do nothing by default. } + /** + * Handle refName updates for changes to display name. + * Assumes refName is already correct. Just ensures it is right. + * + * @param docModel the doc model + * @throws Exception the exception + */ + protected String handleItemRefNameUpdateForDisplayName(DocumentModel docModel, + String newDisplayName) throws Exception { + //String suppliedRefName = (String) docModel.getProperty(authorityItemCommonSchemaName, + // AuthorityItemJAXBSchema.REF_NAME); + RefName.AuthorityItem authItem = RefName.AuthorityItem.parse(oldRefNameOnUpdate); + if(authItem == null) { + String err = "Authority Item has illegal refName: "+oldRefNameOnUpdate; + logger.debug(err); + throw new IllegalArgumentException(err); + } + authItem.displayName = newDisplayName; + String updatedRefName = authItem.toString(); + docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.REF_NAME, updatedRefName); + return updatedRefName; + } + + + /** + * Checks to see if the refName has changed, and if so, + * uses utilities to find all references and update them. + */ + protected void handleItemRefNameReferenceUpdate() { + if(newRefNameOnUpdate != null && oldRefNameOnUpdate!= null) { + // We have work to do. + logger.debug("Need to find and update references to Item."); + logger.debug("Old refName" + oldRefNameOnUpdate); + logger.debug("New refName" + newRefNameOnUpdate); + } + } + + private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception { String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER); String displayName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME); @@ -169,8 +233,17 @@ public abstract class AuthorityItemDocumentModelHandler String suppliedRefName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME); // CSPACE-3178: // Temporarily accept client-supplied refName values, rather than always generating such values. - // Remove the surrounding 'if' statement when clients should no longer supply refName values. - if (suppliedRefName == null || suppliedRefName.isEmpty()) { + // Remove first block and the surrounding 'if' statement when clients should no longer supply refName values. + if(!Tools.isEmpty(suppliedRefName) ) { + // Supplied refName must at least be legal + RefName.AuthorityItem item = RefName.AuthorityItem.parse(suppliedRefName); + if(item==null) { + logger.error("Passed refName for authority item not legal: "+suppliedRefName); + suppliedRefName = null; // Clear this and compute a new one below. + } + } + // Recheck, in case we cleared it for being illegal + if(Tools.isEmpty(suppliedRefName) ) { String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER); String displayName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME); if (Tools.isEmpty(authorityRefBaseName)) { @@ -386,6 +459,7 @@ public abstract class AuthorityItemDocumentModelHandler ServiceContext ctx = getServiceContext(); PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME); ((PoxPayloadOut) ctx.getOutput()).addPart(foo); + handleItemRefNameReferenceUpdate(); } /** updateRelations strategy: diff --git a/services/common-api/src/main/java/org/collectionspace/services/common/api/RefName.java b/services/common-api/src/main/java/org/collectionspace/services/common/api/RefName.java index 6a9370649..3ed0c33b7 100755 --- a/services/common-api/src/main/java/org/collectionspace/services/common/api/RefName.java +++ b/services/common-api/src/main/java/org/collectionspace/services/common/api/RefName.java @@ -3,6 +3,9 @@ package org.collectionspace.services.common.api; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Usage for this class, if you have a URN and would like to get at its fields, is to call one of these methods: * @@ -37,6 +40,9 @@ import java.util.regex.Pattern; * User: laramie */ public class RefName { + + /** The logger. */ + private static final Logger logger = LoggerFactory.getLogger(RefName.class); public static final String HACK_VOCABULARIES = "Vocabularies"; //TODO: get rid of these. public static final String HACK_ORGANIZATIONS = "Organizations"; //TODO: get rid of these. @@ -124,6 +130,9 @@ public class RefName { Matcher m = p.matcher(urn); if (m.find()) { if (m.groupCount() < 5) { + if (m.groupCount() == 4 && logger.isDebugEnabled()) { + logger.debug("AuthorityItem.parse only found 4 items; Missing displayName? Urn:"+urn); + } return null; } termInfo.inAuthority.tenantName = m.group(1); -- 2.47.3