]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
DRYD-1233: Automatically add/update batch jobs on startup. (#349)
authorRay Lee <ray.lee@lyrasis.org>
Tue, 16 May 2023 02:39:34 +0000 (22:39 -0400)
committerGitHub <noreply@github.com>
Tue, 16 May 2023 02:39:34 +0000 (22:39 -0400)
services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CSpaceResteasyBootstrap.java
services/batch/service/src/main/java/org/collectionspace/services/batch/BatchResource.java
services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/MergeAuthorityItemsBatchJob.xml [new file with mode: 0644]
services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/UpdateInventoryStatusBatchJob.xml [new file with mode: 0644]
services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.xml [new file with mode: 0644]
services/client/src/main/java/org/collectionspace/services/client/IQueryManager.java
services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto-unified.xml
services/common/src/main/java/org/collectionspace/services/common/query/QueryManager.java
services/common/src/main/java/org/collectionspace/services/common/query/nuxeo/QueryManagerNuxeoImpl.java
services/jaxb/src/main/java/org/collectionspace/services/jaxb/InvocableJAXBSchema.java

index abc0e7ea13d2c4ba83e2cb14f401ab427559191f..adf2ccfc4ecc502bff18bcf867d3ea0309429c02 100644 (file)
@@ -10,13 +10,16 @@ import javax.ws.rs.core.UriInfo;
 import org.jboss.resteasy.core.Dispatcher;
 import org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap;
 import org.jboss.resteasy.specimpl.PathSegmentImpl;
+import org.apache.commons.io.IOUtils;
 import org.collectionspace.authentication.AuthN;
 import org.collectionspace.authentication.CSpaceTenant;
 import org.collectionspace.services.account.Tenant;
 import org.collectionspace.services.account.TenantResource;
 import org.collectionspace.services.authorization.AuthZ;
+import org.collectionspace.services.batch.BatchResource;
 import org.collectionspace.services.client.AbstractCommonListUtils;
 import org.collectionspace.services.client.AuthorityClient;
+import org.collectionspace.services.client.BatchClient;
 import org.collectionspace.services.client.CollectionSpaceClient;
 import org.collectionspace.services.client.PayloadOutputPart;
 import org.collectionspace.services.client.PoxPayloadOut;
@@ -50,6 +53,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
+import java.io.InputStream;
 import java.lang.reflect.Constructor;
 import java.net.URI;
 import java.net.URLEncoder;
@@ -67,8 +71,10 @@ public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
        private static final String RESET_AUTHORITIES_PROPERTY = "org.collectionspace.services.authorities.reset";
        private static final String RESET_ELASTICSEARCH_INDEX_PROPERTY = "org.collectionspace.services.elasticsearch.reset";
        private static final String RESET_REPORTS_PROPERTY = "org.collectionspace.services.reports.reset";
+       private static final String RESET_BATCH_JOBS_PROPERTY = "org.collectionspace.services.batch.reset";
        private static final String QUICK_BOOT_PROPERTY = "org.collectionspace.services.quickboot";
        private static final String REPORT_PROPERTY = "report";
+       private static final String BATCH_PROPERTY = "batch";
 
        @Override
        public void contextInitialized(ServletContextEvent event) {
@@ -90,6 +96,7 @@ public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
                                // The below properties can be set in the tomcat/bin/setenv.sh (or setenv.bat) file.
                                String resetAuthsString = System.getProperty(RESET_AUTHORITIES_PROPERTY, Boolean.FALSE.toString());
                                String resetElasticsearchIndexString = System.getProperty(RESET_ELASTICSEARCH_INDEX_PROPERTY, Boolean.FALSE.toString());
+                               String resetBatchJobsString = System.getProperty(RESET_BATCH_JOBS_PROPERTY, Boolean.TRUE.toString());
                                String resetReportsString = System.getProperty(RESET_REPORTS_PROPERTY, Boolean.TRUE.toString());
 
                                initializeAuthorities(app.getResourceMap(), Boolean.valueOf(resetAuthsString));
@@ -101,6 +108,10 @@ public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
                                if (Boolean.valueOf(resetReportsString) == true) {
                                        resetReports();
                                }
+
+                               if (Boolean.valueOf(resetBatchJobsString) == true) {
+                                       resetBatchJobs();
+                               }
                        }
 
                        logger.info("CollectionSpace Services JAX-RS application started.");
@@ -234,6 +245,122 @@ public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
                }
        }
 
+       public void resetBatchJobs() throws Exception {
+               logger.info("Resetting batch jobs");
+
+               TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
+               Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
+
+               for (TenantBindingType tenantBinding : tenantBindingsTable.values()) {
+                       ServiceBindingType batchServiceBinding = null;
+
+                       for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
+                               if (serviceBinding.getName().toLowerCase().trim().equals(BatchClient.SERVICE_NAME)) {
+                                       batchServiceBinding = serviceBinding;
+
+                                       break;
+                               }
+                       }
+
+                       Set<String> batchNames = new HashSet<String>();
+
+                       if (batchServiceBinding != null) {
+                               for (PropertyType property : batchServiceBinding.getProperties()) {
+                                       for (PropertyItemType item : property.getItem()) {
+                                               if (item.getKey().equals(BATCH_PROPERTY)) {
+                                                       batchNames.add(item.getValue());
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (batchNames.size() > 0) {
+                               CSpaceTenant tenant = new CSpaceTenant(tenantBinding.getId(), tenantBinding.getName());
+
+                               resetTenantBatchJobs(tenant, batchNames);
+                       }
+               }
+       }
+
+       private void resetTenantBatchJobs(CSpaceTenant tenant, Set<String> batchNames) throws Exception {
+               logger.info("Resetting batch jobs for tenant {}", tenant.getId());
+
+               AuthZ.get().login(tenant);
+
+               CollectionSpaceJaxRsApplication app = (CollectionSpaceJaxRsApplication) deployment.getApplication();
+               ResourceMap resourceMap = app.getResourceMap();
+               BatchResource batchResource = (BatchResource) resourceMap.get(BatchClient.SERVICE_NAME);
+
+               for (String batchName : batchNames) {
+                       InputStream batchMetadataInputStream = BatchResource.getBatchMetadataInputStream(batchName);
+
+                       if (batchMetadataInputStream == null) {
+                               logger.warn(
+                                       "Metadata file not found for batch {}", batchName);
+
+                               continue;
+                       }
+
+                       String payload = IOUtils.toString(batchMetadataInputStream, StandardCharsets.UTF_8);
+
+                       batchMetadataInputStream.close();
+
+                       UriInfo uriInfo = new UriInfoImpl(
+                               new URI(""),
+                               new URI(""),
+                               "",
+                               "pgSz=0&classname=" + URLEncoder.encode(batchName, StandardCharsets.UTF_8.toString()),
+                               Arrays.asList((PathSegment) new PathSegmentImpl("", false))
+                       );
+
+                       AbstractCommonList list = batchResource.getList(uriInfo);
+
+                       if (list.getTotalItems() == 0) {
+                               logger.info("Adding batch job " + batchName);
+
+                               try {
+                                       batchResource.create(resourceMap, null, payload);
+                               } catch(Exception e) {
+                                       logger.error(e.getMessage(), e);
+                               }
+                       } else {
+                               for (ListItem item : list.getListItem()) {
+                                       String csid = AbstractCommonListUtils.ListItemGetCSID(item);
+
+                                       // Update an existing batch job iff:
+                                       // - it was created autmatically (i.e., by the SPRING_ADMIN user)
+                                       // - it was last updated automatically (i.e., by the SPRING_ADMIN user)
+                                       // - it is not soft-deleted
+
+                                       PoxPayloadOut batchPayload = batchResource.getResourceFromCsid(null, null, csid);
+                                       PayloadOutputPart corePart = batchPayload.getPart(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA);
+
+                                       String createdBy = corePart.asElement().selectSingleNode(CollectionSpaceClient.COLLECTIONSPACE_CORE_CREATED_BY).getText();
+                                       String updatedBy = corePart.asElement().selectSingleNode(CollectionSpaceClient.COLLECTIONSPACE_CORE_UPDATED_BY).getText();
+                                       String workflowState = corePart.asElement().selectSingleNode(CollectionSpaceClient.COLLECTIONSPACE_CORE_WORKFLOWSTATE).getText();
+
+                                       if (
+                                               createdBy.equals(AuthN.SPRING_ADMIN_USER)
+                                               && updatedBy.equals(AuthN.SPRING_ADMIN_USER)
+                                               && !workflowState.equals(WorkflowClient.WORKFLOWSTATE_DELETED)
+                                       ) {
+                                               logger.info("Updating batch job {} with csid {}", batchName, csid);
+
+                                               try {
+                                                       batchResource.update(resourceMap, null, csid, payload);
+                                               } catch (Exception e) {
+                                                       logger.error(e.getMessage(), e);
+                                               }
+                                       } else {
+                                               logger.info(
+                                                       "Not updating batch job {} with csid {} - it was not auto-created, or was updated or soft-deleted",
+                                                       batchName, csid);
+                                       }
+                               }
+                       }
+               }
+       }
+
        public void resetElasticSearchIndex() throws Exception {
                boolean isEnabled = Boolean.parseBoolean(Framework.getProperty(ES_ENABLED_PROPERTY, "true"));
 
index 503d62d521b75e411865023bd282a454a1dca670..9fb96512d79ff29c922ce85cd7adb0ad30ba2c43 100644 (file)
@@ -48,6 +48,7 @@ import org.collectionspace.services.authorization.PermissionException;
 import org.collectionspace.services.authorization.URIResourceImpl;
 import org.collectionspace.services.authorization.perms.ActionType;
 
+import java.io.InputStream;
 import java.util.List;
 
 import javax.ws.rs.Consumes;
@@ -96,7 +97,7 @@ public class BatchResource extends NuxeoBasedResource {
             MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
             DocumentHandler handler = createDocumentHandler(ctx);
             String docType = queryParams.getFirst(IQueryManager.SEARCH_TYPE_DOCTYPE);
-            String filename = queryParams.getFirst(IQueryManager.SEARCH_TYPE_FILENAME);
+            String className = queryParams.getFirst(IQueryManager.SEARCH_TYPE_CLASS_NAME);
             List<String> modes = queryParams.get(IQueryManager.SEARCH_TYPE_INVOCATION_MODE);
             String whereClause = null;
             DocumentFilter documentFilter = null;
@@ -109,9 +110,9 @@ public class BatchResource extends NuxeoBasedResource {
                 documentFilter.appendWhereClause(whereClause, IQueryManager.SEARCH_QUALIFIER_AND);
             }
 
-            if (filename != null && !filename.isEmpty()) {
-                whereClause = QueryManager.createWhereClauseForInvocableByFilename(
-                        common_part, filename);
+            if (className != null && !className.isEmpty()) {
+                whereClause = QueryManager.createWhereClauseForInvocableByClassName(
+                        common_part, className);
                 documentFilter = handler.getDocumentFilter();
                 documentFilter.appendWhereClause(whereClause, IQueryManager.SEARCH_QUALIFIER_AND);
             }
@@ -291,4 +292,17 @@ public class BatchResource extends NuxeoBasedResource {
             throw bigReThrow(e, msg);
         }
     }
+
+    public static InputStream getBatchMetadataInputStream(String batchName) {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+        try {
+            Class<?> clazz = classLoader.loadClass(batchName);
+            String metadataFileName = clazz.getSimpleName() + ".xml";
+
+            return clazz.getResourceAsStream(metadataFileName);
+        } catch (Exception e) {
+            return null;
+        }
+    }
 }
diff --git a/services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/MergeAuthorityItemsBatchJob.xml b/services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/MergeAuthorityItemsBatchJob.xml
new file mode 100644 (file)
index 0000000..436da12
--- /dev/null
@@ -0,0 +1,22 @@
+<document name="batch">
+  <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <name>Merge Authority Items</name>
+    <notes>Merge an authority item into a target, and update all referencing records. Runs on a single record only.</notes>
+    <forDocTypes>
+      <forDocType>Chronology</forDocType>
+      <forDocType>Workitem</forDocType>
+      <forDocType>Person</forDocType>
+      <forDocType>Conceptitem</forDocType>
+      <forDocType>Placeitem</forDocType>
+      <forDocType>Citation</forDocType>
+      <forDocType>Organization</forDocType>
+      <forDocType>Locationitem</forDocType>
+    </forDocTypes>
+    <supportsSingleDoc>true</supportsSingleDoc>
+    <supportsDocList>false</supportsDocList>
+    <supportsGroup>false</supportsGroup>
+    <supportsNoContext>false</supportsNoContext>
+    <createsNewFocus>false</createsNewFocus>
+    <className>org.collectionspace.services.batch.nuxeo.MergeAuthorityItemsBatchJob</className>
+  </ns2:batch_common>
+</document>
diff --git a/services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/UpdateInventoryStatusBatchJob.xml b/services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/UpdateInventoryStatusBatchJob.xml
new file mode 100644 (file)
index 0000000..2dc19f2
--- /dev/null
@@ -0,0 +1,15 @@
+<document name="batch">
+  <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <name>Update Inventory Status</name>
+    <notes>Set the inventory status of selected Object records. Runs on a record list only.</notes>
+    <forDocTypes>
+      <forDocType>CollectionObject</forDocType>
+    </forDocTypes>
+    <supportsSingleDoc>false</supportsSingleDoc>
+    <supportsDocList>true</supportsDocList>
+    <supportsGroup>false</supportsGroup>
+    <supportsNoContext>false</supportsNoContext>
+    <createsNewFocus>false</createsNewFocus>
+    <className>org.collectionspace.services.batch.nuxeo.UpdateInventoryStatusBatchJob</className>
+  </ns2:batch_common>
+</document>
diff --git a/services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.xml b/services/batch/service/src/main/resources/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.xml
new file mode 100644 (file)
index 0000000..2b7f544
--- /dev/null
@@ -0,0 +1,15 @@
+<document name="batch">
+  <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <name>Update Current Location</name>
+    <notes>Recompute the current location of Object records, based on the related Location/Movement/Inventory records. Runs on a single record or all records.</notes>
+    <forDocTypes>
+      <forDocType>CollectionObject</forDocType>
+    </forDocTypes>
+    <supportsSingleDoc>true</supportsSingleDoc>
+    <supportsDocList>false</supportsDocList>
+    <supportsGroup>false</supportsGroup>
+    <supportsNoContext>true</supportsNoContext>
+    <createsNewFocus>false</createsNewFocus>
+    <className>org.collectionspace.services.batch.nuxeo.UpdateObjectLocationBatchJob</className>
+  </ns2:batch_common>
+</document>
index 3c23228e4f65a881c1f2db04d66f1d6138b13680..2208b561f1644700e0e50ca76abfd356e508b93c 100644 (file)
@@ -41,6 +41,7 @@ public interface IQueryManager {
        final static String SEARCH_TYPE_PARTIALTERM = "pt";
        final static String SEARCH_TYPE_DOCTYPE = "doctype";
        final static String SEARCH_TYPE_FILENAME = "filename";
+       final static String SEARCH_TYPE_CLASS_NAME = "classname";
        final static String SEARCH_TYPE_INVOCATION_MODE = "mode";
        final static String SEARCH_TYPE_INVOCATION = "inv";
        final static String SEARCH_QUALIFIER_AND = SEARCH_TERM_SEPARATOR + "AND" + SEARCH_TERM_SEPARATOR;
@@ -172,6 +173,15 @@ public interface IQueryManager {
         */
        public String createWhereClauseForInvocableByFilename(String schema, String filename);
 
+       /**
+        * Creates a filtering where clause from class name, for invocables.
+        *
+        * @param schema  the schema name for this invocable
+        * @param docType the class name
+        * @return        the where clause
+        */
+       public String createWhereClauseForInvocableByClassName(String schema, String className);
+
        /**
         * Creates a filtering where clause from invocation mode, for invocables.
         *
index bc3dd22b89207085f9c2bf51a0297886c8a64232..7052bdee36a7abee64e83e0fd789cbb27dc587b8 100644 (file)
                        </service:DocHandlerParams>
                        <service:validatorHandler xmlns:service="http://collectionspace.org/services/config/service">org.collectionspace.services.batch.nuxeo.BatchValidatorHandler
                        </service:validatorHandler>
+                       <service:properties xmlns:service="http://collectionspace.org/services/config/service" xmlns:types="http://collectionspace.org/services/config/types">
+                               <types:item>
+                                       <types:key>batch</types:key>
+                                       <types:value>org.collectionspace.services.batch.nuxeo.MergeAuthorityItemsBatchJob</types:value>
+                               </types:item>
+                               <types:item>
+                                       <types:key>batch</types:key>
+                                       <types:value>org.collectionspace.services.batch.nuxeo.UpdateInventoryStatusBatchJob</types:value>
+                               </types:item>
+                               <types:item>
+                                       <types:key>batch</types:key>
+                                       <types:value>org.collectionspace.services.batch.nuxeo.UpdateObjectLocationBatchJob</types:value>
+                               </types:item>
+                       </service:properties>
                        <service:object xmlns:service="http://collectionspace.org/services/config/service" name="Batch"
                                version="1.0">
                                <service:part id="0" control_group="Managed" versionable="true" auditable="false" label="batch-system"
index 8de9f311db3d4d658808cb68003d5f78ad605ddd..775c1a270b3817d548af5cba16b28239cd27416c 100644 (file)
@@ -120,6 +120,17 @@ public class QueryManager {
                return queryManager.createWhereClauseForInvocableByFilename(schema, filename);
        }
 
+       /**
+        * Creates a filtering where clause from class name, for invocables.
+        *
+        * @param schema  the schema name for this invocable
+        * @param docType the class name
+        * @return        the where clause
+        */
+       static public String createWhereClauseForInvocableByClassName(String schema, String className) {
+               return queryManager.createWhereClauseForInvocableByClassName(schema, className);
+       }
+
        /**
         * Creates a filtering where clause from invocation mode, for invocables.
         *
index 4bc2e39c156f3e71b9041d433dea727de270772d..78c2b72eb625dca74c62d961f3e995e364140809 100644 (file)
@@ -320,6 +320,30 @@ public class QueryManagerNuxeoImpl implements IQueryManager {
                return whereClause;
        }
 
+       /**
+        * Creates a filtering where clause from class name, for invocables.
+        *
+        * @param schema  the schema name for this invocable
+        * @param docType the class name
+        * @return        the where clause
+        */
+       @Override
+       public String createWhereClauseForInvocableByClassName(String schema, String className) {
+               String trimmed = sanitizeNXQLString(className);
+
+               if (trimmed.isEmpty()) {
+                       throw new RuntimeException("No class name specified.");
+               }
+
+               if (schema == null || schema.isEmpty()) {
+                       throw new RuntimeException("No match schema specified.");
+               }
+
+               String whereClause = schema + ":" + InvocableJAXBSchema.CLASS_NAME + " = '" + trimmed + "'";
+
+               return whereClause;
+       }
+
        /**
         * Creates a filtering where clause from invocation mode, for invocables.
         *
index 161e11a87a330b184ada5db1668ee7ebdcbceca9..3c198c58750b25ef9b6f04c0038555f125528bb3 100644 (file)
@@ -5,6 +5,7 @@ package org.collectionspace.services.jaxb;
 
 public interface InvocableJAXBSchema {
     final static String FILENAME = "filename";
+    final static String CLASS_NAME = "className";
     final static String FOR_DOC_TYPES = "forDocTypes";
     final static String SUPPORTS_SINGLE_DOC = "supportsSingleDoc";
     final static String SUPPORTS_DOC_LIST = "supportsDocList";