]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5985:Adding support for authorization checks for invoking batch jobs.
authorremillet <remillet@yahoo.com>
Sat, 25 Mar 2017 00:32:59 +0000 (17:32 -0700)
committerremillet <remillet@yahoo.com>
Sat, 25 Mar 2017 00:32:59 +0000 (17:32 -0700)
65 files changed:
3rdparty/nuxeo/nuxeo-server/7.10-HF17/config/vcsconfig.sql.txt
services/IntegrationTests/pom.xml
services/IntegrationTests/src/main/java/org/collectionspace/services/IntegrationTests/xmlreplay/ServiceResult.java
services/IntegrationTests/src/main/java/org/collectionspace/services/IntegrationTests/xmlreplay/XmlReplay.java
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-Template.xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-permissions.xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-updateobjloc-nocontext.xml
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-Template.xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-gargabe.xml [moved from services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batchBadInvContext.xml with 100% similarity]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-list-empty.xml [moved from services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batchBadInvContextList.xml with 100% similarity]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-list.xml [moved from services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batchInvContextList.xml with 100% similarity]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-nocontext.xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-single.xml [moved from services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1InvContext.xml with 100% similarity]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch.xml
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (2).xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (3).xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (4).xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (5).xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1.xml [deleted file]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch2.xml [new file with mode: 0644]
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batchInvContextSingle.xml [deleted file]
services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java
services/account/jaxb/src/main/resources/accounts_common.xsd
services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountDocumentHandler.java
services/authorization-mgt/client/src/main/java/org/collectionspace/services/client/RoleClient.java
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/RoleResource.java
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleDocumentHandler.java
services/authorization/service/src/main/java/org/collectionspace/services/authorization/AuthZ.java
services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/batch_common-template.xml [new file with mode: 0644]
services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/batch_common.xsd
services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/instance1.xml [new file with mode: 0644]
services/batch/client/src/main/java/org/collectionspace/services/client/BatchClient.java
services/batch/jaxb/pom.xml
services/batch/jaxb/src/main/resources/batch_common-template.xml [new file with mode: 0644]
services/batch/jaxb/src/main/resources/batch_common.xsd
services/batch/jaxb/src/main/resources/batch_common_document.xsd [new file with mode: 0644]
services/batch/jaxb/src/main/resources/instance1.xml [new file with mode: 0644]
services/batch/service/pom.xml
services/batch/service/src/main/java/org/collectionspace/services/batch/AbstractBatchInvocable.java
services/batch/service/src/main/java/org/collectionspace/services/batch/BatchResource.java
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/BatchDocumentModelHandler.java
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/BatchValidatorHandler.java
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/CreateAndLinkLoanOutBatchJob.java
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/TestBatchJob.java [new file with mode: 0644]
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java
services/client/src/main/java/org/collectionspace/services/client/PoxPayload.java
services/common-api/src/main/java/org/collectionspace/services/common/api/Tools.java
services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java
services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java
services/common/src/main/java/org/collectionspace/services/common/NuxeoBasedResource.java
services/common/src/main/java/org/collectionspace/services/common/ResourceMap.java
services/common/src/main/java/org/collectionspace/services/common/ResourceMapImpl.java
services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/ActionGroup.java [new file with mode: 0644]
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java
services/common/src/main/java/org/collectionspace/services/common/context/RemoteServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/invocable/Invocable.java
services/common/src/main/java/org/collectionspace/services/common/query/UriInfoImpl.java [moved from services/batch/service/src/main/java/org/collectionspace/services/batch/UriInfoImpl.java with 99% similarity]
services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java
services/common/src/main/java/org/collectionspace/services/common/security/UnauthorizedException.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaDocumentHandler.java
services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java
services/jaxb/src/main/resources/invocationContext.xsd

index 275fc1d65778b1d24a522dd0d61b8b88c56eb6f4..aef9cbb490a5b17dba7b7cea6786af470845e785 100644 (file)
@@ -1,6 +1,7 @@
 #
 # A place to modify the Nuxeo database with SQL statements.
 # See https://doc.nuxeo.com/display/ADMINDOC/VCS+Configuration#VCSConfiguration-DatabaseCreationOption
+# or https://doc.nuxeo.com/nxdoc/repository-configuration/#page-title
 #
 
 #CATEGORY: afterTableCreation
@@ -15,3 +16,14 @@ SELECT constraint_name FROM information_schema.constraint_column_usage WHERE tab
 
 #IF: emptyResult
 ALTER TABLE reports_common add CONSTRAINT reportname_unique UNIQUE (name);
+
+#
+# Add a unique constraint to the batch job 'name' column of the batch_common table.
+#
+LOG.INFO Adding a unique constraint to the batch 'name' column of the batch_common table
+
+#TEST:
+SELECT constraint_name FROM information_schema.constraint_column_usage WHERE table_name = 'batch_common' AND constraint_name = 'batchname_unique';
+
+#IF: emptyResult
+ALTER TABLE batch_common add CONSTRAINT batchname_unique UNIQUE (name);
index 4b58877f08f0fe9adf0b21b99f1c978836ec6e16..0c8bf9a1b4bc3996bc72b2712d770e1018fb4799 100644 (file)
             <artifactId>org.collectionspace.services.collectionobject.jaxb</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.batch.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.collectionspace.services</groupId>
             <artifactId>org.collectionspace.services.collectionobject.client</artifactId>
index 548a9b4d8aea6f3110b7af85f76393fa94cfd2fc..e4e602e02170642e38fcdd9d8d6e968fa6923f00 100644 (file)
@@ -37,6 +37,7 @@ import java.util.Map;
  * $LastChangedDate:  $
  */
 public class ServiceResult {
+       public boolean autoDelete = true;
     public String testID = "";
     public String testGroupID = "";
     public String fullURL = "";
index 2a58de2cc30433206858400528b891e2c9d44ca3..76217e33b4a1b79fb01991268948acb005acadb4 100644 (file)
@@ -244,7 +244,7 @@ public class XmlReplay {
         int deleteFailures = 0;
         for (ServiceResult pr : serviceResultsMap.values()) {
             try {
-                if (Tools.notEmpty(pr.deleteURL)){
+                if (pr.autoDelete == true && Tools.notEmpty(pr.deleteURL)){
                     ServiceResult deleteResult = XmlReplayTransport.doDELETE(pr.deleteURL, pr.auth, pr.testID, "[autodelete:"+logName+"]");
                     if (deleteResult.gotExpectedResult() == false || deleteResult.responseCode != 200) {
                        reattemptList.put(REATTEMPT_KEY + deleteFailures++, pr); // We need to try again after our dependents have been deleted. cow()
@@ -564,6 +564,14 @@ public class XmlReplay {
                 try {
                     testElementIndex++;
                     String testID = testNode.valueOf("@ID");
+                    //
+                    // Figure out if we will auto delete resources
+                    boolean autoDelete = param_autoDeletePOSTS;
+                    String autoDeleteValue = testNode.valueOf("@autoDeletePOSTS");
+                    if (autoDeleteValue != null && !autoDeleteValue.trim().isEmpty()) {
+                       autoDelete = Boolean.valueOf(autoDeleteValue).booleanValue();
+                    }
+                    
                     String testIDLabel = Tools.notEmpty(testID) ? (testGroupID+'.'+testID) : (testGroupID+'.'+testElementIndex);
                     String method = testNode.valueOf("method");
                     String contentType = testNode.valueOf("contentType");
@@ -637,6 +645,7 @@ public class XmlReplay {
                             vars = parts.varsList.get(0);
                         }
                         serviceResult = XmlReplayTransport.doPOST_PUTFromXML(parts.responseFilename, vars, protoHostPort, uri, method, contentType, evalStruct, authForTest, testIDLabel);
+                        serviceResult.autoDelete = autoDelete;
                         if (vars!=null) {
                             serviceResult.addVars(vars);
                         }
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-Template.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-Template.xml
new file mode 100644 (file)
index 0000000..00cbca7
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ns:batch_common xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:ns="http://collectionspace.org/services/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://collectionspace.org/services/batch file:batch_common.xsd">
+    <name>name0</name>
+    <notes>notes0</notes>
+    <forDocTypes>
+        <forDocType>CollectionObject</forDocType>
+        <forDocType>Intake</forDocType>
+    </forDocTypes>
+    <forRoles>
+        <roleDisplayName>TENANT_READER</roleDisplayName>
+        <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+    </forRoles>
+    <resourceActionGroupList>
+        <resourceActionGroup>
+            <resourceName>blobs</resourceName>
+            <actionGroup>CRUL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>media</resourceName>
+            <actionGroup>CRUL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>concepts</resourceName>
+            <actionGroup>RL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>collectionobjects</resourceName>
+            <actionGroup>RL</actionGroup>
+        </resourceActionGroup>
+    </resourceActionGroupList>
+    <supportsNoContext>false</supportsNoContext>
+    <supportsSingleDoc>false</supportsSingleDoc>
+    <supportsDocList>false</supportsDocList>
+    <supportsGroup>false</supportsGroup>
+    <createsNewFocus>false</createsNewFocus>
+    <className>className0</className>
+</ns:batch_common>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-permissions.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-create-permissions.xml
new file mode 100644 (file)
index 0000000..1ff6409
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="batch">
+    <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch" xmlns:ns3="http://collectionspace.org/services/jaxb">
+        <name>batch-create-permissions</name>
+        <notes>A batch resource for testing the Batch service's permission enforcement before invoking batch jobs.</notes>
+        <resourceActionGroupList>
+            <resourceActionGroup>
+                <resourceName>blobs</resourceName>
+                <actionGroup>CRUL</actionGroup>
+            </resourceActionGroup>
+            <resourceActionGroup>
+                <resourceName>media</resourceName>
+                <actionGroup>CRUL</actionGroup>
+            </resourceActionGroup>
+            <resourceActionGroup>
+                <resourceName>concepts</resourceName>
+                <actionGroup>RL</actionGroup>
+            </resourceActionGroup>
+            <resourceActionGroup>
+                <resourceName>collectionobjects</resourceName>
+                <actionGroup>RL</actionGroup>
+            </resourceActionGroup>
+        </resourceActionGroupList>
+        <supportsNoContext>true</supportsNoContext>
+        <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
+    </ns2:batch_common>
+</document>
index 8f0cfd6275cc04b30f1b1a948897e78b7912c32b..ea41549287eada11586afbf31aaaf474215ace22 100644 (file)
@@ -2,16 +2,40 @@
 <document name="batch">
     <ns2:batch_common
         xmlns:ns2="http://collectionspace.org/services/batch"
-        xmlns:ns3="http://collectionspace.org/services/jaxb">
+        xmlns:ns3="http://collectionspace.org/services/jaxb"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="http://collectionspace.org/services/batch file:batch_common.xsd">
         <name>TestUpdateObjectLocationBatchJob</name>
         <forDocTypes>
             <forDocType>CollectionObject</forDocType>
         </forDocTypes>
+        <forRoles>
+               <roleDisplayName>TENANT_READER</roleDisplayName>
+               <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+       </forRoles>
+       <resourceActionGroupList>
+               <resourceActionGroup>
+                   <resourceName>blobs</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>media</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>concepts</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>collectionobjects</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+        </resourceActionGroupList>
         <supportsSingleDoc>true</supportsSingleDoc>
         <supportsDocList>true</supportsDocList>
         <supportsGroup>true</supportsGroup>
         <supportsNoContext>true</supportsNoContext>
         <createsNewFocus>false</createsNewFocus>
-        <className>org.collectionspace.services.batch.nuxeo.UpdateObjectLocationBatchJob</className>
+        <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
     </ns2:batch_common>
 </document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-Template.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-Template.xml
new file mode 100644 (file)
index 0000000..743d38e
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 
+    Valid modes - {"single", "list", "group", "nocontext"}
+-->
+<ns2:invocationContext xmlns:ns2="http://collectionspace.org/services/common/invocable" xmlns:ns3="http://collectionspace.org/services/jaxb">
+    <mode>mode0</mode>
+    <updateCoreValues>updateCoreValues0</updateCoreValues>
+    <docType>docType0</docType>
+    <singleCSID>singleCSID0</singleCSID>
+    <groupCSID>groupCSID0</groupCSID>
+    <listCSIDs>
+        <csid>csid0</csid>
+        <csid>csid1</csid>
+        <csid>csid2</csid>
+    </listCSIDs>
+    <params>
+        <param>
+        </param>
+        <param>
+        </param>
+        <param>
+        </param>
+    </params>
+</ns2:invocationContext>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-nocontext.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-invoke-nocontext.xml
new file mode 100644 (file)
index 0000000..340e4d9
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 
+    Valid modes - {"single", "list", "group", "nocontext"}
+-->
+<ns2:invocationContext xmlns:ns2="http://collectionspace.org/services/common/invocable" xmlns:ns3="http://collectionspace.org/services/jaxb">
+    <mode>nocontexty</mode>
+</ns2:invocationContext>
index 59981205a7d931628afc46f05d1f4dc9e824035f..c7d195cc48fc22a30e9be716fd3ba852db80133b 100644 (file)
@@ -3,7 +3,23 @@
        <auths>
                <!-- IMPORTANT: THESE ARE STICKY :: THEY STICK AROUND UNTIL RESET, IN EXEC ORDER OF THIS FILE. -->
                <auth ID="admin@core.collectionspace.org">YWRtaW5AY29yZS5jb2xsZWN0aW9uc3BhY2Uub3JnOkFkbWluaXN0cmF0b3I=</auth>
+               <auth ID="reader@core.collectionspace.org">cmVhZGVyQGNvcmUuY29sbGVjdGlvbnNwYWNlLm9yZzpyZWFkZXI=</auth>
+               <auth ID="testAdministator">YWRtaW5AY29sbGVjdGlvbnNwYWNlLm9yZzpBZG1pbmlzdHJhdG9y</auth>
        </auths>
+       
+       <testGroup ID="testPermissionsAndRoles" autoDeletePOSTS="true">
+               <test ID="createBatchPermissions" auth="test">
+                       <method>POST</method>
+                       <uri>/cspace-services/batch/</uri>
+                       <filename>batch/batch-create-permissions.xml</filename>
+               </test>
+               <test ID="testInvokeNoContext" auth="test" autoDeletePOSTS="false">
+                       <method>POST</method>
+                       <uri>/cspace-services/batch/${createBatchPermissions.CSID}</uri>
+                       <filename>batch/batch-invoke-nocontext.xml</filename>
+               </test>         
+       </testGroup>
+       
        <testGroup ID="testSingle" autoDeletePOSTS="true">
                <test ID="createBatch1" auth="test">
                        <method>POST</method>
@@ -13,7 +29,7 @@
                <test ID="createBatch2" auth="test">
                        <method>POST</method>
                        <uri>/cspace-services/batch/</uri>
-                       <filename>batch/batch1.xml</filename>
+                       <filename>batch/batch2.xml</filename>
                </test>
                <test ID="createBatch" auth="test">
                        <method>POST</method>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (2).xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (2).xml
new file mode 100644 (file)
index 0000000..5864169
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="batch">
+       <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch"
+               xmlns:ns3="http://collectionspace.org/services/jaxb">
+               <name>TestBatchJob</name>
+               <notes>A benign batch job for testing the Batch service.</notes>
+               <forRoles>
+               <roleDisplayName>TENANT_READER</roleDisplayName>
+               <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+       </forRoles>
+       <resourceActionGroupList>
+               <resourceActionGroup>
+                   <resourceName>blobs</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>media</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>concepts</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>collectionobjects</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+        </resourceActionGroupList>
+               <supportsNoContext>false</supportsNoContext>
+               <supportsSingleDoc>false</supportsSingleDoc>
+               <supportsDocList>false</supportsDocList>
+               <supportsGroup>false</supportsGroup>
+               <createsNewFocus>false</createsNewFocus>
+               <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
+       </ns2:batch_common>
+</document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (3).xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (3).xml
new file mode 100644 (file)
index 0000000..5864169
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="batch">
+       <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch"
+               xmlns:ns3="http://collectionspace.org/services/jaxb">
+               <name>TestBatchJob</name>
+               <notes>A benign batch job for testing the Batch service.</notes>
+               <forRoles>
+               <roleDisplayName>TENANT_READER</roleDisplayName>
+               <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+       </forRoles>
+       <resourceActionGroupList>
+               <resourceActionGroup>
+                   <resourceName>blobs</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>media</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>concepts</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>collectionobjects</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+        </resourceActionGroupList>
+               <supportsNoContext>false</supportsNoContext>
+               <supportsSingleDoc>false</supportsSingleDoc>
+               <supportsDocList>false</supportsDocList>
+               <supportsGroup>false</supportsGroup>
+               <createsNewFocus>false</createsNewFocus>
+               <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
+       </ns2:batch_common>
+</document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (4).xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (4).xml
new file mode 100644 (file)
index 0000000..5864169
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="batch">
+       <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch"
+               xmlns:ns3="http://collectionspace.org/services/jaxb">
+               <name>TestBatchJob</name>
+               <notes>A benign batch job for testing the Batch service.</notes>
+               <forRoles>
+               <roleDisplayName>TENANT_READER</roleDisplayName>
+               <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+       </forRoles>
+       <resourceActionGroupList>
+               <resourceActionGroup>
+                   <resourceName>blobs</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>media</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>concepts</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>collectionobjects</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+        </resourceActionGroupList>
+               <supportsNoContext>false</supportsNoContext>
+               <supportsSingleDoc>false</supportsSingleDoc>
+               <supportsDocList>false</supportsDocList>
+               <supportsGroup>false</supportsGroup>
+               <createsNewFocus>false</createsNewFocus>
+               <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
+       </ns2:batch_common>
+</document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (5).xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1 - Copy (5).xml
new file mode 100644 (file)
index 0000000..5864169
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="batch">
+       <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch"
+               xmlns:ns3="http://collectionspace.org/services/jaxb">
+               <name>TestBatchJob</name>
+               <notes>A benign batch job for testing the Batch service.</notes>
+               <forRoles>
+               <roleDisplayName>TENANT_READER</roleDisplayName>
+               <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+       </forRoles>
+       <resourceActionGroupList>
+               <resourceActionGroup>
+                   <resourceName>blobs</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>media</resourceName>
+                               <actionGroup>CRUL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>concepts</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+               <resourceActionGroup>
+                   <resourceName>collectionobjects</resourceName>
+                               <actionGroup>RL</actionGroup>
+               </resourceActionGroup>
+        </resourceActionGroupList>
+               <supportsNoContext>false</supportsNoContext>
+               <supportsSingleDoc>false</supportsSingleDoc>
+               <supportsDocList>false</supportsDocList>
+               <supportsGroup>false</supportsGroup>
+               <createsNewFocus>false</createsNewFocus>
+               <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
+       </ns2:batch_common>
+</document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch1.xml
deleted file mode 100644 (file)
index bc3cc10..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<document name="batch">
-       <ns2:batch_common
-       xmlns:ns2="http://collectionspace.org/services/batch"
-       xmlns:ns3="http://collectionspace.org/services/jaxb">
-               <name>TestCreateAndLinkLoanOutBatchJob</name>
-               <notes>This should be interesting</notes>
-               <forDocTypes>
-                 <forDocType>CollectionObject</forDocType>
-               </forDocTypes>
-               <supportsSingleDoc>true</supportsSingleDoc>
-               <supportsDocList>true</supportsDocList>
-               <createsNewFocus>true</createsNewFocus>
-               <className>org.collectionspace.services.batch.nuxeo.CreateAndLinkLoanOutBatchJob</className>
-       </ns2:batch_common>
-</document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch2.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch2.xml
new file mode 100644 (file)
index 0000000..577db7e
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="batch">
+       <ns2:batch_common xmlns:ns2="http://collectionspace.org/services/batch"
+               xmlns:ns3="http://collectionspace.org/services/jaxb">
+               <name>TestBatchJob</name>
+               <notes>A second benign batch job for testing the Batch service.</notes>
+               <supportsNoContext>false</supportsNoContext>
+               <supportsSingleDoc>false</supportsSingleDoc>
+               <supportsDocList>false</supportsDocList>
+               <supportsGroup>false</supportsGroup>
+               <createsNewFocus>false</createsNewFocus>
+               <className>org.collectionspace.services.batch.nuxeo.TestBatchJob</className>
+       </ns2:batch_common>
+</document>
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batchInvContextSingle.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batchInvContextSingle.xml
deleted file mode 100644 (file)
index dc262c4..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<ns2:invocationContext
-xmlns:ns2="http://collectionspace.org/services/common/invocable"
-xmlns:ns3="http://collectionspace.org/services/jaxb">
-  <mode>single</mode>
-       <docType>CollectionObject</docType>
-       <singleCSID>${CollObj1}</singleCSID>
-</ns2:invocationContext>
-
-
index d1a5cd6d29955fa2e613bdad575fddbeaea06fe0..dbc8f68c3238c74756a7a748dac98cffbf0bf68a 100644 (file)
@@ -90,7 +90,7 @@ public class CollectionSpaceJaxRsApplication extends Application
 
     private Set<Object> singletons = new HashSet<Object>();
     private Set<Class<?>> empty = new HashSet<Class<?>>();    
-    private ResourceMap<PoxPayloadIn, PoxPayloadOut> resourceMap = new ResourceMapImpl();
+    private ResourceMap resourceMap = new ResourceMapImpl();
     private ServletContext servletContext = null;
 
     public CollectionSpaceJaxRsApplication() {         
index ec2a18d6c070221ecd788673947f35bb78860e34..63371d4165c4820b143c37f8649238ea4d8e035a 100644 (file)
                                        </xs:annotation>
                                        <xs:sequence>
                                            <xs:element name="screenName" type="xs:string" minOccurs="1"/>
+                                           <xs:element name="userid" type="xs:string" minOccurs="1" />
                                            <xs:element name="personRefName" type="xs:string" minOccurs="1" />
                                            <xs:element name="email" type="xs:string" minOccurs="1" />
                                            <xs:element name="status" type="status" minOccurs="1" />
index bb2e159e2c29effaaa90235ed961da5b65dbda1b..9884685094e8e75fbef47d96553ebf6b4ee3e879 100644 (file)
@@ -27,20 +27,30 @@ import org.collectionspace.services.account.storage.AccountStorageClient;
 import org.collectionspace.services.authorization.AccountPermission;
 import org.collectionspace.services.authorization.AccountRole;
 import org.collectionspace.services.authorization.AccountRoleRel;
+import org.collectionspace.services.authorization.RoleValue;
 import org.collectionspace.services.authorization.SubjectType;
 import org.collectionspace.services.client.AccountClient;
 import org.collectionspace.services.client.PayloadOutputPart;
+import org.collectionspace.services.client.RoleClient;
 import org.collectionspace.services.common.SecurityResourceBase;
 import org.collectionspace.services.common.ServiceMessages;
+import org.collectionspace.services.common.UriInfoWrapper;
 import org.collectionspace.services.common.context.RemoteServiceContextFactory;
 import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.context.ServiceContextFactory;
+import org.collectionspace.services.common.query.UriInfoImpl;
 import org.collectionspace.services.common.storage.StorageClient;
 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
 import org.jboss.resteasy.util.HttpResponseCodes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -51,6 +61,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.PathSegment;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
@@ -105,7 +116,8 @@ public class AccountResource extends SecurityResourceBase {
     @GET
     @Produces("application/xml")
     public AccountsCommonList getAccountList(@Context UriInfo ui) {
-       AccountsCommonList result = (AccountsCommonList)getList(ui, AccountsCommon.class);
+       UriInfoWrapper uriInfoWrapper = new UriInfoWrapper(ui);
+       AccountsCommonList result = (AccountsCommonList)getList(uriInfoWrapper, AccountsCommon.class);
        if(logger.isTraceEnabled()) {
                PayloadOutputPart ppo = new PayloadOutputPart(AccountsCommonList.class.getSimpleName(),
                                result);
@@ -113,6 +125,73 @@ public class AccountResource extends SecurityResourceBase {
        }
        return result;
     }
+    
+    protected UriInfo createUriInfo() throws URISyntaxException {
+        return createUriInfo("");
+    }
+
+    private UriInfo createUriInfo(String queryString) throws URISyntaxException {
+        URI absolutePath = new URI("");
+        URI baseUri = new URI("");
+        return new UriInfoImpl(absolutePath, baseUri, "", queryString, Collections.<PathSegment>emptyList());
+    }
+
+    /**
+     * Perform a search off the accounts for using a user ID
+     * @param userId
+     * @return
+     */
+    private String getAccountCsid(String userId) {
+       String result = null;
+       
+       try {
+                       UriInfo uriInfo = createUriInfo(String.format("uid=%s", userId));
+                       AccountsCommonList accountsCommonList = getAccountList(uriInfo);
+                       if (accountsCommonList != null && accountsCommonList.getAccountListItem() != null) {
+                               for (AccountListItem accountListItem: accountsCommonList.getAccountListItem()) {
+                                       if (accountListItem.getUserid().equalsIgnoreCase(userId)) {
+                                               result = accountListItem.getCsid();
+                                               break;
+                                       }
+                               }
+                       }
+               } catch (URISyntaxException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       
+       return result;
+    }
+    
+    /**
+     * Return the list of roles (display name) for a user id.
+     * 
+     * @param userId
+     * @return
+     */
+    public List<String> getAccountRoles(String userId, String tenantId) {
+       List<String> result = null;
+       
+       String accountCsid = getAccountCsid(userId);
+       if (accountCsid != null) {
+               AccountRole accountRole = getAccountRole(accountCsid);
+               if (accountRole != null && accountRole.getRole() != null) {
+                       List<RoleValue> roleValueList = accountRole.getRole();
+                       if (roleValueList.isEmpty() == false) {
+                               result = new ArrayList<String>();
+                               for (RoleValue roleValue: roleValueList) {
+                                       String displayName = roleValue.getDisplayName();
+                                       if (displayName == null) {
+                                               displayName = RoleClient.inferDisplayName(roleValue.getRoleName(), tenantId);
+                                       }
+                                       result.add(displayName);
+                               }
+                       }
+               }
+       }
+       
+       return result;
+    }
 
     @PUT
     @Path("{csid}")
@@ -225,7 +304,6 @@ public class AccountResource extends SecurityResourceBase {
         logger.debug("getAccountPerm with accCsid=" + accCsid);
         ensureCSID(accCsid, ServiceMessages.GET_FAILED+ "getAccountPerm account ");
         AccountPermission result = null;
-        String userId = "undefined";
         try {
             result = JpaStorageUtils.getAccountPermissions(accCsid);
         } catch (Exception e) {
index 8a0111804f09e264516afe20a28e71c9b8f8fd37..09a3444830ff6bd55efebd6a3ae2d27934718cd1 100644 (file)
@@ -163,6 +163,7 @@ public class AccountDocumentHandler
             AccountsCommon account = (AccountsCommon) obj;
             AccountListItem accListItem = new AccountListItem();
             accListItem.setScreenName(account.getScreenName());
+            accListItem.setUserid(account.getUserId());
             accListItem.setEmail(account.getEmail());
             accListItem.setStatus(account.getStatus());
             String id = account.getCsid();
index 4a9755b605b067b2ea9f9103b4f2d9191c2ae519..7694e7b7a77837cbb4af01ed88e14cfab0a47bd7 100644 (file)
@@ -28,16 +28,7 @@ package org.collectionspace.services.client;
 
 import javax.ws.rs.core.Response;
 
-
-
-
-
-
-
-
-
 import org.apache.http.HttpStatus;
-import org.collectionspace.services.authorization.AccountRole;
 import org.collectionspace.services.authorization.Role;
 import org.collectionspace.services.authorization.RolesList;
 import org.collectionspace.services.description.ServiceDescription;
@@ -53,6 +44,7 @@ public class RoleClient extends AbstractServiceClientImpl<RolesList, Role, Role,
        public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT;
        public static final String SERVICE_PATH_PROXY = SERVICE_PATH + "/";     
        public final static String IMMUTABLE = "immutable";
+       private final static String BACKEND_ROLE_PREFIX = "ROLE_";
 
     public RoleClient() throws Exception {
                super();
@@ -61,7 +53,38 @@ public class RoleClient extends AbstractServiceClientImpl<RolesList, Role, Role,
     public RoleClient(String clientPropertiesFilename) throws Exception {
                super(clientPropertiesFilename);
        }
-
+    
+    /**
+     * Creates a backend (Spring Security as of v4.5) role name.
+     * @param roleDisplayName
+     * @param tenantId
+     * @return
+     */
+    static public String getBackendRoleName(String roleDisplayName, String tenantId) {
+        String roleName = roleDisplayName.toUpperCase();
+        String rolePrefix = BACKEND_ROLE_PREFIX + tenantId + "_";
+        if (!roleName.startsWith(rolePrefix)) {
+            roleName = rolePrefix + roleName;
+        }
+        return roleName;
+    }
+    
+    /*
+     * Only call this method with a valid backend role name (not the display name).
+     */
+    static public String inferDisplayName(String backendRoleName, String tenantId) {
+        String rolePrefix = BACKEND_ROLE_PREFIX + tenantId + "_";
+        String inferredRoleName = backendRoleName.replace(rolePrefix, "");
+        
+        if (logger.isWarnEnabled()) {
+               String msg = String.format("Role display name '%s' is being inferred from backend role name '%s'.", 
+                               inferredRoleName, backendRoleName);
+               logger.warn(msg);
+        }
+        
+        return inferredRoleName;
+    }
+    
        @Override
     public String getServiceName() { 
        throw new UnsupportedOperationException(); //FIXME: REM - http://issues.collectionspace.org/browse/CSPACE-3498 }
@@ -75,7 +98,8 @@ public class RoleClient extends AbstractServiceClientImpl<RolesList, Role, Role,
         return SERVICE_PATH_COMPONENT;
     }
 
-    public Response readList() {
+    @Override
+       public Response readList() {
         return getProxy().readList();
 
     }
@@ -85,7 +109,8 @@ public class RoleClient extends AbstractServiceClientImpl<RolesList, Role, Role,
 
     }
 
-    public Response read(String csid) {
+    @Override
+       public Response read(String csid) {
         return getProxy().read(csid);
     }
     
@@ -99,7 +124,8 @@ public class RoleClient extends AbstractServiceClientImpl<RolesList, Role, Role,
      * @param role the role
      * @return the client response
      */
-    public Response create(Role role) {
+    @Override
+       public Response create(Role role) {
         return getProxy().create(role);
     }
 
@@ -108,7 +134,8 @@ public class RoleClient extends AbstractServiceClientImpl<RolesList, Role, Role,
      * @param role
      * @return
      */
-    public Response update(String csid, Role role) {
+    @Override
+       public Response update(String csid, Role role) {
         return getProxy().update(csid, role);
     }
 
index c5fbde75fbdfa451aec835d3814b53ad2f4f7038..425a4d1f0b7e6b227937fddd6d546afe781d0894 100644 (file)
@@ -56,9 +56,6 @@ public class PermissionRoleSubResource
     final Logger logger = LoggerFactory.getLogger(PermissionRoleSubResource.class);
     /** The storage client. */
     final StorageClient storageClient = new JpaRelationshipStorageClient<PermissionRole>();
-    //
-    private String permissionRoleCsid = null;
-
     /**
      * Instantiates a new permission role sub resource.
      *
index 96a948c08d5dea4fa10c90224cb522e2fdc45d3f..d07d6c2ec3b429f766afe8b0fb1d5fb185ea3bc5 100644 (file)
@@ -47,7 +47,6 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
index 5526957ce290a8626400c9b30570a40784a9d7fd..daeb5ecd720b14af2e6b0ae8f587557c3beed8bc 100644 (file)
@@ -67,8 +67,7 @@ public class RoleDocumentHandler
         }
         
         setTenant(role);
-        role.setRoleName(fixRoleName(role.getRoleName(),
-                       role.getTenantId()));
+        role.setRoleName(RoleClient.getBackendRoleName(role.getRoleName(), role.getTenantId()));
         role.setCsid(id);
         // We do not allow creation of locked roles through the services.
         role.setMetadataProtection(null);
@@ -81,7 +80,7 @@ public class RoleDocumentHandler
         Role roleReceived = getCommonPart();
         // If marked as metadata immutable, do not do update
         if(!RoleClient.IMMUTABLE.equals(roleFound.getMetadataProtection())) {
-               roleReceived.setRoleName(fixRoleName(roleReceived.getRoleName(),
+               roleReceived.setRoleName(RoleClient.getBackendRoleName(roleReceived.getRoleName(),
                                roleFound.getTenantId()));
                merge(roleReceived, roleFound);
         }
@@ -211,15 +210,6 @@ public class RoleDocumentHandler
         }
     }
 
-    private String fixRoleName(String role, String tenantId) {
-        String roleName = role.toUpperCase();
-        String rolePrefix = "ROLE_" + tenantId + "_";
-        if (!roleName.startsWith(rolePrefix)) {
-            roleName = rolePrefix + roleName;
-        }
-        return roleName;
-    }
-
     private void setTenant(Role role) {
         //set tenant only if not available from input
         if (role.getTenantId() == null || role.getTenantId().isEmpty()) {
index cef1fb3d91e024a72e6f0e0ee460a1393029e09b..9dd09df36a19416b5290e17af981acde3f1650e0 100644 (file)
@@ -28,6 +28,7 @@ import java.util.HashSet;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.collectionspace.services.authorization.perms.ActionType;
 import org.collectionspace.services.authorization.spi.CSpaceAuthorizationProvider;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -61,6 +62,36 @@ public class AuthZ {
         return self;
     }
     
+    public static String getMethod(ActionType actionType) {
+       String result = null;
+       
+       switch (actionType) {
+       case CREATE:
+               result = "POST";
+               break;
+       case READ:
+               result = "GET";
+               break;
+       case UPDATE:
+               result = "PUT";
+               break;
+       case DELETE:
+               result = "DELETE";
+               break;
+       case RUN:
+               result = "RUN";
+               break;
+       case SEARCH:
+               result = "READ";
+               break;
+       default:
+               throw new RuntimeException(String.format("Encountered unexpected action type '%s'.",
+                               actionType.value()));
+       }
+       
+       return result;
+    }
+    
     private void setupProvider() {
         String beanConfig = "applicationContext-authorization.xml";
         //system property is only set in test environment
diff --git a/services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/batch_common-template.xml b/services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/batch_common-template.xml
new file mode 100644 (file)
index 0000000..53890a8
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ns:batch_common xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
+    xmlns:ns="http://collectionspace.org/services/batch" 
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+    xsi:schemaLocation="http://collectionspace.org/services/batch file:batch_common.xsd">
+    <name>name0</name>
+    <notes>notes0</notes>
+    <forDocTypes>
+        <forDocType>CollectionObject</forDocType>
+        <forDocType>Intake</forDocType>
+    </forDocTypes>
+    <forRoles>
+        <roleDisplayName>TENANT_READER</roleDisplayName>
+        <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+    </forRoles>
+    <resourceActionGroupList>
+        <resourceActionGroup>
+            <resourceName>blobs</resourceName>
+            <actionGroup>CRUL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>media</resourceName>
+            <actionGroup>CRUL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>concepts</resourceName>
+            <actionGroup>RL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>collectionobjects</resourceName>
+            <actionGroup>RL</actionGroup>
+        </resourceActionGroup>
+    </resourceActionGroupList>
+    <supportsNoContext>false</supportsNoContext>
+    <supportsSingleDoc>false</supportsSingleDoc>
+    <supportsDocList>false</supportsDocList>
+    <supportsGroup>false</supportsGroup>
+    <createsNewFocus>false</createsNewFocus>
+    <className>className0</className>
+</ns:batch_common>
index 0b670e4e29374e2f0e64b6dd93dc4403bbc7e1f8..d0e5c17298e943cf5b3977472c1bdfb173e70d98 100644 (file)
@@ -1,14 +1,12 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 
 <!--
-    Loan Out schema (XSD)
+    Batch common schema (XSD)
     
     Entity  : Batch
     Part    : Common
     Used for: Nuxeo EP core document type
 
-    $LastChangedRevision: 2316 $
-    $LastChangedDate: 2010-06-02 16:03:51 -0700 (Wed, 02 Jun 2010) $
 -->
 
 <xs:schema 
     
     <!-- See http://wiki.collectionspace.org/display/collectionspace/Loans+Out+Schema -->
 
-    <!--  Batch Information Group -->
-    
-    <xs:element name="name" type="xs:string"/>
-    <xs:element name="notes" type="xs:string"/>
+       <!-- Batch Information Group -->
+       <xs:element name="name" type="xs:string" />
+       <xs:element name="notes" type="xs:string" />
     <xs:element name="forDocTypes">
+               <xs:complexType>
+                       <xs:sequence>
+                               <xs:element name="forDocType" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
+                       </xs:sequence>
+               </xs:complexType>
+       </xs:element>
+    <xs:element name="forRoles">
         <xs:complexType>
             <xs:sequence>
-                <xs:element name="forDocType" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
+                <xs:element name="roleDisplayName" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
             </xs:sequence>
         </xs:complexType>
     </xs:element>
-    <xs:element name="supportsNoContext" type="xs:boolean"/>
-    <xs:element name="supportsSingleDoc" type="xs:boolean"/>
-    <xs:element name="supportsDocList" type="xs:boolean"/>
-    <xs:element name="supportsGroup" type="xs:boolean"/>
-    <!-- NYI <xs:element name="supportsQuery" type="xs:boolean"/>  -->
-    <xs:element name="createsNewFocus" type="xs:boolean"/>
-    <xs:element name="className" type="xs:string"/>
+    <xs:element name="resourceActionGroupList" type="resourceActionGroupList"/>
+       <xs:element name="supportsNoContext" type="xs:boolean" />
+       <xs:element name="supportsSingleDoc" type="xs:boolean" />
+       <xs:element name="supportsDocList" type="xs:boolean" />
+       <xs:element name="supportsGroup" type="xs:boolean" />
+       <!-- Batch specific fields -->
+       <xs:element name="createsNewFocus" type="xs:boolean" />
+       <xs:element name="className" type="xs:string" />
+    
+    <xs:complexType name="resourceActionGroupList">
+        <xs:sequence>
+            <xs:element name="resourceActionGroup" type="resourceActionGroup" minOccurs="3" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    
+    <xs:complexType name="resourceActionGroup">
+        <xs:sequence>
+            <xs:element name="resourceName" type="xs:string"/>
+            <xs:element name="actionGroup" type="xs:string"/>
+        </xs:sequence>
+    </xs:complexType>
+    
 </xs:schema>
diff --git a/services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/instance1.xml b/services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/instance1.xml
new file mode 100644 (file)
index 0000000..bb247a7
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ns:className xmlns:ns="http://collectionspace.org/batch/"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://collectionspace.org/batch/ file:/C:/dev/src/cspace/services/services/batch/3rdparty/nuxeo-platform-cs-batch/src/main/resources/schemas/batch_common.xsd">className0</ns:className>
index 097bd972f37df2174a8c00e15de1719e6310f3e8..1a107f6ace84ab3d958c9c283c1d321850c9f246 100644 (file)
@@ -29,7 +29,8 @@ public class BatchClient extends AbstractCommonListPoxServiceClientImpl<BatchPro
        public static final String SERVICE_NAME = "batch";
        public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME;       
        public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT;
-       public static final String SERVICE_PAYLOAD_NAME = SERVICE_NAME; 
+       public static final String SERVICE_PAYLOAD_NAME = SERVICE_NAME;
+       public static final String SERVICE_COMMON_PART_NAME = SERVICE_NAME + PART_LABEL_SEPARATOR + PART_COMMON_LABEL;
 
        public BatchClient() throws Exception {
                super();
index bef6c3c0d813b5ed7b6afd76f4c9555b98bc46b3..e9246ce220eb3a11837fd34822faa9cd2dc22bc5 100644 (file)
@@ -9,7 +9,6 @@
     </parent>
     
     <modelVersion>4.0.0</modelVersion>
-    <groupId>org.collectionspace.services</groupId>
     <artifactId>org.collectionspace.services.batch.jaxb</artifactId>
     <name>services.batch.jaxb</name>
     
             <artifactId>org.collectionspace.services.jaxb</artifactId>
             <version>${project.version}</version>
         </dependency>        
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.hyperjaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>        
     </dependencies>
     
     <build>
diff --git a/services/batch/jaxb/src/main/resources/batch_common-template.xml b/services/batch/jaxb/src/main/resources/batch_common-template.xml
new file mode 100644 (file)
index 0000000..53890a8
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ns:batch_common xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
+    xmlns:ns="http://collectionspace.org/services/batch" 
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+    xsi:schemaLocation="http://collectionspace.org/services/batch file:batch_common.xsd">
+    <name>name0</name>
+    <notes>notes0</notes>
+    <forDocTypes>
+        <forDocType>CollectionObject</forDocType>
+        <forDocType>Intake</forDocType>
+    </forDocTypes>
+    <forRoles>
+        <roleDisplayName>TENANT_READER</roleDisplayName>
+        <roleDisplayName>TENANT_ADMINISTRATOR</roleDisplayName>
+    </forRoles>
+    <resourceActionGroupList>
+        <resourceActionGroup>
+            <resourceName>blobs</resourceName>
+            <actionGroup>CRUL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>media</resourceName>
+            <actionGroup>CRUL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>concepts</resourceName>
+            <actionGroup>RL</actionGroup>
+        </resourceActionGroup>
+        <resourceActionGroup>
+            <resourceName>collectionobjects</resourceName>
+            <actionGroup>RL</actionGroup>
+        </resourceActionGroup>
+    </resourceActionGroupList>
+    <supportsNoContext>false</supportsNoContext>
+    <supportsSingleDoc>false</supportsSingleDoc>
+    <supportsDocList>false</supportsDocList>
+    <supportsGroup>false</supportsGroup>
+    <createsNewFocus>false</createsNewFocus>
+    <className>className0</className>
+</ns:batch_common>
index 7b9eebd446f22bb907c031efa58883a23cd63f03..dd1437fa59ea63a8a0385569a901cc48a1a1306b 100644 (file)
                <xs:complexType>
                        <xs:sequence>
                                <!-- Batch Information Group -->
-                               <xs:element name="name" type="xs:string" />
+                           <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
                                <xs:element name="notes" type="xs:string" />
-                               <xs:element name="forDocTypes">
+                           <xs:element name="forDocTypes" minOccurs="0" maxOccurs="1">
                                        <xs:complexType>
                                                <xs:sequence>
-                                                       <xs:element name="forDocType" type="xs:string"
-                                                               minOccurs="1" maxOccurs="unbounded" />
+                                                       <xs:element name="forDocType" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
                                                </xs:sequence>
                                        </xs:complexType>
                                </xs:element>
-                               <xs:element name="supportsNoContext" type="xs:boolean" />
-                               <xs:element name="supportsSingleDoc" type="xs:boolean" />
-                               <xs:element name="supportsDocList" type="xs:boolean" />
-                               <xs:element name="supportsGroup" type="xs:boolean" />
+                           <xs:element name="forRoles" minOccurs="0" maxOccurs="1">
+                               <xs:complexType>
+                                   <xs:sequence>
+                                       <xs:element name="roleDisplayName" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
+                                   </xs:sequence>
+                               </xs:complexType>
+                           </xs:element>
+                           <xs:element name="resourceActionGroupList" type="resourceActionGroupList" minOccurs="0" maxOccurs="1"/>
+                           <xs:element name="supportsNoContext" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                           <xs:element name="supportsSingleDoc" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                           <xs:element name="supportsDocList" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                           <xs:element name="supportsGroup" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
                                <!-- Batch specific fields -->
-                               <xs:element name="createsNewFocus" type="xs:boolean" />
-                               <xs:element name="className" type="xs:string" />
+                           <xs:element name="createsNewFocus" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                           <xs:element name="className" type="xs:string" minOccurs="1" maxOccurs="1"/>
                        </xs:sequence>
                </xs:complexType>
        </xs:element>
 
+    <xs:complexType name="resourceActionGroupList">
+        <xs:sequence>
+            <xs:element name="resourceActionGroup" type="resourceActionGroup" minOccurs="1" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    
+    <xs:complexType name="resourceActionGroup">
+        <xs:sequence>
+            <xs:element name="resourceName" type="xs:string" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="actionGroup" type="xs:string" minOccurs="1" maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
 </xs:schema>
 
diff --git a/services/batch/jaxb/src/main/resources/batch_common_document.xsd b/services/batch/jaxb/src/main/resources/batch_common_document.xsd
new file mode 100644 (file)
index 0000000..15b1118
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
+    jaxb:version="1.0" elementFormDefault="unqualified" 
+    xmlns:ns="http://collectionspace.org/services/batch" 
+    xmlns="http://collectionspace.org/services/batch" targetNamespace="http://collectionspace.org/services/batch" version="0.1">
+
+    <!--
+        An XSD for a CollectionSpace "document" payload that contains a batch_common "part".  This is based on the
+        batch_common.xsd file.
+    -->
+    <!-- batch -->
+    <xs:element name="document">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="batch_common" minOccurs="1" maxOccurs="1">
+                    <xs:complexType>
+                        <xs:sequence>
+                            <!-- Batch Information Group -->
+                            <xs:element name="name" type="xs:string"></xs:element>
+                            <xs:element name="notes" type="xs:string"></xs:element>
+                            <xs:element name="forDocTypes" minOccurs="0" maxOccurs="1">
+                                <xs:complexType>
+                                    <xs:sequence>
+                                        <xs:element name="forDocType" type="xs:string" minOccurs="1" maxOccurs="unbounded"></xs:element>
+                                    </xs:sequence>
+                                </xs:complexType>
+                            </xs:element>
+                            <xs:element name="forRoles" minOccurs="0" maxOccurs="1">
+                                <xs:complexType>
+                                    <xs:sequence>
+                                        <xs:element name="roleDisplayName" type="xs:string" minOccurs="1" maxOccurs="unbounded"></xs:element>
+                                    </xs:sequence>
+                                </xs:complexType>
+                            </xs:element>
+                            <xs:element name="resourceActionGroupList" type="resourceActionGroupList" minOccurs="0" maxOccurs="1"></xs:element>
+                            <xs:element name="supportsNoContext" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                            <xs:element name="supportsSingleDoc" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                            <xs:element name="supportsDocList" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                            <xs:element name="supportsGroup" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                            <!-- Batch specific fields -->
+                            <xs:element name="createsNewFocus" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+                            <xs:element name="className" type="xs:string" minOccurs="1" maxOccurs="1"/>
+                        </xs:sequence>
+                    </xs:complexType>
+                </xs:element>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    
+    <xs:complexType name="resourceActionGroupList">
+        <xs:sequence>
+            <xs:element name="resourceActionGroup" type="resourceActionGroup" minOccurs="1" maxOccurs="unbounded"></xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="resourceActionGroup">
+        <xs:sequence>
+            <xs:element name="resourceName" type="xs:string" minOccurs="1" maxOccurs="1"></xs:element>
+            <xs:element name="actionGroup" type="xs:string" minOccurs="1" maxOccurs="1"></xs:element>
+        </xs:sequence>
+    </xs:complexType>
+</xs:schema>
diff --git a/services/batch/jaxb/src/main/resources/instance1.xml b/services/batch/jaxb/src/main/resources/instance1.xml
new file mode 100644 (file)
index 0000000..aa3a12c
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ns:document xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ xmlns:ns="http://collectionspace.org/services/batch"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://collectionspace.org/services/batch file:/C:/dev/src/cspace/services/services/batch/jaxb/src/main/resources/batch_common_document.xsd">
+    <ns:batch_common>
+        <ns:name>name0</ns:name>
+        <ns:notes>notes0</ns:notes>
+        <ns:forDocTypes>
+            <ns:forDocType>forDocType0</ns:forDocType>
+            <ns:forDocType>forDocType1</ns:forDocType>
+        </ns:forDocTypes>
+        <ns:forRoles>
+            <ns:roleDisplayName>roleDisplayName0</ns:roleDisplayName>
+            <ns:roleDisplayName>roleDisplayName1</ns:roleDisplayName>
+        </ns:forRoles>
+        <ns:resourceActionGroupList>
+            <ns:resourceActionGroup>
+                <ns:resourceName>resourceName0</ns:resourceName>
+                <ns:actionGroup>actionGroup0</ns:actionGroup>
+            </ns:resourceActionGroup>
+            <ns:resourceActionGroup>
+                <ns:resourceName>resourceName1</ns:resourceName>
+                <ns:actionGroup>actionGroup1</ns:actionGroup>
+            </ns:resourceActionGroup>
+        </ns:resourceActionGroupList>
+        <ns:supportsNoContext>false</ns:supportsNoContext>
+        <ns:supportsSingleDoc>false</ns:supportsSingleDoc>
+        <ns:supportsDocList>false</ns:supportsDocList>
+        <ns:supportsGroup>false</ns:supportsGroup>
+        <ns:createsNewFocus>false</ns:createsNewFocus>
+        <ns:className>className0</ns:className>
+    </ns:batch_common>
+</ns:document>
index 5f95b882078aa650ae6d2dc812a92248cd2f8183..c881fd723a34fbd04091fe1a7265757fdd8603b8 100644 (file)
             <groupId>org.collectionspace.services</groupId>
             <artifactId>org.collectionspace.services.common</artifactId>
         </dependency>
+               <dependency>
+                       <groupId>org.collectionspace.services</groupId>
+                       <artifactId>org.collectionspace.services.authentication.service</artifactId>
+                       <version>${project.version}</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.collectionspace.services</groupId>
+                       <artifactId>org.collectionspace.services.account.service</artifactId>
+                       <version>${project.version}</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.collectionspace.services</groupId>
+                       <artifactId>org.collectionspace.services.authorization.jaxb</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.collectionspace.services</groupId>
+                       <artifactId>org.collectionspace.services.authorization.service</artifactId>
+                       <version>${project.version}</version>
+               </dependency>        
         <dependency>
             <groupId>org.collectionspace.services</groupId>
             <artifactId>org.collectionspace.services.jaxb</artifactId>
index d5f0b74916df87432c252b50a91ddd31bd2b864b..c487489a7225a6e29bc291f86772d5b9ee4f24d0 100644 (file)
@@ -3,6 +3,9 @@ package org.collectionspace.services.batch;
 import java.util.Collections;
 import java.util.List;
 import javax.ws.rs.core.Response;
+
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.invocable.InvocationContext;
@@ -26,6 +29,7 @@ import org.slf4j.LoggerFactory;
  * - ADR 2013-01-04
  */
 public abstract class AbstractBatchInvocable implements BatchInvocable {
+    final Logger logger = LoggerFactory.getLogger(AbstractBatchInvocable.class);
 
     public final int OK_STATUS = Response.Status.OK.getStatusCode();
     public final int CREATED_STATUS = Response.Status.CREATED.getStatusCode();
@@ -33,15 +37,15 @@ public abstract class AbstractBatchInvocable implements BatchInvocable {
     public final int INT_ERROR_STATUS = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
     protected final String CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT =
             "Could not find required CSID values in the invocation context for this batch job.";
+    
+    private ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx;
     private List<String> invocationModes;
     private ResourceMap resourceMap;
-    private InvocationContext invocationCtx;
-    private ServiceContext ctx;
 
-    private int completionStatus;
-    private InvocationResults results;
-    private InvocationError errorInfo;
-    final Logger logger = LoggerFactory.getLogger(AbstractBatchInvocable.class);
+    protected InvocationContext invocationCtx;
+    protected int completionStatus;
+    protected InvocationResults results;
+    protected InvocationError errorInfo;
 
     public AbstractBatchInvocable() {
         init();
@@ -75,12 +79,12 @@ public abstract class AbstractBatchInvocable implements BatchInvocable {
     }
 
     @Override
-    public void setServiceContext(ServiceContext context) {
+    public void setServiceContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> context) {
         this.ctx = context;
     }
     
     @Override
-    public ServiceContext getServiceContext() {
+    public ServiceContext<PoxPayloadIn, PoxPayloadOut> getServiceContext() {
         return ctx;
     }
 
index 41322dbf6b0531d767ca86867fc1e203044f6455..aa38ece22be617d88a78da17fb7f82097174cdc1 100644 (file)
@@ -27,6 +27,7 @@ import org.collectionspace.services.BatchJAXBSchema;
 import org.collectionspace.services.batch.nuxeo.BatchDocumentModelHandler;
 import org.collectionspace.services.client.BatchClient;
 import org.collectionspace.services.client.IQueryManager;
+import org.collectionspace.services.client.PayloadPart;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.NuxeoBasedResource;
@@ -72,11 +73,7 @@ public class BatchResource extends NuxeoBasedResource {
     @Override
     //public Class<BatchCommon> getCommonPartClass() {
     public Class getCommonPartClass() {
-       try {
-            return Class.forName("org.collectionspace.services.batch.BatchCommon");//.class;
-        } catch (ClassNotFoundException e){
-            return null;
-        }
+       return BatchCommon.class;
     }
     
        /**
@@ -105,8 +102,7 @@ public class BatchResource extends NuxeoBasedResource {
         return list;
        }
 
-    private AbstractCommonList batchSearch(UriInfo ui, 
-                                                                               String docType, String mode) {
+    private AbstractCommonList batchSearch(UriInfo ui, String docType, String mode) {
         try {
             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
             DocumentHandler handler = createDocumentHandler(ctx);
@@ -158,10 +154,18 @@ public class BatchResource extends NuxeoBasedResource {
                }
                return ptClause;
        }
-
-
-
     
+       private BatchCommon getBatchCommon(String csid) throws Exception {
+               BatchCommon result = null;
+       
+       ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
+               PoxPayloadOut ppo = get(csid, ctx);
+               PayloadPart batchCommonPart = ppo.getPart(BatchClient.SERVICE_COMMON_PART_NAME);
+               result = (BatchCommon)batchCommonPart.getBody();
+               
+       return result;
+    }
+       
     @POST
     @Path("{csid}")
     public InvocationResults invokeBatchJob(
@@ -169,13 +173,15 @@ public class BatchResource extends NuxeoBasedResource {
                @Context UriInfo ui,
                @PathParam("csid") String csid,
                InvocationContext invContext) {
+
         try {
             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
             BatchDocumentModelHandler handler = (BatchDocumentModelHandler)createDocumentHandler(ctx);
-            
-            return handler.invokeBatchJob(ctx, csid, resourceMap, invContext);
+            return handler.invokeBatchJob(ctx, csid, resourceMap, invContext, getBatchCommon(csid));
         } catch (Exception e) {
-            throw bigReThrow(e, ServiceMessages.POST_FAILED);
+               String msg = String.format("%s Could not invoke batch job with CSID='%s'.", 
+                               ServiceMessages.POST_FAILED, csid);
+            throw bigReThrow(e, msg);
         }
     }
 }
index 5509ebf0c51df896656779f90fd818f48e8d5940..52f75556db7e49113e75ff99be1192bd236f6805 100644 (file)
  */
 package org.collectionspace.services.batch.nuxeo;
 
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.ws.rs.core.Response;
 
-import org.collectionspace.services.BatchJAXBSchema;
-import org.collectionspace.services.jaxb.InvocableJAXBSchema;
+import org.collectionspace.authentication.AuthN;
+import org.collectionspace.services.account.AccountResource;
+import org.collectionspace.services.authorization.AuthZ;
+import org.collectionspace.services.authorization.CSpaceResource;
+import org.collectionspace.services.authorization.PermissionException;
+import org.collectionspace.services.authorization.URIResourceImpl;
+import org.collectionspace.services.authorization.perms.ActionType;
 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
-import org.collectionspace.services.nuxeo.util.NuxeoUtils;
 import org.collectionspace.services.batch.BatchCommon;
+import org.collectionspace.services.batch.BatchCommon.ForDocTypes;
+import org.collectionspace.services.batch.BatchCommon.ForRoles;
 import org.collectionspace.services.batch.BatchInvocable;
+import org.collectionspace.services.batch.ResourceActionGroup;
+import org.collectionspace.services.batch.ResourceActionGroupList;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.ResourceMap;
+import org.collectionspace.services.common.authorization_mgt.ActionGroup;
 import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.document.BadRequestException;
 import org.collectionspace.services.common.document.DocumentException;
-import org.collectionspace.services.common.document.DocumentWrapper;
 import org.collectionspace.services.common.invocable.Invocable;
 import org.collectionspace.services.common.invocable.InvocationContext;
 import org.collectionspace.services.common.invocable.InvocationResults;
 import org.collectionspace.services.common.invocable.Invocable.InvocationError;
+
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.nuxeo.ecm.core.api.DocumentModel;
-import org.nuxeo.ecm.core.api.model.PropertyException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,28 +66,161 @@ public class BatchDocumentModelHandler extends NuxeoDocumentModelHandler<BatchCo
        private final Logger logger = LoggerFactory.getLogger(BatchDocumentModelHandler.class);
 
        protected final int BAD_REQUEST_STATUS = Response.Status.BAD_REQUEST.getStatusCode();
-
-       public InvocationResults invokeBatchJob(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String csid,
-                       ResourceMap resourceMap, InvocationContext invocationCtx) throws Exception {
-
-               CoreSessionInterface repoSession = null;
-               boolean releaseRepoSession = false;
-
-               String invocationMode = invocationCtx.getMode();
-               String modeProperty = null;
-               boolean checkDocType = true;
+       
+       /**
+        * Return true if the batch job supports the requested mode.
+        * @param invocationCtx
+        * @param batchCommon
+        * @return
+        * @throws BadRequestException 
+        */
+       protected boolean supportsInvokationMode(InvocationContext invocationCtx, BatchCommon batchCommon) throws BadRequestException {
+               boolean result = false;
+               
+               String invocationMode = invocationCtx.getMode().toLowerCase();
                if (BatchInvocable.INVOCATION_MODE_SINGLE.equalsIgnoreCase(invocationMode)) {
-                       modeProperty = BatchJAXBSchema.SUPPORTS_SINGLE_DOC;
+                       result = batchCommon.isSupportsSingleDoc(); //BatchJAXBSchema.SUPPORTS_SINGLE_DOC;
                } else if (BatchInvocable.INVOCATION_MODE_LIST.equalsIgnoreCase(invocationMode)) {
-                       modeProperty = BatchJAXBSchema.SUPPORTS_DOC_LIST;
+                       result = batchCommon.isSupportsDocList(); //BatchJAXBSchema.SUPPORTS_DOC_LIST;
                } else if (BatchInvocable.INVOCATION_MODE_GROUP.equalsIgnoreCase(invocationMode)) {
-                       modeProperty = BatchJAXBSchema.SUPPORTS_GROUP;
+                       result = batchCommon.isSupportsGroup(); //BatchJAXBSchema.SUPPORTS_GROUP;
                } else if (Invocable.INVOCATION_MODE_NO_CONTEXT.equalsIgnoreCase(invocationMode)) {
-                       modeProperty = InvocableJAXBSchema.SUPPORTS_NO_CONTEXT;
-                       checkDocType = false;
+                       result = batchCommon.isSupportsNoContext(); //InvocableJAXBSchema.SUPPORTS_NO_CONTEXT;
                } else {
-                       throw new BadRequestException("BatchResource: unknown Invocation Mode: " + invocationMode);
+                       String msg = String.format("BatchResource: Unknown invocation mode '%s' requested trying to invoke batch job '%s'.",
+                                       invocationMode, batchCommon.getName());
+                       throw new BadRequestException(msg);
+               }
+               
+               return result;
+       }
+       
+       /**
+        * Returns true if we found any required permissions.
+        * 
+        * @param batchCommon
+        * @return
+        */
+       private boolean hasRequiredPermissions(BatchCommon batchCommon) {
+               boolean result = false;
+               
+               try {
+                       result = batchCommon.getResourceActionGroupList().getResourceActionGroup().size() > 0;
+               } catch (NullPointerException e) {
+                       // ignore exception, we're just testing to see if we have any list elements
+               }
+               
+               return result;
+       }
+       
+       /**
+        * Returns true if we found any required roles.
+        * 
+        * @param batchCommon
+        * @return
+        */
+       private boolean hasRequiredRoles(BatchCommon batchCommon) {
+               boolean result = false;
+               
+               try {
+                       result = batchCommon.getForRoles().getRoleDisplayName().size() > 0;
+               } catch (NullPointerException e) {
+                       // ignore exception, we're just testing to see if we have any list elements
+               }
+               
+               return result;
+       }
+
+       /**
+        * The current user is authorized to run the batch job if:
+        *      1. No permissions or roles are specified in the batch job
+        *  2. No roles are specified, but permissions are specified and the current user has those permissions
+        *  3. Roles are specified and the current user is a member of at least one of the roles.
+        * 
+        * @param batchCommon
+        * @return
+        */
+       protected boolean isAuthoritzed(BatchCommon batchCommon) {
+               boolean result = true;
+               
+               if (hasRequiredRoles(batchCommon)) { 
+                       result = isAuthorizedWithRoles(batchCommon);
+               } else if (hasRequiredPermissions(batchCommon)) {
+                       result = isAuthoritzedWithPermissions(batchCommon);
+               }
+                               
+               return result;
+       }
+       
+       protected boolean isAuthorizedWithRoles(BatchCommon batchCommon) {
+               boolean result = false;
+               
+               ForRoles forRolesList = batchCommon.getForRoles();
+               if (forRolesList != null) {
+                       AccountResource accountResource = new AccountResource();
+                       List<String> roleDisplayNameList = accountResource.getAccountRoles(AuthN.get().getUserId(), AuthN.get().getCurrentTenantId());
+                       for (String target : forRolesList.getRoleDisplayName()) {
+                               if (roleDisplayNameList.contains(target)) {
+                                       result = true;
+                                       break;
+                               }
+                       }
+               }
+               
+               return result;
+       }
+       
+       /**
+        * Check to see if the current user is authorized to run/invoke this batch job.  If the batch job
+        * did not specify any permissions, we assume that the current user is authorized to run the job.
+        * @param batchCommon
+        * @return
+        */
+       protected boolean isAuthoritzedWithPermissions(BatchCommon batchCommon) {
+               boolean result = true;
+               
+               ResourceActionGroupList resourceActionGroupList = batchCommon.getResourceActionGroupList();
+               if (resourceActionGroupList != null) {
+                       String tenantId = AuthN.get().getCurrentTenantId();
+                       for (ResourceActionGroup resourceActionGroup: resourceActionGroupList.getResourceActionGroup()) {
+                               String resourceName = resourceActionGroup.getResourceName();
+                               ActionGroup actionGroup = ActionGroup.creatActionGroup(resourceActionGroup.getActionGroup());
+                               for (ActionType actionType: actionGroup.getActions()) {
+                                       CSpaceResource res = new URIResourceImpl(tenantId, resourceName, AuthZ.getMethod(actionType));
+                                       if (AuthZ.get().isAccessAllowed(res) == false) {
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+               
+               return result;
+       }
+       
+       /**
+        * Returns a copy of the incoming list of strings all lower-cased.  Also removes any duplicates.
+        * 
+        * @param listOfStrings
+        * @return
+        */
+       private List<String> toLowerCase(List<String> listOfStrings) {
+               List<String> result = null;
+               
+               if (listOfStrings != null) {
+                       Set<String> stringSet = new HashSet<String>();
+                       for (String s : listOfStrings) {
+                               stringSet.add(s.toLowerCase());
+                       }
+                       result = new ArrayList<String>(stringSet);
                }
+               
+               return result;
+       }
+
+       public InvocationResults invokeBatchJob(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String csid,
+                       ResourceMap resourceMap, InvocationContext invocationCtx, BatchCommon batchCommon) throws Exception {
+               CoreSessionInterface repoSession = null;
+               boolean releaseRepoSession = false;
 
                RepositoryClientImpl repoClient = (RepositoryClientImpl) this.getRepositoryClient(ctx);
                repoSession = this.getRepositorySession();
@@ -86,37 +229,97 @@ public class BatchDocumentModelHandler extends NuxeoDocumentModelHandler<BatchCo
                        releaseRepoSession = true;
                }
 
-               String className = null;
                // Get properties from the batch docModel, and release the session
                try {
-                       DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, csid);
-                       DocumentModel docModel = wrapper.getWrappedObject();
-                       Boolean supports = (Boolean) NuxeoUtils.getProperyValue(docModel, modeProperty);
-                       if (!supports) {
-                               throw new BadRequestException("BatchResource: This Batch Job does not support Invocation Mode: "
-                                               + invocationMode);
+                       //
+                       // Ensure the current user has permission to run this batch job
+                       if (isAuthoritzed(batchCommon) == false) {
+                               String msg = String.format("BatchResource: The user '%s' does not have permission to run the batch job '%s' CSID='%s'", 
+                                               AuthN.get().getUserId(), batchCommon.getName(), csid);
+                               throw new PermissionException(msg);
                        }
-                       if (checkDocType) {
-                               List<String> forDocTypeList = (List<String>) NuxeoUtils.getProperyValue(docModel, BatchJAXBSchema.FOR_DOC_TYPES); //docModel.getPropertyValue(BatchJAXBSchema.FOR_DOC_TYPES);
-                               if (forDocTypeList == null || !forDocTypeList.contains(invocationCtx.getDocType())) {
-                                       throw new BadRequestException("BatchResource: Invoked with unsupported document type: "
-                                                       + invocationCtx.getDocType());
+                       
+                       //
+                       // Ensure the batch job supports the requested invocation context's mode type
+                       if (supportsInvokationMode(invocationCtx, batchCommon) == false) {
+                               String msg = String.format("BatchResource: The batch job '%s' CSID='%s' does not support the invocation mode '%s'.", 
+                                               batchCommon.getName(), csid, invocationCtx.getMode());
+                               throw new BadRequestException(msg);
+                       }
+                       
+                       //
+                       // Ensure the batch job supports the requested invocation context's document type
+                       if (!Invocable.INVOCATION_MODE_NO_CONTEXT.equalsIgnoreCase(invocationCtx.getMode())) {
+                               ForDocTypes forDocTypes = batchCommon.getForDocTypes();
+                               if (forDocTypes != null) {
+                                       List<String> forDocTypeList = toLowerCase(forDocTypes.getForDocType()); // convert all strings to lowercase.
+                                       if (forDocTypeList == null || !forDocTypeList.contains(invocationCtx.getDocType().toLowerCase())) {
+                                               String msg = String.format("BatchResource: The batch job '%s' CSID='%s' does not support the invocation document type '%s'.", 
+                                                               batchCommon.getName(), csid, invocationCtx.getDocType());
+                                               throw new BadRequestException(msg);
+                                       }
                                }
                        }
-                       className = (String) NuxeoUtils.getProperyValue(docModel, BatchJAXBSchema.BATCH_CLASS_NAME); //docModel.getPropertyValue(BatchJAXBSchema.BATCH_CLASS_NAME);
-               } catch (PropertyException pe) {
-                       if (logger.isDebugEnabled()) {
-                               logger.debug("Property exception getting batch values: ", pe);
+
+                       //
+                       // Now that we've ensure all the prerequisites have been met, let's try to
+                       // instantiate and run the batch job.
+                       //
+                       
+                       String className = batchCommon.getClassName().trim();
+                       ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+                       Class<?> c = tccl.loadClass(className);
+                       tccl.setClassAssertionStatus(className, true);
+                       if (!BatchInvocable.class.isAssignableFrom(c)) {
+                               throw new RuntimeException("BatchResource: Class: " + className + " does not implement BatchInvocable!");
+                       }
+       
+                       BatchInvocable batchInstance = (BatchInvocable) c.newInstance();
+                       List<String> modes = batchInstance.getSupportedInvocationModes();
+                       if (!modes.contains(invocationCtx.getMode().toLowerCase())) {
+                               String msg = String.format("BatchResource: Invoked with unsupported mode '%s'.  Batch class '%s' supports these modes: %s.",
+                                               invocationCtx.getMode().toLowerCase(), className, modes.toString());
+                               throw new BadRequestException(msg);
+                       }
+       
+                       batchInstance.setInvocationContext(invocationCtx);
+                       batchInstance.setServiceContext(ctx);
+                       
+                       if (resourceMap != null) {
+                               batchInstance.setResourceMap(resourceMap);
+                       } else {
+                               resourceMap = ResteasyProviderFactory.getContextData(ResourceMap.class);
+                               if (resourceMap != null) {
+                                       batchInstance.setResourceMap(resourceMap);
+                               } else {
+                                       logger.warn("BatchResource.invoke did not get a resourceMapHolder in context!");
+                               }
+                       }
+       
+                       batchInstance.run();
+                       int status = batchInstance.getCompletionStatus();
+                       if (status == Invocable.STATUS_ERROR) {
+                               InvocationError error = batchInstance.getErrorInfo();
+                               if (error.getResponseCode() == BAD_REQUEST_STATUS) {
+                                       throw new BadRequestException("BatchResouce: batchProcess encountered error: "
+                                                       + batchInstance.getErrorInfo());
+                               } else {
+                                       throw new RuntimeException("BatchResouce: batchProcess encountered error: "
+                                                       + batchInstance.getErrorInfo());
+       
+                               }
                        }
-                       throw pe;
-               } catch (DocumentException de) {
+       
+                       InvocationResults results = batchInstance.getResults();
+                       return results;
+               } catch (PermissionException e) {
                        if (logger.isDebugEnabled()) {
-                               logger.debug("Problem getting batch doc: ", de);
+                               logger.debug("BatchResource: Caught exception ", e);
                        }
-                       throw de;
+                       throw e;
                } catch (Exception e) {
                        if (logger.isDebugEnabled()) {
-                               logger.debug("Caught exception ", e);
+                               logger.debug("BatchResource: Caught exception ", e);
                        }
                        throw new DocumentException(e);
                } finally {
@@ -124,51 +327,5 @@ public class BatchDocumentModelHandler extends NuxeoDocumentModelHandler<BatchCo
                                repoClient.releaseRepositorySession(ctx, repoSession);
                        }
                }
-
-               className = className.trim();
-               ClassLoader tccl = Thread.currentThread().getContextClassLoader();
-               Class<?> c = tccl.loadClass(className);
-               // enable validation assertions
-               tccl.setClassAssertionStatus(className, true);
-               if (!BatchInvocable.class.isAssignableFrom(c)) {
-                       throw new RuntimeException("BatchResource: Class: " + className + " does not implement BatchInvocable!");
-               }
-
-               BatchInvocable batchInstance = (BatchInvocable) c.newInstance();
-               List<String> modes = batchInstance.getSupportedInvocationModes();
-               if (!modes.contains(invocationMode)) {
-                       throw new BadRequestException("BatchResource: Invoked with unsupported context mode: " + invocationMode);
-               }
-
-               batchInstance.setInvocationContext(invocationCtx);
-               batchInstance.setServiceContext(ctx);
-               
-               if (resourceMap != null) {
-                       batchInstance.setResourceMap(resourceMap);
-               } else {
-                       resourceMap = ResteasyProviderFactory.getContextData(ResourceMap.class);
-                       if (resourceMap != null) {
-                               batchInstance.setResourceMap(resourceMap);
-                       } else {
-                               logger.warn("BatchResource.invoke did not get a resourceMapHolder in Context!");
-                       }
-               }
-
-               batchInstance.run();
-               int status = batchInstance.getCompletionStatus();
-               if (status == Invocable.STATUS_ERROR) {
-                       InvocationError error = batchInstance.getErrorInfo();
-                       if (error.getResponseCode() == BAD_REQUEST_STATUS) {
-                               throw new BadRequestException("BatchResouce: batchProcess encountered error: "
-                                               + batchInstance.getErrorInfo());
-                       } else {
-                               throw new RuntimeException("BatchResouce: batchProcess encountered error: "
-                                               + batchInstance.getErrorInfo());
-
-                       }
-               }
-
-               InvocationResults results = batchInstance.getResults();
-               return results;
        }
 }
index 4598b146d2fc14ffdb472f7dbc65f8a5b1a520e1..c864a662ede4a7daadaa0fe068bf4fa942384c00 100644 (file)
 package org.collectionspace.services.batch.nuxeo;
 
-import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.batch.BatchCommon;
+import org.collectionspace.services.batch.BatchInvocable;
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.document.InvalidDocumentException;
-import org.collectionspace.services.common.document.ValidatorHandler;
-import org.collectionspace.services.common.document.DocumentHandler.Action;
+import org.collectionspace.services.common.document.ValidatorHandlerImpl;
 
-public class BatchValidatorHandler implements ValidatorHandler {
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BatchValidatorHandler extends ValidatorHandlerImpl<PoxPayloadIn, PoxPayloadOut> {
+
+    final Logger logger = LoggerFactory.getLogger(BatchValidatorHandler.class);
+
+    //
+    // Error Strings
+    //
+    private static final String VALIDATION_ERROR = "The batch record payload was invalid. See log file for more details.";
+    private static final String NAME_NULL_ERROR = "The batch record field \"name\" cannot be empty or missing.";
+       private static final String MISSING_CLASS_ERROR = "The Java class '%s' (fully qualified with package name) for the batch job named '%s' cannot be found.";
+
+       @Override
+       protected Class<?> getCommonPartClass() {
+               return BatchCommon.class;
+       }
+
+       @Override
+       protected void handleCreate() throws InvalidDocumentException {
+       try {
+               BatchCommon batchCommon = (BatchCommon) getCommonPart();
+               validateBatchCommon(batchCommon);                        
+       } catch (AssertionError e) {
+               if (logger.isErrorEnabled() == true) {
+                       logger.error(e.getMessage(), e);
+               }
+               throw new InvalidDocumentException(VALIDATION_ERROR, e);
+       }
+    }
+
+       @Override
+       protected void handleGet() throws InvalidDocumentException {
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       protected void handleGetAll() throws InvalidDocumentException {
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       protected void handleUpdate() throws InvalidDocumentException {
+       try {
+               BatchCommon batchCommon = (BatchCommon) getCommonPart();
+               validateBatchCommon(batchCommon);                        
+       } catch (AssertionError e) {
+               if (logger.isErrorEnabled() == true) {
+                       logger.error(e.getMessage(), e);
+               }
+               throw new InvalidDocumentException(VALIDATION_ERROR, e);
+       }
+    }
 
        @Override
-       public void validate(Action action, ServiceContext ctx)
-                       throws InvalidDocumentException {
+       protected void handleDelete() throws InvalidDocumentException {
                // TODO Auto-generated method stub
-               //System.out.println("BatchValidatorHandler executed.");
+               
        }
 
+    //
+    // Private Methods
+    //
+       private boolean canFindClass(String className) {
+               boolean result = false;
+               
+               try {
+                       ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+                       Class<?> c = tccl.loadClass(className);
+                       tccl.setClassAssertionStatus(className, true);
+                       if (!BatchInvocable.class.isAssignableFrom(c)) {
+                               throw new RuntimeException("BatchResource: Class: " + className + " does not implement BatchInvocable!");
+                       }
+                       result = true;
+               } catch (Exception e) {
+                       String msg = String.format("Could not find load batch class named '%s'",
+                                       className);
+                       logger.debug(msg, e);
+               }
+
+               return result;
+       }
+       
+       private void validateBatchCommon(BatchCommon batchCommon) {
+       CS_ASSERT(batchCommon != null);
+       
+       //
+       // Ensure a batch name
+        String batchName = batchCommon.getName();
+        CS_ASSERT(batchName != null, NAME_NULL_ERROR);
+        CS_ASSERT(batchName.isEmpty() == false, NAME_NULL_ERROR);
+        
+       //
+       // Ensure a batch class
+        String batchClassName = batchCommon.getClassName();
+        CS_ASSERT(batchName != null, NAME_NULL_ERROR);
+        CS_ASSERT(batchName.isEmpty() == false, NAME_NULL_ERROR);
+        
+        //
+        // Ensure we can find and load the batch Java class
+        if (canFindClass(batchClassName) == false) {
+               String msg = String.format(MISSING_CLASS_ERROR, batchClassName, batchCommon.getName());
+               CS_ASSERT(false, batchClassName);
+        }
+    }
+       
 }
index 1781753f1a4662f9b7113ed3c9ca03a8dc4c8e17..4ac26db5bf0b1fae8c285655446d9e3280b27b95 100644 (file)
 package org.collectionspace.services.batch.nuxeo;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.ws.rs.core.Response;
 
-import org.collectionspace.services.batch.BatchInvocable;
+import org.collectionspace.services.batch.AbstractBatchInvocable;
 import org.collectionspace.services.client.CollectionSpaceClientUtils;
 import org.collectionspace.services.common.NuxeoBasedResource;
-import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.api.GregorianCalendarDateTimeUtils;
-import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.invocable.InvocationContext;
-import org.collectionspace.services.common.invocable.InvocationResults;
 import org.collectionspace.services.client.LoanoutClient;
 import org.collectionspace.services.client.RelationClient;
 
-public class CreateAndLinkLoanOutBatchJob implements BatchInvocable {
+public class CreateAndLinkLoanOutBatchJob extends AbstractBatchInvocable {
 
-       private static ArrayList<String> invocationModes = null;
-       private InvocationContext invocationCtx;
-       private ServiceContext ctx;
-       private int completionStatus;
-       private ResourceMap resourceMap;
-       private InvocationResults results;
-       private InvocationError errorInfo;
        private final String RELATION_TYPE = "affects"; 
        private final String LOAN_DOCTYPE = "LoanOut"; 
        private final String RELATION_PREDICATE_DISP = "affects"; 
-       protected final int CREATED_STATUS = Response.Status.CREATED.getStatusCode();
-       protected final int BAD_REQUEST_STATUS = Response.Status.BAD_REQUEST.getStatusCode();
-       protected final int INT_ERROR_STATUS = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
        
        public CreateAndLinkLoanOutBatchJob() {
-               CreateAndLinkLoanOutBatchJob.setupClassStatics();
-               invocationCtx = null;
-               completionStatus = STATUS_UNSTARTED;
-               resourceMap = null;
-               results = new InvocationResults();
-               errorInfo = null;
+        setSupportedInvocationModes(Arrays.asList(INVOCATION_MODE_SINGLE, INVOCATION_MODE_LIST));
        }
-
-       private static void setupClassStatics() {
-               if(invocationModes == null ) {
-                       invocationModes = new ArrayList<String>(1);
-                       invocationModes.add(INVOCATION_MODE_SINGLE);
-                       invocationModes.add(INVOCATION_MODE_LIST);
-               }
-       }
-
-       /**
-        * @return a set of modes that this plugin can support on invocation. Must be non-empty.
-        */
-       public List<String> getSupportedInvocationModes() {
-               return CreateAndLinkLoanOutBatchJob.invocationModes;
-       }
-       
-    @Override
-    public void setServiceContext(ServiceContext context) {
-        this.ctx = context;
-    }
-    
-    @Override
-    public ServiceContext getServiceContext() {
-        return ctx;
-    }
-
-    @Override
-    public InvocationContext getInvocationContext() {
-        return invocationCtx;
-    }    
        
-       /**
-        * Sets the invocation context for the batch job. Called before run().
-        * @param context an instance of InvocationContext.
-        */
-    @Override
-       public void setInvocationContext(InvocationContext context) {
-               this.invocationCtx = context;
-       }
-
-       /**
-        * Sets the invocation context for the batch job. Called before run().
-        * @param invocationCtx an instance of InvocationContext.
-        */
-       public void setResourceMap(ResourceMap resourceMap) {
-               this.resourceMap = resourceMap;
-       }
-
        /**
         * The main work logic of the batch job. Will be called after setContext.
         */
+       @Override
        public void run() {
                completionStatus = STATUS_MIN_PROGRESS;
 
                try {
                        // First, create the Loanout
-                       if(createLoan() != STATUS_ERROR) {
+                       if (createLoan() != STATUS_ERROR) {
                                if(INVOCATION_MODE_SINGLE.equalsIgnoreCase(invocationCtx.getMode())) {
                                        if(createRelation(results.getPrimaryURICreated(), 
                                                                                invocationCtx.getSingleCSID()) != STATUS_ERROR) {
@@ -151,8 +87,8 @@ public class CreateAndLinkLoanOutBatchJob implements BatchInvocable {
 
                // First, create the Loanout
                // We fetch the resource class by service name
-               NuxeoBasedResource resource = (NuxeoBasedResource) resourceMap.get( LoanoutClient.SERVICE_NAME); 
-               Response response = resource.create(resourceMap, null, loanoutPayload);
+               NuxeoBasedResource resource = (NuxeoBasedResource) getResourceMap().get( LoanoutClient.SERVICE_NAME); 
+               Response response = resource.create(getResourceMap(), null, loanoutPayload);
                if(response.getStatus() != CREATED_STATUS) {
                        completionStatus = STATUS_ERROR;
                        errorInfo = new InvocationError(INT_ERROR_STATUS,
@@ -177,8 +113,8 @@ public class CreateAndLinkLoanOutBatchJob implements BatchInvocable {
                        +   "<relationshipType>"+RELATION_TYPE+"</relationshipType>"
                        +   "<predicateDisplayName>"+RELATION_PREDICATE_DISP+"</predicateDisplayName>"
                        + "</ns2:relations_common></document>";
-               NuxeoBasedResource resource = (NuxeoBasedResource) resourceMap.get(RelationClient.SERVICE_NAME);
-               Response response = resource.create(resourceMap, null, relationPayload);
+               NuxeoBasedResource resource = (NuxeoBasedResource) getResourceMap().get(RelationClient.SERVICE_NAME);
+               Response response = resource.create(getResourceMap(), null, relationPayload);
                if(response.getStatus() != CREATED_STATUS) {
                        completionStatus = STATUS_ERROR;
                        errorInfo = new InvocationError(INT_ERROR_STATUS,
@@ -187,32 +123,4 @@ public class CreateAndLinkLoanOutBatchJob implements BatchInvocable {
                }
                return completionStatus;
        }
-
-       /**
-        * @return one of the STATUS_* constants, or a value from 1-99 to indicate progress.
-        * Implementations need not support partial completion (progress) values, and can transition
-        * from STATUS_MIN_PROGRESS to STATUS_COMPLETE.
-        */
-       public int getCompletionStatus() {
-               return completionStatus;
-       }
-
-       /**
-        * @return information about the batch job actions and results
-        */
-       public InvocationResults getResults() {
-               if(completionStatus != STATUS_COMPLETE)
-                       return null;
-               return results;
-       }
-
-       /**
-        * @return a user-presentable note when an error occurs in batch processing. Will only
-        * be called if getCompletionStatus() returns STATUS_ERROR.
-        */
-       public InvocationError getErrorInfo() {
-               return errorInfo;
-       }
-
-
 }
diff --git a/services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/TestBatchJob.java b/services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/TestBatchJob.java
new file mode 100644 (file)
index 0000000..0358cf9
--- /dev/null
@@ -0,0 +1,20 @@
+package org.collectionspace.services.batch.nuxeo;
+
+import java.util.Arrays;
+
+import org.collectionspace.services.batch.AbstractBatchInvocable;
+
+public class TestBatchJob extends AbstractBatchInvocable {
+
+       public TestBatchJob() {
+               super();
+        setSupportedInvocationModes(Arrays.asList(INVOCATION_MODE_SINGLE, INVOCATION_MODE_LIST,
+                INVOCATION_MODE_GROUP, INVOCATION_MODE_NO_CONTEXT));
+       }
+       
+       @Override
+       public void run() {
+               // An empty batch job used just for testing.
+       }
+
+}
index b4ea9c4e5c15ea0642d6733bf58ceec2025f6690..add7e158e572f9cd8a390491e758b7dc48ffb77d 100644 (file)
@@ -14,7 +14,6 @@ import javax.ws.rs.core.PathSegment;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.services.batch.AbstractBatchInvocable;
-import org.collectionspace.services.batch.UriInfoImpl;
 import org.collectionspace.services.client.AbstractCommonListUtils;
 import org.collectionspace.services.client.CollectionObjectClient;
 import org.collectionspace.services.client.IClientQueryParams;
@@ -27,6 +26,7 @@ import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.api.RefNameUtils;
 import org.collectionspace.services.common.api.Tools;
 import org.collectionspace.services.common.invocable.InvocationResults;
+import org.collectionspace.services.common.query.UriInfoImpl;
 import org.collectionspace.services.jaxb.AbstractCommonList;
 import org.dom4j.DocumentException;
 //import org.jboss.resteasy.specimpl.UriInfoImpl;
@@ -137,7 +137,6 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
         ResourceMap resourcemap = getResourceMap();
         NuxeoBasedResource collectionObjectResource = (NuxeoBasedResource) resourcemap.get(CollectionObjectClient.SERVICE_NAME);
         NuxeoBasedResource movementResource = (NuxeoBasedResource) resourcemap.get(MovementClient.SERVICE_NAME);
-        String computedCurrentLocation;
         long numUpdated = 0;
         long processed = 0;
 
@@ -397,8 +396,11 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
         }
         
         UriInfo uriInfo = this.setupQueryParamForUpdateRecords(); // Determines if we'll updated the updateAt and updatedBy core values
-        byte[] response = collectionObjectResource.update(resourcemap, uriInfo, collectionObjectCsid,
-                collectionObjectUpdatePayload);
+        if (logger.isDebugEnabled()) {
+               byte[] responseBytes = collectionObjectResource.update(resourcemap, uriInfo, collectionObjectCsid,
+                       collectionObjectUpdatePayload);
+               logger.debug(String.format("Batch resource: Resonse from collectionobject (cataloging record) update: %s", new String(responseBytes)));
+        }
         numUpdated++;
         
         if (logger.isTraceEnabled()) {
@@ -635,7 +637,6 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
         }
     }
     
-
     private List<String> getMemberCsidsFromGroup(String serviceName, String groupCsid) throws URISyntaxException, DocumentException {
         ResourceMap resourcemap = getResourceMap();
         NuxeoBasedResource resource = (NuxeoBasedResource) resourcemap.get(serviceName);
@@ -659,7 +660,6 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
 
         boolean morePages = true;
         long currentPage = 0;
-        long totalItems = 0;
         long pageSize = DEFAULT_PAGE_SIZE;
         List<String> noContextCsids = new ArrayList<String>();
         
index 76577afe9f04543c3016b9b86585d2f72e8f4bfe..af3648d4c51bdf2ac2a87385f657e09d5e29548e 100644 (file)
@@ -63,11 +63,11 @@ public abstract class PoxPayload<PT extends PayloadPart> {
        private void setDomDocument(Document dom) throws DocumentException {
                this.domDocument = dom;
                String label = domDocument.getRootElement().getName();
-               if (label != null) {
+               if (label != null && label.equalsIgnoreCase("document")) {
                        this.payloadName = label;
-               } else if (logger.isWarnEnabled() == true) {
-                       logger.warn("Incoming message payload is missing a name/label.");
-                       logger.warn(this.xmlPayload);
+               } else {
+                       String msg = "The following incoming request payload is missing the root <document> element or is otherwise malformed.  For example valid payloads, see https://wiki.collectionspace.org/display/DOC/Common+Services+REST+API+documentation";
+                       throw new DocumentException(msg + '\n' + this.xmlPayload);
                }
                parseParts();
        }
@@ -295,7 +295,7 @@ public abstract class PoxPayload<PT extends PayloadPart> {
     }
       
     /**
-     * Attempts to marshal a DOM4j element (for a part) into an instance of a JAXB object
+     * Attempts to unmarshal a DOM4j element (for a part) into an instance of a JAXB object
      *
      * @param elementInput the element input
      * @return the object
@@ -310,9 +310,9 @@ public abstract class PoxPayload<PT extends PayloadPart> {
                result = um.unmarshal(
                                new StreamSource(new StringReader(elementInput.asXML())));                              
        } catch (Exception e) {
-               if (logger.isTraceEnabled() == true) {
-                       logger.trace(e.getMessage());
-               }
+               String msg = String.format("Could not unmarshal XML payload '%s' into a JAXB object.", 
+                               elementInput.getName());
+               logger.warn(msg);
        }
        
        return result;
@@ -345,7 +345,9 @@ public abstract class PoxPayload<PT extends PayloadPart> {
                Document doc = DocumentHelper.parseText(text);
                result = doc.getRootElement(); //FIXME: REM - call .detach() to free the element
        } catch (Exception e) {
-               e.printStackTrace(); //FIXME: REM - Please use proper logger.isWarning() statement
+               String msg = String.format("Could not marshal JAXB object '%s' to an XML element.",
+                               jaxbObject.toString());
+               logger.error(msg);
        }
        
        return result;
index 16d356ee84d9f0794b3cc2e888e88c44a4f0f5b4..427228b76c6dab3fe226e110f45664437ea23fb2 100644 (file)
@@ -241,24 +241,25 @@ public class Tools {
       * presentation of error messages to clients.
      * @param includeLines if zero, return all lines of stack trace, otherwise return number of lines from top.
       */
-    public static String errorToString(Throwable e, boolean stackTraceOnException, int includeLines){
-        if (e==null){
-            return "";
-        }
-        String s = e.toString() + "\r\n  -- message: " + e.getMessage();
-
-        StringBuffer causeBuffer = new StringBuffer();
-        Throwable cause = e.getCause();
-        while (cause != null){
-            causeBuffer.append(cause.getClass().getName()+"::"+cause.getMessage()+"\r\n");
-            cause = cause.getCause();
-        }
-        if (causeBuffer.length()>0) s = s + "\r\n  -- Causes: "+causeBuffer.toString();
+       public static String errorToString(Throwable e, boolean stackTraceOnException, int includeLines) {
+               if (e == null) {
+                       return "";
+               }
+               String s = "\r\n  -- Exception: " + e.getClass().getCanonicalName() + "\r\n  -- Message: " + e.getMessage();
 
+               StringBuffer causeBuffer = new StringBuffer();
+               Throwable cause = e.getCause();
+               while (cause != null) {
+                       causeBuffer.append(cause.getClass().getName() + "::" + cause.getMessage() + "\r\n");
+                       cause = cause.getCause();
+               }
+               if (causeBuffer.length() > 0) {
+                       s = s + "\r\n  -- Causes: " + causeBuffer.toString();
+               }
 
-        s = s + "\r\n  -- Stack Trace: \r\n  --      " + getStackTrace(e, includeLines);
-        return s;
-    }
+               s = s + "\r\n  -- Stack Trace: \r\n  --      " + getStackTrace(e, includeLines);
+               return s;
+       }
 
     /**
      * Return a set of properties from a properties file.
index 1a5dde637f3b273d2640fc874269f39545ba48f3..d89d51bbccb73ee2e9e5c62e3f4f8896febfd629 100644 (file)
@@ -37,9 +37,8 @@ import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
+import org.collectionspace.services.authorization.PermissionException;
 import org.collectionspace.services.client.CollectionSpaceClient;
-import org.collectionspace.services.client.PoxPayloadIn;
-import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.CSWebApplicationException;
 import org.collectionspace.services.common.api.Tools;
 import org.collectionspace.services.common.config.ServiceConfigUtils;
@@ -501,6 +500,10 @@ public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
             response = Response.status(Response.Status.UNAUTHORIZED).entity(serviceMsg + e.getMessage()).type("text/plain").build();
             result = new CSWebApplicationException(e, response);
 
+        } else if (e instanceof PermissionException) {
+            response = Response.status(Response.Status.FORBIDDEN).entity(serviceMsg + e.getMessage()).type("text/plain").build();
+            result = new CSWebApplicationException(e, response);
+
         } else if (e instanceof DocumentNotFoundException) {
                //
                // Don't log this error unless we're in 'trace' mode
@@ -534,6 +537,10 @@ public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
             // return new WebApplicationException(e, code);
             result = new CSWebApplicationException(e, response);
            
+        } else if (e instanceof org.dom4j.DocumentException) {
+            int code = Response.Status.BAD_REQUEST.getStatusCode();
+            response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
+            result = new CSWebApplicationException(e, response);     
         } else if (e instanceof CSWebApplicationException) {
             // subresource may have already thrown this exception
             // so just pass it on
index 2c06dd3e430433208e927c17937d4e09db3fd0f7..dd7b84db3e70b34c4fef7c8fba7fb8c605dfcec3 100644 (file)
@@ -62,7 +62,7 @@ public interface CollectionSpaceResource<IT, OT> {
      * @param ctx the ctx
      * @return the repository client
      */
-    public RepositoryClient getRepositoryClient(ServiceContext<IT, OT> ctx);
+    public RepositoryClient<IT, OT> getRepositoryClient(ServiceContext<IT, OT> ctx);
 
     /**
      * Gets the storage client.
index 37508b209be7c3e9175de862602787944a9d6d2c..ccfc4344a6f20e9a9d9f22679433e9523cda63b5 100644 (file)
@@ -158,7 +158,7 @@ public abstract class NuxeoBasedResource
                @Context UriInfo uriInfo,
             String xmlPayload) {
        uriInfo = new UriInfoWrapper(uriInfo);
-        return this.create(null, resourceMap, uriInfo, xmlPayload); 
+        return this.create(null, resourceMap, uriInfo, xmlPayload);
     }
     
     public Response create(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx, // REM: 8/13/2012 - Some sub-classes will override this method -e.g., MediaResource does.
index d11f69c736a642dfefb157a6cfb6fbabb61870b9..259baf6840c5eca45572e4b3a2eb65209004731a 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<IT, OT> extends Map<String, CollectionSpaceResource<IT, OT>> {
+public interface ResourceMap extends Map<String, CollectionSpaceResource<?, ?>> {
 
 }
index 85407e90438dbe4870623856dc4b506e13e1802e..9c31fab1e0a15aa56618a4ea29389e711cfb9ab6 100644 (file)
@@ -2,10 +2,7 @@ package org.collectionspace.services.common;
 
 import java.util.HashMap;
 
-import org.collectionspace.services.client.PoxPayloadIn;
-import org.collectionspace.services.client.PoxPayloadOut;
-
-public class ResourceMapImpl extends HashMap<String, CollectionSpaceResource<PoxPayloadIn, PoxPayloadOut>> implements ResourceMap<PoxPayloadIn, PoxPayloadOut> {
+public class ResourceMapImpl extends HashMap<String, CollectionSpaceResource<?, ?>> implements ResourceMap {
 
        /**
         * 
index 9821be5f718766c4d340384d31082e1afa5fe4e2..d7fa1a585655362895c07c047e764cfc013bcec0 100644 (file)
@@ -822,10 +822,10 @@ public class ServiceMain {
      */
     private synchronized void populateUriTemplateRegistry() {
        if (uriTemplateRegistry.isEmpty()) {
-          CollectionSpaceResource resource = null;
+          CollectionSpaceResource<?, ?> resource = null;
             ResourceMap resourceMap = getJaxRSResourceMap();
-            Set<Map.Entry<String, CollectionSpaceResource>> entrySet = resourceMap.entrySet();
-            for (Map.Entry<String, CollectionSpaceResource> entry : entrySet) {
+            Set<Map.Entry<String, CollectionSpaceResource<?, ?>>> entrySet = resourceMap.entrySet();
+            for (Map.Entry<String, CollectionSpaceResource<?, ?>> entry : entrySet) {
                 resource = entry.getValue();
                 Map<UriTemplateRegistryKey, StoredValuesUriTemplate> entries =
                         resource.getUriRegistryEntries();
diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/ActionGroup.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/ActionGroup.java
new file mode 100644 (file)
index 0000000..ea86045
--- /dev/null
@@ -0,0 +1,200 @@
+package org.collectionspace.services.common.authorization_mgt;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.collectionspace.services.authorization.perms.ActionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ActionGroup {
+    final static Logger logger = LoggerFactory.getLogger(ActionGroup.class);
+
+       String name;
+       ActionType[] actions = {};
+       
+       static private String toString(ActionType[] actionTypes) {
+               String result = null;
+               
+               if (actionTypes.length > 0) {
+                       result = new String();
+                       for (ActionType actionType: actionTypes) {
+                               result = result + actionType.value() + ':';
+                       }
+               }
+               
+               return result;
+       }
+       
+       static private String toString(List<Character> charList) {
+               String result = null;
+               
+               if (charList.isEmpty() == false) {
+                       result = new String();
+                       for (Character c: charList) {
+                               result = result + c;
+                       }
+               }
+               
+               return result;
+       }
+       
+       static int valueOf(Character c) {
+               int result = 0;
+               
+               switch (c) {
+               case 'C':
+                       result = 1;
+                       break;
+               case 'R':
+                       result = 2;
+                       break;
+               case 'U':
+                       result = 3;
+                       break;
+               case 'D':
+                       result = 4;
+                       break;
+               case 'I':
+                       result = 5;
+                       break;
+               case 'L':
+                       result = 6;
+                       break;
+               default:
+                       result = 0;
+               }
+               
+               return result;
+       }
+       
+       static int valueOf(ActionType actionType) {
+               int result = 0;
+               
+               switch (actionType) {
+               case CREATE:
+                       result = 1;
+                       break;
+               case READ:
+                       result = 2;
+                       break;
+               case UPDATE:
+                       result = 3;
+                       break;
+               case DELETE:
+                       result = 4;
+                       break;
+               case RUN:
+                       result = 5;
+                       break;
+               case SEARCH:
+                       result = 6;
+                       break;
+               default:
+                       result = 0;
+               }
+               
+               return result;
+       }
+
+       /**
+        * Factory method to create an ActionGroup from an action string -i.e., "CRUDL", "RL", "CRUL", etc.
+        * @param actionString
+        * @return
+        */
+       static public ActionGroup creatActionGroup(String actionString) {
+               ActionGroup result = null;
+               
+               Set<Character> actionCharSet = new HashSet<Character>();
+               Set<ActionType> actionTypeSet = new HashSet<ActionType>();
+               for (char c : actionString.toCharArray()) {
+                       switch (c) {
+                       case 'C':
+                               actionTypeSet.add(ActionType.CREATE);
+                               actionCharSet.add(c);
+                               break;
+                               
+                       case 'R':
+                               actionTypeSet.add(ActionType.READ);
+                               actionCharSet.add(c);
+                               break;
+                               
+                       case 'U':
+                               actionTypeSet.add(ActionType.UPDATE);
+                               actionCharSet.add(c);
+                               break;
+                               
+                       case 'D':
+                               actionTypeSet.add(ActionType.DELETE);
+                               actionCharSet.add(c);
+                               break;
+                               
+                       case 'I':
+                               actionTypeSet.add(ActionType.RUN);
+                               actionCharSet.add(c);
+                               break;
+                               
+                       case 'L':
+                               actionTypeSet.add(ActionType.SEARCH);
+                               actionCharSet.add(c);
+                               break;
+                               
+                       default:
+                               System.out.println(String.format("Unknown action character '%c'.", c));
+                       }
+               }
+               
+               if (actionTypeSet.size() > 0) {
+                       // sort for readability
+                       ArrayList<Character> actionCharList = new ArrayList<Character>(actionCharSet);
+                       Collections.sort(actionCharList, new Comparator<Character>() {
+                           @Override
+                           public int compare(Character c1, Character c2) {
+                               if (valueOf(c1) > valueOf(c2)) {
+                                       return 1;
+                               } else if (valueOf(c1) < valueOf(c2)) {
+                                       return -1;
+                               } else {
+                                       return 0;
+                               }
+                           }
+                       });
+                       
+                       // sort for readability
+                       ArrayList<ActionType> actionTypeList = new ArrayList<ActionType>(actionTypeSet);
+                       Collections.sort(actionTypeList, new Comparator<ActionType>() {
+                           @Override
+                           public int compare(ActionType a1, ActionType a2) {
+                               if (valueOf(a1) > valueOf(a2)) {
+                                       return 1;
+                               } else if (valueOf(a1) < valueOf(a2)) {
+                                       return -1;
+                               } else {
+                                       return 0;
+                               }
+                           }
+                       });
+                       
+                       result = new ActionGroup();
+                       result.name = toString(actionCharList);
+                       result.actions = actionTypeList.toArray(result.actions);
+               }
+               
+               logger.trace(String.format("Create new action group containing these actions name:'%s' actions:'%s'",
+                               result.name, toString(result.actions)));                        
+               
+               return result;
+       }
+       
+       public String getName() {
+               return name;
+       }
+       
+       public ActionType[] getActions() {
+               return this.actions;
+       }
+}
index 01c03ceb53f205e339f7cc4795b462b639614df6..014c460e69f2cbdbe259dd0d4facccc60ebc1e69 100644 (file)
@@ -68,32 +68,18 @@ public class AuthorizationCommon {
     // for READ-ONLY
     final public static String ACTIONGROUP_RL_NAME = "RL";
     final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};
-
-    
-       /*
-        * Inner class to deal with predefined ADMIN and READER action groupds
-        */
-       public class ActionGroup {
-               String name;
-               ActionType[] actions;
-               
-               public String getName() {
-                       return name;
-               }
-       }
        
        static ActionGroup ACTIONGROUP_CRUDL;
        static ActionGroup ACTIONGROUP_RL;
        
        // A static block to initialize the predefined action groups
        static {
-               AuthorizationCommon ac = new AuthorizationCommon();
                // For admin
-               ACTIONGROUP_CRUDL = ac.new ActionGroup();
+               ACTIONGROUP_CRUDL = new ActionGroup();
                ACTIONGROUP_CRUDL.name = ACTIONGROUP_CRUDL_NAME;
                ACTIONGROUP_CRUDL.actions = ACTIONSET_CRUDL;
                // For reader
-               ACTIONGROUP_RL = ac.new ActionGroup();
+               ACTIONGROUP_RL = new ActionGroup();
                ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME;
                ACTIONGROUP_RL.actions = ACTIONSET_RL;
 
index e9dd0574432c4773b54a7230cca3fa77f4f042ee..0b1a66a5bca571aad5ed1e33cc7135cd109eb920 100644 (file)
@@ -117,7 +117,8 @@ public class RemoteServiceContextImpl<IT, OT>
     /*
      * Returns the name of the service's acting repository.  Gets this from the tenant and service bindings files
      */
-    public String getRepositoryName() throws Exception {
+    @Override
+       public String getRepositoryName() throws Exception {
        String result = null;
        
        TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
@@ -181,10 +182,10 @@ public class RemoteServiceContextImpl<IT, OT>
      * @return
      * @throws Exception 
      */
-    public CollectionSpaceResource<IT, OT> getResource(ServiceContext ctx) throws Exception {
+    public CollectionSpaceResource<IT, OT> getResource(ServiceContext<?, ?> ctx) throws Exception {
        CollectionSpaceResource<IT, OT> result = null;
        
-       ResourceMap<IT, OT> resourceMap = ctx.getResourceMap();
+       ResourceMap resourceMap = ctx.getResourceMap();
        String resourceName = ctx.getClient().getServiceName();
        result = (CollectionSpaceResource<IT, OT>) resourceMap.get(resourceName);
        
@@ -208,7 +209,8 @@ public class RemoteServiceContextImpl<IT, OT>
     /**
      * @param map the map of service names to resource instances.
      */
-    public void setResourceMap(ResourceMap map) {
+    @Override
+       public void setResourceMap(ResourceMap map) {
        this.resourceMap = map;
     }
 
@@ -218,7 +220,7 @@ public class RemoteServiceContextImpl<IT, OT>
      * @see org.collectionspace.services.common.context.RemoteServiceContext#getLocalContext(java.lang.String)
      */
     @Override
-    public ServiceContext getLocalContext(String localContextClassName) throws Exception {
+    public ServiceContext<IT, OT> getLocalContext(String localContextClassName) throws Exception {
         ClassLoader cloader = Thread.currentThread().getContextClassLoader();
         Class<?> ctxClass = cloader.loadClass(localContextClassName);
         if (!ServiceContext.class.isAssignableFrom(ctxClass)) {
@@ -226,8 +228,8 @@ public class RemoteServiceContextImpl<IT, OT>
                     + " implementation of " + ServiceContext.class.getName());
         }
 
-        Constructor ctor = ctxClass.getConstructor(java.lang.String.class);
-        ServiceContext ctx = (ServiceContext) ctor.newInstance(getServiceName());
+        Constructor<?> ctor = ctxClass.getConstructor(java.lang.String.class);
+        ServiceContext<IT, OT> ctx = (ServiceContext<IT, OT>) ctor.newInstance(getServiceName());
         return ctx;
     }
 
index efd24294d494d2e066e30a54c6089be3961aa925..f0863c139cd0c58ede2148d1712055134cb6f09a 100644 (file)
@@ -24,6 +24,9 @@ package org.collectionspace.services.common.invocable;
 
 import org.collectionspace.services.common.invocable.InvocationContext;
 import java.util.List;
+
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.api.Tools;
 import org.collectionspace.services.common.context.ServiceContext;
 
@@ -64,11 +67,13 @@ public interface Invocable {
             return (Tools.notBlank(message)) ? message : "No error message provided";  
         }
     }
+    
     public String INVOCATION_MODE_SINGLE = "single";
     public String INVOCATION_MODE_LIST = "list";
     public String INVOCATION_MODE_GROUP = "group";
     public String INVOCATION_MODE_NO_CONTEXT = "nocontext";
     //public String INVOCATION_MODE_QUERY = "query"; NYI
+    
     public final int STATUS_ERROR = -1;
     public final int STATUS_UNSTARTED = 0;
     public final int STATUS_MIN_PROGRESS = 1;
@@ -113,9 +118,9 @@ public interface Invocable {
     /*
      * Save a handle to the JAX-RS related service context
      */
-       void setServiceContext(ServiceContext context);
+       void setServiceContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> context);
 
-       ServiceContext getServiceContext();
+       ServiceContext<PoxPayloadIn, PoxPayloadOut> getServiceContext();
 
        InvocationContext getInvocationContext();
 }
similarity index 99%
rename from services/batch/service/src/main/java/org/collectionspace/services/batch/UriInfoImpl.java
rename to services/common/src/main/java/org/collectionspace/services/common/query/UriInfoImpl.java
index 237c156e4a06409bbdef8b325b952c2b13d120df..90e2be1a188ffe67b8baecfe3125842d34234271 100644 (file)
@@ -1,4 +1,4 @@
-package org.collectionspace.services.batch;
+package org.collectionspace.services.common.query;
 
 import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.jboss.resteasy.specimpl.PathSegmentImpl;
index f1958f9ba4f053db539b1e3dc68bc180d7bf2612..30182024f70a3f6c85ada472b0162d5b1df54e92 100644 (file)
@@ -159,7 +159,7 @@ public class SecurityInterceptor implements PreProcessInterceptor, PostProcessIn
                        checkActive();
                        
                        //
-                       // All active users are allowed to the *their* (we enforce this) current list of permissions.  If this is not
+                       // All active users are allowed to see the *their* (we enforce this) current list of permissions.  If this is not
                        // the request, then we'll do a full AuthZ check.
                        //
                        if (resName.equalsIgnoreCase(ACCOUNT_PERMISSIONS) != true) { //see comment immediately above
index 730a7d2cb678864338518b1e860866f8b85c36ae..353bbeec48425ccc8ddb2042139c16fcc566d7fd 100644 (file)
@@ -33,7 +33,11 @@ import org.collectionspace.services.common.ServiceException;
  */
 public class UnauthorizedException extends ServiceException {
 
-    final public static int HTTP_CODE = 401;
+    /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+       final public static int HTTP_CODE = 401;
 
     /**
      * Creates a new instance of <code>UnauthorizedException</code> without detail message.
index 9ce64108e95735a55373e234732157b52b766a82..c2d77bd06665dbcd826af5a629a73a2276705356 100644 (file)
@@ -35,7 +35,8 @@ public abstract class JpaDocumentHandler<T, TL, WT, WLT>
      * @return the tL
      * @throws Exception the exception
      */
-    public TL extractPagingInfo(TL theCommonList, DocumentWrapper<WLT> wrapDoc)
+    @Override
+       public TL extractPagingInfo(TL theCommonList, DocumentWrapper<WLT> wrapDoc)
             throws Exception {
         AbstractCommonList commonList = (AbstractCommonList) theCommonList;
 
@@ -54,7 +55,8 @@ public abstract class JpaDocumentHandler<T, TL, WT, WLT>
         return (TL) commonList;
     }
     
-    public Lifecycle getLifecycle(String docTypeName) {
+    @Override
+       public Lifecycle getLifecycle(String docTypeName) {
        Lifecycle result = new Lifecycle();
        result.setName("Life cycles are not supported by the JPA-based services.");
        return result; // NOTE: As of 3/2012, none of the JPA-based services support a life cycle type.
index 4baecf27325401321973aeb2b6356afeffda2a7f..68c64bbcd5fff32ad659d0a6d3e0c62adf583d87 100644 (file)
@@ -388,6 +388,7 @@ public abstract class   RemoteDocumentModelHandlerImpl<T, TL>
         Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
 
         //iterate over parts received and fill those parts
+        boolean werePartsFilled = false;
         List<PayloadInputPart> inputParts = input.getParts();
         for (PayloadInputPart part : inputParts) {
 
@@ -404,6 +405,14 @@ public abstract class   RemoteDocumentModelHandlerImpl<T, TL>
                 continue;
             }
             fillPart(part, docModel, partMeta, action, ctx);
+            werePartsFilled = true;
+        }
+        
+        if (werePartsFilled == false) {
+               String msg = String.format("%s request failed because there were no XML payload parts in the request.", 
+                               action.toString());
+               logger.error(msg);
+               throw new BadRequestException(msg);
         }
     }
 
index 1665c8ab2b64440afc31f71848631a3af1f9c4de..b4f2347222fb9110c82327628718b5e6205a4e58 100644 (file)
@@ -8,45 +8,38 @@
     $LastChangedRevision: 2316 $
     $LastChangedDate: 2010-06-02 16:03:51 -0700 (Wed, 02 Jun 2010) $
 -->
-<xs:schema 
-               xmlns:xs="http://www.w3.org/2001/XMLSchema" 
-               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
-               jaxb:version="1.0" elementFormDefault="unqualified" 
-               xmlns:ns="http://collectionspace.org/services/common/invocable" 
-               xmlns="http://collectionspace.org/services/common/invocable" 
-               targetNamespace="http://collectionspace.org/services/common/invocable" version="0.1">
-       
-       <xs:element name="invocationContext">
-               <xs:complexType>
-                       <xs:sequence>
-                               <xs:element name="mode" type="xs:string"/>
-                               <xs:element name="updateCoreValues" type="xs:string"/>                          
-                               <xs:element name="docType" type="xs:string"/>
-                               <xs:element name="singleCSID" type="xs:string"/>
-                               <xs:element name="groupCSID" type="xs:string"/>
-                               <xs:element name="listCSIDs">
-                                       <xs:complexType>
-                                               <xs:sequence>
-                                                       <xs:element name="csid" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
-                                               </xs:sequence>
-                                       </xs:complexType>
-                               </xs:element>
-                               <xs:element name="params">
-                                       <xs:complexType>
-                                               <xs:sequence>
-              <xs:element name="param" minOccurs="0" maxOccurs="unbounded">
-                                                               <xs:complexType>
-                                                                       <xs:sequence>
-                                                                               <xs:element name="key" type="xs:string" minOccurs="0" maxOccurs="1"/>
-                                                                               <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="1"/>
-                                                                       </xs:sequence>
-                                                               </xs:complexType>
-                                                       </xs:element>
-                                               </xs:sequence>
-                                       </xs:complexType>
-                               </xs:element>
-                       </xs:sequence>
-               </xs:complexType>
-       </xs:element>
-</xs:schema>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="1.0" elementFormDefault="unqualified" xmlns:ns="http://collectionspace.org/services/common/invocable" xmlns="http://collectionspace.org/services/common/invocable" targetNamespace="http://collectionspace.org/services/common/invocable" version="0.1">
 
+    <xs:element name="invocationContext">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="mode" type="xs:string"></xs:element>
+                <xs:element name="updateCoreValues" type="xs:string"></xs:element>
+                <xs:element name="docType" type="xs:string"></xs:element>
+                <xs:element name="singleCSID" type="xs:string"></xs:element>
+                <xs:element name="groupCSID" type="xs:string"></xs:element>
+                <xs:element name="listCSIDs">
+                    <xs:complexType>
+                        <xs:sequence>
+                            <xs:element name="csid" type="xs:string" minOccurs="0" maxOccurs="unbounded"></xs:element>
+                        </xs:sequence>
+                    </xs:complexType>
+                </xs:element>
+                <xs:element name="params">
+                    <xs:complexType>
+                        <xs:sequence>
+                            <xs:element name="param" minOccurs="0" maxOccurs="unbounded">
+                                <xs:complexType>
+                                    <xs:sequence>
+                                        <xs:element name="key" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
+                                        <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
+                                    </xs:sequence>
+                                </xs:complexType>
+                            </xs:element>
+                        </xs:sequence>
+                    </xs:complexType>
+                </xs:element>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>