]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-6937-A: Adding support for deleting and/or deprecated local terms that no...
authorRichard Millet <remillet@yahoo.com>
Mon, 18 Apr 2016 15:22:42 +0000 (08:22 -0700)
committerRichard Millet <remillet@yahoo.com>
Mon, 18 Apr 2016 15:22:42 +0000 (08:22 -0700)
14 files changed:
services/authority/jaxb/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemJAXBSchema.java
services/authority/jaxb/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemListItemJAXBSchema.java
services/authority/jaxb/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityJAXBSchema.java
services/authority/jaxb/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityListItemJAXBSchema.java
services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java
services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityServiceUtils.java
services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityDocumentModelHandler.java
services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java
services/client/src/main/java/org/collectionspace/services/client/AbstractCommonListUtils.java
services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java
services/common/src/main/java/org/collectionspace/services/common/ResourceMap.java
services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java
services/common/src/main/java/org/collectionspace/services/common/workflow/service/nuxeo/WorkflowDocumentModelHandler.java

index 2a1397a4f02dc4765221fbdf9c91fe21aba31aad..3d4172699091c6a04122825796f82145f4d6edc7 100644 (file)
@@ -34,6 +34,9 @@ public interface AuthorityItemJAXBSchema {
     final static String SHORT_IDENTIFIER = "shortIdentifier";
     final static String CSID = "csid";
     final static String REV = "rev";
+    final static String SAS = "sas";
+    final static String DEPRECATED = "deprecated";
+    final static String PROPOSED = "proposed";
     final static String DISPLAY_NAME = "displayName"; // This is the display name element for the Vocabulary service's item    
     final static String TERM_DISPLAY_NAME = "termDisplayName"; // This is the display name element for all Authority services' items
     final static String TERM_NAME = "termName";
index e12f0b6516a5c86f7f7d081d40f3881a733ef395..2735496e3d1d569bb3b054e12493890539eebcdb 100644 (file)
@@ -29,6 +29,9 @@ public interface AuthorityItemListItemJAXBSchema {
        final static String REF_NAME = "refName";
        final static String SHORT_IDENTIFIER = "shortIdentifier";
        final static String CSID = "csid";
-    final static String REV = "rev";   
+    final static String REV = "rev";
+    final static String SAS = "sas";
+    final static String PROPOSED = "proposed";
+    final static String DEPRECATED = "deprecated";
        final static String URI = "url";
 }
index d3cfd7127286ac52ee2e8589c72f375457b4a4f3..b0714322d53008beb2bac6839ebe09076fd1ee1f 100644 (file)
@@ -30,6 +30,7 @@ public interface AuthorityJAXBSchema {
        final static String VOCAB_TYPE = "vocabType";
        final static String CSID = "csid";
     final static String REV = "rev";
+    final static String SAS = "sas"; // boolean flag indicating if authority is a shared authority
 }
 
 
index a4d1280966895794c0e56a679505d24cec2a70f3..c1c0933475665d4c68f065ef86e9a01e297746b9 100644 (file)
@@ -30,5 +30,6 @@ public interface AuthorityListItemJAXBSchema {
        final static String VOCAB_TYPE = "vocabType";
        final static String CSID = "csid";
     final static String REV = "rev";
+    final static String SAS = "sas"; // boolean flag indicating if authority is a shared authority item
        final static String URI = "url";
 }
index c6bb8652ed8dfac6968883f63336fdebf8909c04..c52f3cf3fde517bec65f4612f20a0b81f9909996 100644 (file)
@@ -95,24 +95,14 @@ import org.slf4j.LoggerFactory;
 /**
  * The Class AuthorityResource.
  */
-/**
- * @author pschmitz
- *
- * @param <AuthCommon>
- * @param <AuthItemHandler>
- */
-/**
- * @author pschmitz
- *
- * @param <AuthCommon>
- * @param <AuthItemHandler>
- */
+
 @Consumes("application/xml")
 @Produces("application/xml")
 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         extends NuxeoBasedResource {
        
        final static String SEARCH_TYPE_TERMSTATUS = "ts";
+    public final static String hierarchy = "hierarchy";
 
     protected Class<AuthCommon> authCommonClass;
     protected Class<?> resourceClass;
@@ -398,6 +388,7 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
             AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
             specifier = getSpecifier(csid, "getAuthority", "GET");
+            handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
             neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
             payloadOut = ctx.getOutput();
         } catch (Exception e) {
@@ -622,7 +613,18 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         }
     }
     
-    protected Response createAuthorityItem(ServiceContext ctx, String parentspecifier, boolean shouldUpdateRevNumber) throws Exception {
+    /**
+     * 
+     * @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
+     * @return
+     * @throws Exception
+     */
+    protected Response createAuthorityItem(ServiceContext ctx, String parentspecifier,
+               boolean shouldUpdateRevNumber,
+               boolean proposed) throws Exception {
        Response result = null;
        
         // Note: must have the parentShortId, to do the create.
@@ -630,6 +632,7 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         AuthorityItemDocumentModelHandler handler = 
                (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
+        handler.setIsProposed(proposed);
         String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
         UriBuilder path = UriBuilder.fromResource(resourceClass);
         path.path(parent.CSID + "/items/" + itemcsid);
@@ -649,7 +652,8 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
     public Response createAuthorityItemWithParentContext(ServiceContext parentCtx,
                String parentspecifier,
                PoxPayloadIn input,
-               boolean shouldUpdateRevNumber) throws Exception {
+               boolean shouldUpdateRevNumber,
+               boolean isProposed) throws Exception {
        Response result = null;
        
         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
@@ -657,7 +661,7 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         if (parentCtx.getCurrentRepositorySession() != null) {
                ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
         }
-        result = this.createAuthorityItem(ctx, parentspecifier, shouldUpdateRevNumber);
+        result = this.createAuthorityItem(ctx, parentspecifier, shouldUpdateRevNumber, isProposed);
 
        return result;
     }
@@ -679,7 +683,8 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         try {
             PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
-            result = this.createAuthorityItem(ctx, parentspecifier, AuthorityServiceUtils.UPDATE_REV);
+            result = this.createAuthorityItem(ctx, parentspecifier, AuthorityServiceUtils.UPDATE_REV,
+                       AuthorityServiceUtils.PROPOSED);
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
         }
@@ -732,14 +737,14 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
     /**
      * Update an authority item's workflow state.
      * @param existingContext
-     * @param csid
-     * @param itemcsid
+     * @param parentCsid
+     * @param itemCsid
      * @param transition
      * @return
      */
     public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext existingContext,
-            String csid,
-            String itemcsid,
+            String parentCsid,
+            String itemCsid,
             String transition,
             boolean updateRevNumber) {
        PoxPayloadOut result = null;
@@ -772,10 +777,10 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
             ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
             
             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
-            getRepositoryClient(ctx).update(ctx, itemcsid, handler);
+            getRepositoryClient(ctx).update(ctx, itemCsid, handler);
             result = ctx.getOutput();
         } catch (Exception e) {
-            throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
+            throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemCsid);
         }
        
        return result;
@@ -882,6 +887,63 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
                return result;
        }
     
+    /**
+     * Return a paged list of authority items.
+     * 
+     * @param existingContext
+     * @param specifier
+     * @param uriInfo
+     * @return
+     * @throws Exception
+     */
+    public AbstractCommonList getAuthorityItemList(ServiceContext existingContext,
+               String specifier,
+            UriInfo uriInfo) throws Exception {
+       AbstractCommonList result = null;
+
+        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
+        MultivaluedMap<String, String> 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);
+
+        // 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<?, AbstractCommonList, DocumentModel, DocumentModelList> 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);
+        }
+
+        result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);        
+       
+       return result;
+    }
+    
     /**
      * Gets the authorityItem list for the specified authority
      * If partialPerm is specified, keywords will be ignored.
@@ -901,41 +963,7 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
        AbstractCommonList result = null;
        
         try {
-            ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
-            MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
-            
-            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<?, AbstractCommonList, DocumentModel, DocumentModelList> 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);
-            }
-
-            result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);            
+            result = getAuthorityItemList(NULL_CONTEXT, specifier, uriInfo);    
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.LIST_FAILED);
         }
@@ -958,8 +986,8 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
      * for the service bindings. If not set, the type defaults to
      * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
      *
-     * @param parentspecifier either a CSID or one of the urn forms
-     * @param itemspecifier either a CSID or one of the urn forms
+     * @param parentSpecifier either a CSID or one of the urn forms
+     * @param itemSpecifier either a CSID or one of the urn forms
      * @param ui the ui
      * 
      * @return the info for the referencing objects
@@ -968,40 +996,59 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
     @Path("{csid}/items/{itemcsid}/refObjs")
     @Produces("application/xml")
     public AuthorityRefDocList getReferencingObjects(
-            @PathParam("csid") String parentspecifier,
-            @PathParam("itemcsid") String itemspecifier,
+            @PathParam("csid") String parentSpecifier,
+            @PathParam("itemcsid") String itemSpecifier,
             @Context UriTemplateRegistry uriTemplateRegistry,
             @Context UriInfo uriInfo) {
         AuthorityRefDocList authRefDocList = null;
         try {
-            ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
-            MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
-
-            String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
-            String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
-
-            List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
-            if(serviceTypes == null || serviceTypes.isEmpty()) {
-               serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
-            }
-            
-            // Note that we have to create the service context for the Items, not the main service
-            // We omit the parentShortId, only needed when doing a create...
-            AuthorityItemDocumentModelHandler<?> handler = (AuthorityItemDocumentModelHandler<?>)
-                                                                                               createItemDocumentHandler(ctx, parentcsid, null);
-
-            authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
+            authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.GET_FAILED);
         }
+        
         if (authRefDocList == null) {
             Response response = Response.status(Response.Status.NOT_FOUND).entity(
-                    "Get failed, the requested Item CSID:" + itemspecifier + ": was not found.").type(
+                    "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
                     "text/plain").build();
             throw new CSWebApplicationException(response);
         }
         return authRefDocList;
     }
+    
+    public AuthorityRefDocList getReferencingObjects(
+               ServiceContext existingContext,
+            String parentspecifier,
+            String itemspecifier,
+            UriTemplateRegistry uriTemplateRegistry,
+            UriInfo uriInfo) throws Exception {
+       AuthorityRefDocList authRefDocList = null;
+       
+        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
+        MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
+        //
+        // Merge parts of existing context with our new context
+        //
+        if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
+               ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());  // If one exists, use the existing repo session
+               ctx.setProperties(existingContext.getProperties());
+        }
+
+        String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
+        String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
+
+        List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
+        if(serviceTypes == null || serviceTypes.isEmpty()) {
+               serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
+        }
+        
+        // Note that we have to create the service handler for the Items, not the main parent resource
+        // We omit the parentShortId, only needed when doing a create...
+        AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
+        authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
+
+       return authRefDocList;
+    }
 
     /**
      * Gets the authority terms used in the indicated Authority item.
@@ -1047,7 +1094,7 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
      * @return
      * @throws Exception
      */
-    protected PoxPayloadOut synchronizeItem(
+    private PoxPayloadOut synchronizeItem(
                ServiceContext ctx,
             String parentIdentifier,
             String itemIdentifier) throws Exception {
@@ -1058,6 +1105,8 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
 
         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
+        // Create an authority item specifier
         Specifier parentSpecifier = getSpecifier(parent.CSID, "getAuthority", "GET");
         Specifier itemSpecifier = getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
         specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
@@ -1162,7 +1211,8 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         try {
             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
             result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
-                       AuthorityServiceUtils.UPDATE_REV); // passing TRUE so rev num increases
+                       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
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
         }
@@ -1177,7 +1227,8 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
             String parentspecifier,
             String itemspecifier,
             PoxPayloadIn theUpdate,
-            boolean shouldUpdateRevNumber) throws Exception {
+            boolean shouldUpdateRevNumber,
+            Boolean isProposed) throws Exception {
         PoxPayloadOut result = null;
         
         CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
@@ -1198,6 +1249,9 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
         // We omit the parentShortId, only needed when doing a create...
         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
+        if (isProposed != null) {
+               handler.setIsProposed(isProposed);
+        }
         getRepositoryClient(ctx).update(ctx, itemcsid, handler);
         result = ctx.getOutput();
 
@@ -1217,29 +1271,39 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
     public Response deleteAuthorityItem(
             @PathParam("csid") String parentcsid,
             @PathParam("itemcsid") String itemcsid) {
-        //try{
+       Response result = null;
+       
         if (logger.isDebugEnabled()) {
             logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
         }
+        
         try {
-            ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
-            ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
-            //Laramie, removing this catch, since it will surely fail below, since itemcsid or parentcsid will be null.
-            // }catch (Throwable t){
-            //    System.out.println("ERROR in setting up DELETE: "+t);
-            // }
-            // try {
-            // Note that we have to create the service context for the Items, not the main service
-            ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
-            DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
-            getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
-            return Response.status(HttpResponseCodes.SC_OK).build();
+            deleteAuthorityItem(null, parentcsid, itemcsid);
+            result = Response.status(HttpResponseCodes.SC_OK).build();
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.DELETE_FAILED + "  itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
         }
+        
+        return result;
     }
-    public final static String hierarchy = "hierarchy";
-
+    
+    public void deleteAuthorityItem(ServiceContext existingCtx,
+            String parentcsid,
+            String itemcsid) throws Exception {
+       Response result = null;
+       
+        ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
+        ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
+        // Note that we have to create the service context for the Items, not the main service
+        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
+        if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
+               ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists
+               ctx.setProperties(existingCtx.getProperties());
+        }
+        DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
+        getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
+    }
+    
     @GET
     @Path("{csid}/items/{itemcsid}/" + hierarchy)
     @Produces("application/xml")
index 7213612d2964e0c58ca8ffa47c436856e893feef..d192bf53b0ee54014c9855a30d2fcd49495fd8c6 100644 (file)
@@ -15,9 +15,21 @@ import org.slf4j.LoggerFactory;
 public class AuthorityServiceUtils {
     private static final Logger logger = LoggerFactory.getLogger(AuthorityIdentifierUtils.class);
 
+    // Used to keep track if an authority item's is deprecated
+    public static final String IS_DEPRECATED_PROPERTY = "IS_DEPRECATED_PROPERTY";
+    public static final Boolean DEPRECATED = true;
+    public static final Boolean NOT_DEPRECATED = !DEPRECATED;
+    
+    // Used to keep track if an authority item's rev number should be updated
     public static final String SHOULD_UPDATE_REV_PROPERTY = "SHOULD_UPDATE_REV_PROPERTY";
-    public static final boolean DONT_UPDATE_REV = false;
     public static final boolean UPDATE_REV = true;
+    public static final boolean DONT_UPDATE_REV = !UPDATE_REV;
+    
+    // Used to keep track if an authority item is a locally proposed member of a SAS authority
+    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 NO_CHANGE = null;
 
     static public PoxPayloadIn requestPayloadIn(ServiceContext ctx, Specifier specifier, Class responseType) throws Exception {
        PoxPayloadIn result = null;
index ee0ead044881e8f737f2bbc9930acc320fb870af..72ccc315aa98c4db68b014a49fd6252bc559466f 100644 (file)
  */
 package org.collectionspace.services.common.vocabulary.nuxeo;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
 import javax.ws.rs.core.Response;
 
+import org.collectionspace.services.client.AbstractCommonListUtils;
 import org.collectionspace.services.client.AuthorityClient;
 import org.collectionspace.services.client.CollectionSpaceClient;
 import org.collectionspace.services.client.PayloadInputPart;
 import org.collectionspace.services.client.VocabularyClient;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.XmlTools;
 import org.collectionspace.services.common.api.RefName;
@@ -55,6 +58,8 @@ import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Author
 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
 import org.collectionspace.services.config.service.ObjectPartType;
+import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
 import org.collectionspace.services.lifecycle.TransitionDef;
 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
@@ -123,7 +128,7 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
         Specifier specifier = (Specifier) wrapDoc.getWrappedObject();
         //
-        // Get the rev number of the authority so we can compare with rev number of shared authority
+        // Get the rev number and short ID of the local authority
         //
         DocumentModel docModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName, specifier);
         Long localRev = (Long) NuxeoUtils.getProperyValue(docModel, AuthorityJAXBSchema.REV);
@@ -134,12 +139,13 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
         Specifier sasSpecifier = new Specifier(SpecifierForm.URN_NAME, RefNameUtils.createShortIdRefName(shortId));
         PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(ctx, sasSpecifier, getEntityResponseType());
         //
+        // Compare revision number of local authority with that of the shared authority on the SAS.
         // If the authority on the SAS is newer, synch all the items and then the authority record as well
         //
         Long sasRev = getRevision(sasPayloadIn);
         if (sasRev > localRev) {
                //
-               // First, sync all the authority items
+               // First, synchronize all the authority item records/resources.
                //
                syncAllItems(ctx, sasSpecifier);
                //
@@ -148,6 +154,8 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
                ResourceMap resourceMap = ctx.getResourceMap();
                String resourceName = ctx.getClient().getServiceName();
                AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
+               // Set this context property since we don't want to update the revision number on sync updates
+               ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, AuthorityServiceUtils.DONT_UPDATE_REV);
                PoxPayloadOut payloadOut = authorityResource.update(ctx, resourceMap, ctx.getUriInfo(), docModel.getName(), 
                                sasPayloadIn);
                if (payloadOut != null) {
@@ -168,7 +176,9 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
        int created = 0;
        int synched = 0;
        int alreadySynched = 0;
+       int deprecated = 0;
        int totalItemsProcessed = 0;
+       ArrayList<String> itemsInRemoteAuthority = new ArrayList<String>();
        //
        // Iterate over the list of items/terms in the remote authority
        //
@@ -177,6 +187,7 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
         if (itemList != null) {
                for (Element e:itemList) {
                        String remoteRefName = XmlTools.getElementValue(e, "refName");
+                       itemsInRemoteAuthority.add(remoteRefName);
                        long status = syncRemoteItemWithLocalItem(ctx, remoteRefName);
                        if (status == 1) {
                                created++;
@@ -188,6 +199,20 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
                        totalItemsProcessed++;
                }
         }
+        //
+        // Now see if we need to deprecate or delete items that have been hard-deleted from the SAS but still exist
+        // locally.  Subtract (remove) the list of remote items from the list of local items to determine which
+        // of the remote items have been hard deleted.
+        //
+       ArrayList<String> itemsInLocalAuthority = getItemsInLocalAuthority(ctx, sasSpecifier);
+       if (itemsInLocalAuthority.removeAll(itemsInRemoteAuthority) == true) {
+               ArrayList<String> remainingItems = itemsInLocalAuthority; // now a subset of local items
+               //
+               // We now need to either hard-deleted or deprecate the remaining authorities
+               //
+               deleteOrDeprecateItems(ctx, remainingItems);
+       }
+
         
         logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
         logger.info(String.format("Number of items synchronized: %d", synched));
@@ -197,6 +222,109 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
         return result;
     }
     
+    private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList<String> refNameList) throws Exception {
+       long result = 0;
+       ArrayList<String> failureList = new ArrayList<String>();
+       
+       for (String refName:refNameList) {
+               AuthorityTermInfo itemInfo = RefNameUtils.parseAuthorityTermInfo(refName);
+               AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
+               try {
+                       authorityResource.deleteAuthorityItem(ctx, itemInfo.inAuthority.csid, itemInfo.csid);
+                       result++;
+               } catch (DocumentException de) {
+                       //
+                       // If we can't delete the item, it might be because there are existing records referencing it. So
+                       // we need to mark the item as deprecated
+                       //
+                       logger.info(String.format("Hit document exception trying to delete or deprecate '%s' during sync",
+                                       refName), de);
+                       boolean marked = markAuthorityItemAsDeprecated(ctx, itemInfo);
+                       if (marked == true) {
+                               result++;
+                       }
+               } catch (Exception e) {
+                       logger.warn(String.format("Unable to delete authority item '%s'", refName), e);
+               }
+       }
+       
+       if (logger.isWarnEnabled() == true) {
+               if (result != refNameList.size()) {
+                       logger.warn(String.format("Unable to delete or deprecate some authority items during synchronization with SAS.  Deleted or deprecated %d of %d",
+                                       result, refNameList.size()));
+               }
+       }
+       
+       return result;
+    }
+    
+    /**
+     * Mark the authority item as deprecated.
+     * 
+     * @param ctx
+     * @param itemInfo
+     * @throws Exception
+     */
+    private boolean markAuthorityItemAsDeprecated(ServiceContext ctx, AuthorityTermInfo itemInfo) throws Exception {
+       boolean result = false;
+       
+       try {
+               String itemCsid = itemInfo.csid;
+               DocumentModel docModel = NuxeoUtils.getDocFromCsid(ctx, (CoreSessionInterface)ctx.getCurrentRepositorySession(), itemCsid);
+               docModel.setProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.DEPRECATED,
+                               new Boolean(AuthorityServiceUtils.DEPRECATED));
+               result = true;
+       } catch (Exception e) {
+               logger.warn(String.format("Could not mark item '%s' as deprecated.", itemInfo.name), e);
+       }
+       
+       return result;
+    }
+    
+    /**
+     * Gets the list of SAS related items in the local authority.  We exlude items with the "proposed" flags because
+     * we want a list with only SAS created items.
+     * 
+     * We need to add pagination support to this call!!!
+     * 
+     * @param ctx
+     * @param specifier
+     * @return
+     * @throws Exception
+     */
+    private ArrayList<String> getItemsInLocalAuthority(ServiceContext ctx, Specifier specifier) throws Exception {
+       ArrayList<String> result = new ArrayList<String>();
+       
+       ResourceMap resourceMap = ctx.getResourceMap();
+       String resourceName = ctx.getClient().getServiceName();
+       AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
+       AbstractCommonList acl = authorityResource.getAuthorityItemList(ctx, specifier.value, ctx.getUriInfo());
+       List<ListItem> 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));
+               }
+       }
+       
+       return result;
+    }
+    
+    private Boolean getBooleanValue(ListItem listItem, String name) {
+       Boolean result = null;
+       
+               String value = AbstractCommonListUtils.ListItemGetElementValue(listItem, name);
+               if (value != null) {
+                       result = Boolean.valueOf(value);
+               }
+               
+               return result;
+    }
+    
+    private String getStringValue(ListItem listItem, String name) {
+       return AbstractCommonListUtils.ListItemGetElementValue(listItem, AuthorityItemJAXBSchema.REF_NAME);
+    }
+    
     /**
      * This is a sync method.
      * @param ctx
@@ -223,17 +351,19 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
        String resourceName = ctx.getClient().getServiceName();
        AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
        Response response = authorityResource.createAuthorityItemWithParentContext(ctx, authoritySpecifier.value,
-                       sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV);
+                       sasPayloadIn, AuthorityServiceUtils.DONT_UPDATE_REV, AuthorityServiceUtils.NOT_PROPOSED);
        //
        // Check the response for successful POST result
        //
        if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
                throw new DocumentException(String.format("Could not create new authority item '%s' during synchronization of the '%s' authority.",
                                itemIdentifier, parentIdentifier));
+       }
        //
-       // Handle the workflow state
+       // Handle the workflow state by "locking" this new copy of the SAS item.
        //
-       }
+       authorityResource.updateItemWorkflowWithTransition(ctx, parentIdentifier, itemIdentifier, 
+                       WorkflowClient.WORKFLOWTRANSITION_LOCK, AuthorityServiceUtils.DONT_UPDATE_REV);
     }
     
     /**
@@ -257,7 +387,7 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
        String parentIdentifier = RefNameUtils.createShortIdRefName(authorityTermInfo.inAuthority.name);
        String itemIdentifier = RefNameUtils.createShortIdRefName(authorityTermInfo.name);
        //
-       // We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
+       // We'll use the Authority JAX-RS resource class to peform sync operations (creates and updates)
        //
        ResourceMap resourceMap = ctx.getResourceMap();
        String resourceName = ctx.getClient().getServiceName();
@@ -268,14 +398,15 @@ public abstract class AuthorityDocumentModelHandler<AuthCommon>
                localItemPayloadOut = authorityResource.getAuthorityItemWithParentContext(ctx, parentIdentifier, itemIdentifier);
        } catch (DocumentNotFoundException dnf) {
                //
-               // Document not found, means we need to create an item/term that exists only on the SAS
+               // Document not found, means we need to create a local 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.", remoteRefName));
                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
+       // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
+       // We synchronize by calling the authority resource (the JAX-RS resource) class' sync method for an item.
        //
        PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithParentContext(ctx, parentIdentifier, itemIdentifier);
        if (theUpdate != null) {
index e5762339ad89e4d0db654f48ef1fd9f7659f91d5..679038fc6e10979bf9a54de6467acc566d6cb1ba 100644 (file)
@@ -28,7 +28,9 @@ 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.workflow.WorkflowClient;
 import org.collectionspace.services.common.ResourceMap;
+import org.collectionspace.services.common.ServiceMain;
 import org.collectionspace.services.common.UriTemplateRegistry;
 import org.collectionspace.services.common.api.RefName;
 import org.collectionspace.services.common.api.RefNameUtils;
@@ -92,6 +94,8 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
     protected String authorityCommonSchemaName;
     protected String authorityItemCommonSchemaName;
     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 shouldUpdateRevNumber = true; // by default we should update the revision number -not true on synchronization with SAS
     /**
      * inVocabulary is the parent Authority for this context
@@ -110,6 +114,20 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
     
     abstract public String getParentCommonSchemaName();
     
+    //
+    // Getter and Setter for 'proposed'
+    //
+    public boolean getIsProposed() {
+       return this.isProposed;
+    }
+    
+    public void setIsProposed(boolean flag) {
+       this.isProposed = flag;
+    }
+    
+    //
+    // Getter and Setter for 'shouldUpdateRevNumber'
+    //
     public boolean getShouldUpdateRevNumber() {
        return this.shouldUpdateRevNumber;
     }
@@ -362,7 +380,9 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
     }
         
     /**
-     * This method synchronizes/updates a single authority item resource.
+     * This method synchronizes/updates a single authority item resource with the corresponding SAS items.
+     * The argument 'wrapDoc' in most CSpace methods usually contains a resource payload -like a nuxeo document model.  However,
+     * for the handleSync method, the wrapDoc argument contains a authority item specifier.
      */
     @Override
     public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
@@ -370,7 +390,7 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
        
         //
-        // Get information about the local authority item so we can compare with corresponding item on the shared authority server
+        // Get information about the local authority item so we can compare with the corresponding item on the shared authority server
         //
        AuthorityItemSpecifier authorityItemSpecifier = (AuthorityItemSpecifier) wrapDoc.getWrappedObject();
         DocumentModel itemDocModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), getAuthorityItemCommonSchemaName(), 
@@ -380,6 +400,7 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
                                authorityItemSpecifier.getItemSpecifier().value));
         }
         Long localItemRev = (Long) NuxeoUtils.getProperyValue(itemDocModel, AuthorityItemJAXBSchema.REV);
+        Boolean localIsProposed = (Boolean) NuxeoUtils.getProperyValue(itemDocModel, AuthorityItemJAXBSchema.PROPOSED);
         String localItemCsid = itemDocModel.getName();
         String localItemWorkflowState = (String) NuxeoUtils.getProperyValue(itemDocModel, CollectionSpaceClient.CORE_WORKFLOWSTATE);
         String itemShortId = (String) NuxeoUtils.getProperyValue(itemDocModel, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
@@ -391,31 +412,33 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
                        authorityItemSpecifier.getParentSpecifier());
         String authorityShortId = (String) NuxeoUtils.getProperyValue(authorityDocModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
         String localParentCsid = authorityDocModel.getName();
+        
         //
         // Using the short IDs of the local authority and item, create URN specifiers to retrieve the SAS authority item
         //
         Specifier sasAuthoritySpecifier = new Specifier(SpecifierForm.URN_NAME, RefNameUtils.createShortIdRefName(authorityShortId));
         Specifier sasItemSpecifier = new Specifier(SpecifierForm.URN_NAME, RefNameUtils.createShortIdRefName(itemShortId));
         AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(sasAuthoritySpecifier, sasItemSpecifier);
-        // Get the shared authority server's copy
+        // Get the shared authority server's copy of the item/term
         PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier, 
                        getAuthorityServicePath(), getEntityResponseType());
         Long sasRev = getRevision(sasPayloadIn);
         String sasWorkflowState = getWorkflowState(sasPayloadIn);
         //
-        // If the shared authority item is newer, update our local copy
+        // Update the local item if the shared authority item is newer or if the local item is a proposed item that is now becoming a true SAS item
         //
-        if (sasRev > localItemRev) {
+        if (sasRev > localItemRev || localIsProposed) {
                ResourceMap resourceMap = ctx.getResourceMap();
                String resourceName = this.getAuthorityServicePath();
                AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
                PoxPayloadOut payloadOut = authorityResource.updateAuthorityItem(ctx, 
                                resourceMap,                                    
                                ctx.getUriInfo(),
-                               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
+                               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) {
                        ctx.setOutput(payloadOut);
                        result = true;
@@ -429,7 +452,7 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
                String resourceName = this.getAuthorityServicePath();
                AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
                //
-               // We need to move the local item to the SAS workflow state.  This might involve multiple transitions.
+               // We need to move the local item to the SAS workflow state -i.e., the locked state.
                //
                List<String> transitionList = getTransitionList(sasWorkflowState, localItemWorkflowState);
                for (String transition:transitionList) {
@@ -441,11 +464,23 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
     }
     
     /**
-     * We need to move the local item to the SAS workflow state.  This might involve multiple transitions.
+     * We need to move the local item to the SAS item's workflow state.  This might involve multiple transitions.
      */
     private List<String> getTransitionList(String sasWorkflowState, String localItemWorkflowState) {
        List<String> result = new ArrayList<String>();
-       // TO BE COMPLETELED
+       //
+       // If the SAS authority items is soft-deleted, we need to mark the local item as soft-deleted
+       //
+       if (sasWorkflowState.contains(WorkflowClient.WORKFLOWSTATE_DELETED) == true) {
+               result.add(WorkflowClient.WORKFLOWTRANSITION_DELETE);
+       }
+       //
+       // Ensure the local item is in a "locked" state.  Items sync'd with a SAS should always be locked
+       //
+       if (localItemWorkflowState.contains(WorkflowClient.WORKFLOWSTATE_LOCKED) != true) {
+               result.add(WorkflowClient.WORKFLOWTRANSITION_LOCK);
+       }
+
        return result;
     }
     
@@ -459,6 +494,34 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
         // Ensure we have required fields set properly
         handleInAuthority(wrapDoc.getWrappedObject());        
     }
+    
+    /* This method ensures that before we delete an authority item, there are no records in the system that reference it.
+     * 
+     * (non-Javadoc)
+     * @see org.collectionspace.services.common.document.DocumentHandler#handleDelete(org.collectionspace.services.common.document.DocumentWrapper)
+     */
+    @Override
+    public void handleDelete(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
+        UriTemplateRegistry uriTemplateRegistry = ServiceMain.getInstance().getUriTemplateRegistry();
+       ServiceContext ctx = getServiceContext();
+       DocumentModel docModel = wrapDoc.getWrappedObject();
+       String inAuthorityCsid = (String) docModel.getProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.IN_AUTHORITY);
+       String itemCsid = docModel.getName();
+       
+       ResourceMap resourceMap = ctx.getResourceMap();
+       String resourceName = this.getAuthorityServicePath();
+       AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(resourceName);
+        //
+       // If the authority item has references to it from other resources, we can't and won't
+       // delete it.
+       //
+       AuthorityRefDocList refObjs = authorityResource.getReferencingObjects(ctx, inAuthorityCsid, itemCsid, 
+                       uriTemplateRegistry, ctx.getUriInfo());
+       if (refObjs.getTotalItems() != 0) {
+               throw new DocumentException(String.format("Can not delete authority item '%s' because it still has records in the system that are referencing it.",
+                               itemCsid));
+       }
+    }
 
     /*
      * This method gets called after the primary update to an authority item has happened.  If the authority item's refName
@@ -524,6 +587,9 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
         }
     }
     
+    //
+    // Handles both update calls (PUTS) AND create calls (POSTS)
+    //
     public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
        super.fillAllParts(wrapDoc, action);
        //
@@ -532,6 +598,12 @@ public abstract class AuthorityItemDocumentModelHandler<AICommon>
        if (this.getShouldUpdateRevNumber() == true) { // We won't update rev numbers on synchronization with SAS
                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()));
     }
     
     /**
index 1741033bd6325680bd78add67e5571fa090cb3a4..e4019cbc9e0172eb6b66683d7ee6ef4b7db215e0 100644 (file)
@@ -3,6 +3,7 @@ package org.collectionspace.services.client;
 import java.util.List;
 
 import org.collectionspace.services.jaxb.AbstractCommonList;
+
 import org.slf4j.Logger;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -28,19 +29,20 @@ public class AbstractCommonListUtils {
     public static String ListItemGetCSID(AbstractCommonList.ListItem item) {
                return ListItemGetElementValue(item, "csid");
        }
-
+    
     public static String ListItemGetElementValue(AbstractCommonList.ListItem item,
                String elName) {
+       String result = null;
+       
                List<Element> elList = item.getAny();
-               for(Element el : elList) {
-                       if(elName.equalsIgnoreCase(el.getNodeName())) {
+               for (Element el : elList) {
+                       if (elName.equalsIgnoreCase(el.getNodeName())) {
                        Node textEl = el.getFirstChild();
-                       return textEl.getNodeValue();
+                       result = textEl.getNodeValue();
+                       break;
                        }
-               }
-               return null;
+               } 
+               
+               return result;
        }
-
-
-
 }
index db4da7375d50b1108663e943feef30197013e4ce..b8db13132a3d36183f26b9f8c1b38d53353ac65c 100644 (file)
@@ -65,7 +65,7 @@ public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
 
     protected final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-
+    protected final ServiceContext<IT, OT> NULL_CONTEXT = null;
     // Fields for default client factory and client
     /** The repository client factory. */
     private RepositoryClientFactory<IT, OT> repositoryClientFactory;
index 6d1ef8642cc67faf7afd84cdeb92ecbc2b481f5d..e74ed266d12aa559ad81ac7b338d4c4d53b104a5 100644 (file)
@@ -5,6 +5,6 @@ import java.util.Map;
 /*
  * Maps service names to Resource instances. Use the Service Client Class to get the service name. 
  */
-public interface ResourceMap extends Map<String, NuxeoBasedResource> {
+public interface ResourceMap extends Map<String, CollectionSpaceResource> {
 
 }
index e030f7439df47806a78228134ebc00f43ff73af7..3ab5372b2e17b17b121df263fb100200863e508b 100644 (file)
 package org.collectionspace.services.common.context;
 
 import java.lang.reflect.Constructor;
+
 import javax.ws.rs.core.UriInfo;
 
+import org.collectionspace.services.common.CollectionSpaceResource;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.ServiceMain;
 import org.collectionspace.services.common.config.ConfigUtils;
@@ -33,7 +35,6 @@ import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
 import org.collectionspace.services.common.security.UnauthorizedException;
 import org.collectionspace.services.config.service.ServiceBindingType;
 import org.collectionspace.services.config.tenant.TenantBindingType;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -173,6 +174,23 @@ public class RemoteServiceContextImpl<IT, OT>
         this.output = output;
     }
 
+    /**
+     * Return the JAX-RS resource for the current context.
+     * 
+     * @param ctx
+     * @return
+     * @throws Exception 
+     */
+    public CollectionSpaceResource<IT, OT> getResource(ServiceContext ctx) throws Exception {
+       CollectionSpaceResource<IT, OT> result = null;
+       
+       ResourceMap resourceMap = ctx.getResourceMap();
+       String resourceName = ctx.getClient().getServiceName();
+       result = resourceMap.get(resourceName);
+       
+       return result;
+    }
+    
     /**
      * @return the map of service names to resource classes.
      */
index 0cb4cf8f2b89d93005e76052f9dc2350fff3ed0a..d971c791bc9ec7b4ccde529a158949f62f475b71 100644 (file)
@@ -30,6 +30,7 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.services.client.CollectionSpaceClient;
+import org.collectionspace.services.common.CollectionSpaceResource;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.document.DocumentHandler;
 import org.collectionspace.services.common.document.ValidatorHandler;
@@ -235,6 +236,11 @@ public interface ServiceContext<IT, OT> {
      */
     public void setOutput(OT output);
 
+    /**
+     * 
+     */
+    public CollectionSpaceResource getResource();
+    
     /**
      * @return the map of service names to resource classes.
      */
index c65da9b96c59017f45fa386ab75078ceae76357f..696bc4641394980e1698b2f006b334399ed5cb6e 100644 (file)
@@ -71,7 +71,7 @@ public class WorkflowDocumentModelHandler
        DocumentModelHandler targetDocHandler = (DocumentModelHandler)ctx.getProperty(WorkflowClient.TARGET_DOCHANDLER);
        targetDocHandler.setRepositorySession(this.getRepositorySession()); // Make sure the target doc handler has a repository session to work with
        TransitionDef transitionDef =  (TransitionDef)ctx.getProperty(WorkflowClient.TRANSITION_ID);
-       targetDocHandler.handleWorkflowTransition(wrapDoc, transitionDef);  // Call the parent resouce's handler first
+       targetDocHandler.handleWorkflowTransition(wrapDoc, transitionDef);  // Call the target resouce's handler first
        //
        // If no exception occurred, then call the super's method
        //