From 6dd5845ca2d3d573d92cdcd5df574945ea20e6fd Mon Sep 17 00:00:00 2001 From: remillet Date: Fri, 22 Apr 2016 21:50:28 -0700 Subject: [PATCH] CSPACE-6937-A: Support for SAS item field and starting to add support for sync'ing hierarchy relationships. --- .../common/vocabulary/AuthorityResource.java | 122 ++++++++++------- .../vocabulary/AuthorityServiceUtils.java | 11 +- .../nuxeo/AuthorityDocumentModelHandler.java | 129 +++++++++++++++--- .../AuthorityItemDocumentModelHandler.java | 43 ++++-- 4 files changed, 218 insertions(+), 87 deletions(-) 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 51a12e20a..fe8bb78b6 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 @@ -218,7 +218,7 @@ public abstract class AuthorityResource protected String lookupParentCSID(String parentspecifier, String method, String op, UriInfo uriInfo) throws Exception { - CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(null, + CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(NULL_CONTEXT, parentspecifier, method, op, uriInfo); return tempResult.CSID; } @@ -592,13 +592,14 @@ public abstract class AuthorityResource * @param ctx * @param parentspecifier - ID of the container. Can be URN or CSID form * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS - * @param proposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority + * @param isProposed - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority * @return * @throws Exception */ protected Response createAuthorityItem(ServiceContext ctx, String parentIdentifier, boolean shouldUpdateRevNumber, - boolean proposed) throws Exception { + boolean isProposed, + boolean isSasItem) throws Exception { Response result = null; // Note: must have the parentShortId, to do the create. @@ -606,7 +607,8 @@ public abstract class AuthorityResource AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier); handler.setShouldUpdateRevNumber(shouldUpdateRevNumber); - handler.setIsProposed(proposed); + handler.setIsProposed(isProposed); + handler.setIsSASItem(isSasItem); // Make the client call String itemcsid = getRepositoryClient(ctx).create(ctx, handler); @@ -630,7 +632,8 @@ public abstract class AuthorityResource String parentIdentifier, PoxPayloadIn input, boolean shouldUpdateRevNumber, - boolean isProposed) throws Exception { + boolean isProposed, + boolean isSASItem) throws Exception { Response result = null; ServiceContext ctx = createServiceContext(getItemServiceName(), input, @@ -638,7 +641,7 @@ public abstract class AuthorityResource if (parentCtx.getCurrentRepositorySession() != null) { ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession()); } - result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed); + result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem); return result; } @@ -661,7 +664,7 @@ public abstract class AuthorityResource PoxPayloadIn input = new PoxPayloadIn(xmlPayload); ServiceContext ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo); result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV, - AuthorityServiceUtils.PROPOSED); + AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.CREATE_FAILED); } @@ -888,56 +891,56 @@ public abstract class AuthorityResource * Gets the authorityItem list for the specified authority * If partialPerm is specified, keywords will be ignored. * - * @param specifier either a CSID or one of the urn forms + * @param authorityIdentifier either a CSID or one of the urn forms * @param partialTerm if non-null, matches partial terms * @param keywords if non-null, matches terms in the keyword index for items * @param ui passed to include additional parameters, like pagination controls * */ public AbstractCommonList getAuthorityItemList(ServiceContext existingContext, - String specifier, + String authorityIdentifier, UriInfo uriInfo) throws Exception { AbstractCommonList result = null; - ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo); - MultivaluedMap queryParams = ctx.getQueryParams(); + ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo); + MultivaluedMap queryParams = ctx.getQueryParams(); if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); ctx.setProperties(existingContext.getProperties()); } - String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM); - String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS); - String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW); - String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS); - String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM); + String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM); + String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS); + String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW); + String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS); + String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM); - // For the wildcard case, parentcsid is null, but docHandler will deal with this. - // We omit the parentShortId, only needed when doing a create... - String parentcsid = PARENT_WILDCARD.equals(specifier) ? null : - lookupParentCSID(specifier, "getAuthorityItemList", "LIST", uriInfo); - DocumentHandler handler = - createItemDocumentHandler(ctx, parentcsid, null); - - DocumentFilter myFilter = handler.getDocumentFilter(); - // If we are not wildcarding the parent, add a restriction - if (parentcsid != null) { - myFilter.appendWhereClause(authorityItemCommonSchemaName + ":" - + AuthorityItemJAXBSchema.IN_AUTHORITY + "=" - + "'" + parentcsid + "'", - IQueryManager.SEARCH_QUALIFIER_AND); - } + // For the wildcard case, parentcsid is null, but docHandler will deal with this. + // We omit the parentShortId, only needed when doing a create... + String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null : + lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo); + DocumentHandler handler = + createItemDocumentHandler(ctx, parentcsid, null); + + DocumentFilter myFilter = handler.getDocumentFilter(); + // If we are not wildcarding the parent, add a restriction + if (parentcsid != null) { + myFilter.appendWhereClause(authorityItemCommonSchemaName + ":" + + AuthorityItemJAXBSchema.IN_AUTHORITY + "=" + + "'" + parentcsid + "'", + IQueryManager.SEARCH_QUALIFIER_AND); + } - if (Tools.notBlank(termStatus)) { - // Start with the qualified termStatus field - String qualifiedTermStatusField = authorityItemCommonSchemaName + ":" - + AuthorityItemJAXBSchema.TERM_STATUS; - String[] filterTerms = termStatus.trim().split("\\|"); - String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE); - myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND); - } + if (Tools.notBlank(termStatus)) { + // Start with the qualified termStatus field + String qualifiedTermStatusField = authorityItemCommonSchemaName + ":" + + AuthorityItemJAXBSchema.TERM_STATUS; + String[] filterTerms = termStatus.trim().split("\\|"); + String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE); + myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND); + } - result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm); + result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm); return result; } @@ -946,7 +949,7 @@ public abstract class AuthorityResource * Gets the authorityItem list for the specified authority * If partialPerm is specified, keywords will be ignored. * - * @param specifier either a CSID or one of the urn forms + * @param authorityIdentifier either a CSID or one of the urn forms * @param partialTerm if non-null, matches partial terms * @param keywords if non-null, matches terms in the keyword index for items * @param ui passed to include additional parameters, like pagination controls @@ -956,12 +959,12 @@ public abstract class AuthorityResource @GET @Path("{csid}/items") @Produces("application/xml") - public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier, + public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier, @Context UriInfo uriInfo) { AbstractCommonList result = null; try { - result = getAuthorityItemList(NULL_CONTEXT, specifier, uriInfo); + result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.LIST_FAILED); } @@ -1032,7 +1035,7 @@ public abstract class AuthorityResource ctx.setProperties(existingContext.getProperties()); } - String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo); + String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo); String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS"); List serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP); @@ -1063,6 +1066,7 @@ public abstract class AuthorityResource @PathParam("itemcsid") String itemspecifier, @Context UriInfo uriInfo) { AuthorityRefList authRefList = null; + try { // Note that we have to create the service context for the Items, not the main service ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo); @@ -1079,6 +1083,7 @@ public abstract class AuthorityResource } catch (Exception e) { throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier); } + return authRefList; } @@ -1101,6 +1106,7 @@ public abstract class AuthorityResource CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null); AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier); handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag + handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item // Create an authority item specifier Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET"); Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET"); @@ -1207,7 +1213,8 @@ public abstract class AuthorityResource PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload); result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate, AuthorityServiceUtils.UPDATE_REV, // passing TRUE so rev num increases, passing - AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "proposed" field -we could be performing a sync or just a plain update + AuthorityServiceUtils.NO_CHANGE, // don't change the state of the "proposed" field -we could be performing a sync or just a plain update + AuthorityServiceUtils.NO_CHANGE); // don't change the state of the "sas" field -we could be performing a sync or just a plain update } catch (Exception e) { throw bigReThrow(e, ServiceMessages.UPDATE_FAILED); } @@ -1223,7 +1230,9 @@ public abstract class AuthorityResource String itemspecifier, PoxPayloadIn theUpdate, boolean shouldUpdateRevNumber, - Boolean isProposed) throws Exception { + Boolean isProposed, + Boolean isSASItem + ) throws Exception { PoxPayloadOut result = null; CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null); @@ -1247,6 +1256,9 @@ public abstract class AuthorityResource if (isProposed != null) { handler.setIsProposed(isProposed); } + if (isSASItem != null) { + handler.setIsSASItem(isSASItem); + } getRepositoryClient(ctx).update(ctx, itemcsid, handler); result = ctx.getOutput(); @@ -1277,7 +1289,7 @@ public abstract class AuthorityResource try { ServiceContext ctx = createServiceContext(getItemServiceName(), uriInfo); - deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier); + deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV); result = Response.status(HttpResponseCodes.SC_OK).build(); } catch (Exception e) { throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier); @@ -1295,19 +1307,23 @@ public abstract class AuthorityResource */ public void deleteAuthorityItem(ServiceContext existingCtx, String parentIdentifier, - String itemIdentifier) throws Exception { + String itemIdentifier, + boolean shouldUpdateRevNumber + ) throws Exception { Response result = null; ServiceContext ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo()); - String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null); - String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null - - if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) { - ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists + if (existingCtx != null) { + ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); ctx.setProperties(existingCtx.getProperties()); } + String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null); + String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null + DocumentHandler handler = createDocumentHandler(ctx); + ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, shouldUpdateRevNumber); // Sometimes we can only soft-delete, so if it is during a sync we dont' update the revision number + getRepositoryClient(ctx).delete(ctx, itemCsid, handler); } diff --git a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityServiceUtils.java b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityServiceUtils.java index 1cdec5731..498e97908 100644 --- a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityServiceUtils.java +++ b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityServiceUtils.java @@ -12,6 +12,7 @@ import org.collectionspace.services.common.context.MultipartServiceContextImpl; import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier; import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier; +import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm; import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityIdentifierUtils; import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface; import org.collectionspace.services.nuxeo.util.NuxeoUtils; @@ -37,6 +38,9 @@ public class AuthorityServiceUtils { public static final String IS_PROPOSED_PROPERTY = "IS_PROPOSED"; public static final Boolean PROPOSED = true; public static final Boolean NOT_PROPOSED = !PROPOSED; + public static final Boolean SAS_ITEM = true; + public static final Boolean NOT_SAS_ITEM = !SAS_ITEM; + public static final Boolean NO_CHANGE = null; static public PoxPayloadIn requestPayloadIn(ServiceContext ctx, Specifier specifier, Class responseType) throws Exception { @@ -137,14 +141,15 @@ public class AuthorityServiceUtils { * @param itemInfo * @throws Exception */ - static public boolean markAuthorityItemAsDeprecated(ServiceContext ctx, String authorityItemCommonSchemaName, String itemCsid) throws Exception { + static public boolean markAuthorityItemAsDeprecated(ServiceContext ctx, String authorityItemCommonSchemaName, AuthorityItemSpecifier authorityItemSpecifier) throws Exception { boolean result = false; try { - DocumentModel docModel = NuxeoUtils.getDocFromCsid(ctx, (CoreSessionInterface)ctx.getCurrentRepositorySession(), itemCsid); + DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, (CoreSessionInterface)ctx.getCurrentRepositorySession(), + authorityItemCommonSchemaName, authorityItemSpecifier); result = setAuthorityItemDeprecated(ctx, docModel, authorityItemCommonSchemaName, AuthorityServiceUtils.DEPRECATED); } catch (Exception e) { - logger.warn(String.format("Could not mark item '%s' as deprecated.", itemCsid), e); + logger.warn(String.format("Could not mark item '%s' as deprecated.", authorityItemSpecifier.getItemSpecifier().getURNValue()), e); throw e; } diff --git a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityDocumentModelHandler.java b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityDocumentModelHandler.java index c2a89e740..e9d2427df 100644 --- a/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityDocumentModelHandler.java +++ b/services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityDocumentModelHandler.java @@ -184,8 +184,8 @@ public abstract class AuthorityDocumentModelHandler List itemList = getItemList(sasPayloadInItemList); if (itemList != null) { for (Element e:itemList) { - String remoteRefName = XmlTools.getElementValue(e, "refName"); - itemsInRemoteAuthority.add(remoteRefName); + String remoteRefName = XmlTools.getElementValue(e, AuthorityItemJAXBSchema.REF_NAME); + itemsInRemoteAuthority.add(XmlTools.getElementValue(e, AuthorityItemJAXBSchema.SHORT_IDENTIFIER)); long status = syncRemoteItemWithLocalItem(ctx, remoteRefName); if (status == 1) { created++; @@ -203,8 +203,9 @@ public abstract class AuthorityDocumentModelHandler // of the remote items have been hard deleted. // ArrayList itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasAuthoritySpecifier); - if (itemsInLocalAuthority.removeAll(itemsInRemoteAuthority) == true) { - ArrayList remainingItems = itemsInLocalAuthority; // now a subset of local items + itemsInLocalAuthority.removeAll(itemsInRemoteAuthority); + if (itemsInLocalAuthority.size() > 0) { + ArrayList remainingItems = itemsInLocalAuthority; // now a subset of local items that no longer exist on the SAS, so we need to try to delete them (or mark them as deprecated if they still have records referencing them) // // We now need to either hard-deleted or deprecate the remaining authorities // @@ -213,8 +214,26 @@ public abstract class AuthorityDocumentModelHandler throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization."); } } - - + // + // We need to synchronize the hierarchy relationships + // + itemList = getItemList(sasPayloadInItemList); // Really need to re-request the sasPayload? I don't think so. + if (itemList != null) { + for (Element e:itemList) { + String remoteRefName = XmlTools.getElementValue(e, "refName"); + itemsInRemoteAuthority.add(remoteRefName); + long status = syncRemoteItemRelationshipsWithLocalItem(ctx, remoteRefName); + if (status == 1) { + created++; + } else if (status == 0) { + synched++; + } else { + alreadySynched++; + } + totalItemsProcessed++; + } + } + logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed)); logger.info(String.format("Number of items synchronized: %d", synched)); logger.info(String.format("Number of items created during sync: %d", created)); @@ -224,7 +243,7 @@ public abstract class AuthorityDocumentModelHandler } /** - * + * This method should only be used as part of a SAS synch operation. * @param ctx * @param refNameList * @return @@ -233,25 +252,29 @@ public abstract class AuthorityDocumentModelHandler private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList refNameList) throws Exception { long result = 0; - ArrayList failureList = new ArrayList(); - ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); - - for (String refName:refNameList) { - AuthorityTermInfo itemInfo = RefNameUtils.parseAuthorityTermInfo(refName); + ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item + for (String itemRefName:refNameList) { + AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName); + AuthorityItemSpecifier authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityTermInfo.inAuthority.name, + authorityTermInfo.name); + AuthorityResource authorityResource = (AuthorityResource) ctx.getResource(); try { - authorityResource.deleteAuthorityItem(ctx, itemInfo.inAuthority.csid, itemInfo.csid); + authorityResource.deleteAuthorityItem(ctx, + Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name), + Specifier.createShortIdURNValue(authorityTermInfo.name), + AuthorityServiceUtils.DONT_UPDATE_REV); // Since we're sync'ing, we shouldn't update the revision number (obviously this only applies to soft-deletes since hard-deletes destroy the record) result++; } catch (DocumentReferenceException de) { logger.info(String.format("Authority item '%s' has existing references and cannot be removed during sync.", - refName), de); + itemRefName), de); boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName, - itemInfo.csid); + authorityItemSpecificer); if (marked == true) { result++; } } catch (Exception e) { - logger.warn(String.format("Unable to delete authority item '%s'", refName), e); + logger.warn(String.format("Unable to delete authority item '%s'", itemRefName), e); throw e; } } @@ -273,22 +296,23 @@ public abstract class AuthorityDocumentModelHandler * We need to add pagination support to this call!!! * * @param ctx - * @param specifier + * @param authoritySpecifier * @return * @throws Exception */ - private ArrayList getItemsInLocalAuthority(ServiceContext ctx, Specifier specifier) throws Exception { + private ArrayList getItemsInLocalAuthority(ServiceContext ctx, Specifier authoritySpecifier) throws Exception { ArrayList result = new ArrayList(); ResourceMap resourceMap = ctx.getResourceMap(); String resourceName = ctx.getClient().getServiceName(); AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName); - AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, specifier.value, ctx.getUriInfo()); + AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, authoritySpecifier.getURNValue(), ctx.getUriInfo()); + List listItemList = acl.getListItem(); for (ListItem listItem:listItemList) { Boolean proposed = getBooleanValue(listItem, AuthorityItemJAXBSchema.PROPOSED); if (proposed == false) { // exclude "proposed" (i.e., local-only items) - result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME)); + result.add(AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.SHORT_IDENTIFIER)); } } @@ -311,7 +335,8 @@ public abstract class AuthorityDocumentModelHandler } /** - * This is a sync method. + * This method should only be used during a SAS synchronization request. + * * @param ctx * @param parentIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid) * @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid) @@ -335,7 +360,7 @@ public abstract class AuthorityDocumentModelHandler // AuthorityResource authorityResource = (AuthorityResource) ctx.getResource(); Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.getURNValue(), - sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED); + sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED, AuthorityServiceUtils.SAS_ITEM); // // Check the response for successful POST result // @@ -404,6 +429,66 @@ public abstract class AuthorityDocumentModelHandler return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item } + + /** + * Ensure the local items relationships look the same as the remote items' by synchronizing the hierarchy relationship records + * of the SAS item with the local item. + * + * @param ctx + * @param refName + * @return + * @throws Exception + */ + protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception { + long result = -1; + // + // WARNING: THIS CODE IS NOT IMPLEMENTED YET + // + return result; + // + // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions + // + + /* + AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName); + String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name); + String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name); + // + // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates) + // + AuthorityResource authorityResource = (AuthorityResource) ctx.getResource(); + PoxPayloadOut localItemPayloadOut; + try { + localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier); + } catch (DocumentNotFoundException dnf) { + // + // Document not found, means we need to create an item/term that exists only on the SAS + // + logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName)); + createLocalItem(ctx, parentIdentifier, itemIdentifier); + return 1; // exit with status of 1 means we created a new authority item + } + // + // If we get here, we know the item exists both locally and remotely, so we need to synchronize them. + // + // + try { + PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier); + if (theUpdate != null) { + result = 0; // means we needed to sync this item with SAS + logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s", + parentIdentifier, itemIdentifier, theUpdate.getXmlPayload())); + } + } catch (DocumentReferenceException de) { // Exception for items that still have records/resource referencing them. + result = -1; + logger.error(String.format("Could not sync authority item = '%s' because it has existing records referencing it.", + itemIdentifier)); + } + + return result; // -1 = no sync needed/possible, 0 = sync'd, 1 = created new item + */ + + } private PoxPayloadIn requestPayloadInItemList(ServiceContext ctx, Specifier specifier) throws Exception { PoxPayloadIn result = null; 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 bef1d4517..4153c69cf 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 @@ -98,6 +98,7 @@ public abstract class AuthorityItemDocumentModelHandler private String authorityItemTermGroupXPathBase; private boolean isProposed = false; // used by local authority to propose a new shared item. Allows local deployments to use new terms until they become official + private boolean isSAS = false; // used to indicate if the authority item originated as a SAS item private boolean shouldUpdateRevNumber = true; // by default we should update the revision number -not true on synchronization with SAS /** * inVocabulary is the parent Authority for this context @@ -127,6 +128,17 @@ public abstract class AuthorityItemDocumentModelHandler this.isProposed = flag; } + // + // Getter and Setter for 'isSAS' + // + public boolean getIsSASItem() { + return this.isSAS; + } + + public void setIsSASItem(boolean flag) { + this.isSAS = flag; + } + // // Getter and Setter for 'shouldUpdateRevNumber' // @@ -449,12 +461,13 @@ public abstract class AuthorityItemDocumentModelHandler PoxPayloadOut payloadOut = authorityResource.updateAuthorityItem(ctx, ctx.getResourceMap(), ctx.getUriInfo(), - localParentCsid, // parent's CSID - localItemCsid, // item's CSID - sasPayloadIn, // the payload from the remote SAS + localParentCsid, // parent's CSID + localItemCsid, // item's CSID + sasPayloadIn, // the payload from the remote SAS AuthorityServiceUtils.DONT_UPDATE_REV, // don't update the parent's revision number - AuthorityServiceUtils.NOT_PROPOSED); // The items is not proposed, make it a real SAS item now - if (payloadOut != null) { + AuthorityServiceUtils.NOT_PROPOSED, // The items is not proposed, make it a real SAS item now + AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this must be a SAS item + if (payloadOut != null) { ctx.setOutput(payloadOut); result = true; } @@ -482,6 +495,9 @@ public abstract class AuthorityItemDocumentModelHandler } result = true; } + // + // We need to synchronize the hierarchy relationships here. + // return result; } @@ -623,9 +639,10 @@ public abstract class AuthorityItemDocumentModelHandler // ctx.setUriInfo(this.getServiceContext().getUriInfo()); // try to get a UriInfo instance from the handler's context } - ctx.getUriInfo().getQueryParameters().addFirst(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED, Boolean.toString(onlyRefsToDeletedObjects)); // Add the wf_deleted query param to the resource call + ctx.getUriInfo().getQueryParameters().addFirst(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED, Boolean.toString(onlyRefsToDeletedObjects)); // Add the wf_only_deleted query param to the resource call AuthorityRefDocList refObjs = authorityResource.getReferencingObjects(ctx, inAuthorityCsid, itemCsid, uriTemplateRegistry, ctx.getUriInfo()); + ctx.getUriInfo().getQueryParameters().remove(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED); // Need to clear wf_only_deleted values to prevent unexpected side effects result = refObjs.getTotalItems(); if (result > 0) { @@ -722,18 +739,26 @@ public abstract class AuthorityItemDocumentModelHandler // public void fillAllParts(DocumentWrapper wrapDoc, Action action) throws Exception { super.fillAllParts(wrapDoc, action); + DocumentModel documentModel = wrapDoc.getWrappedObject(); + // - // Update the record's revision number on both CREATE and UPDATE actions + // Update the record's revision number on both CREATE and UPDATE actions (as long as it is NOT a SAS authority item) // - if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS + Boolean propertyValue = (Boolean) documentModel.getProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.SAS); + boolean isMarkedAsSASItem = propertyValue != null ? propertyValue : false; + if (this.getShouldUpdateRevNumber() == true && !isMarkedAsSASItem) { // We won't update rev numbers on synchronization with SAS items and on local changes to SAS items updateRevNumbers(wrapDoc); } // // If this is a proposed item (not part of the SAS), mark it as such // - DocumentModel documentModel = wrapDoc.getWrappedObject(); documentModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.PROPOSED, new Boolean(this.getIsProposed())); + // + // If it is a SAS authority item, mark it as such + // + documentModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.SAS, + new Boolean(this.getIsSASItem())); } /** -- 2.47.3