]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5950: Allow importing of documents into repository domains other than the...
authorAron Roberts <aron@socrates.berkeley.edu>
Fri, 19 Jul 2013 22:54:04 +0000 (15:54 -0700)
committerAron Roberts <aron@socrates.berkeley.edu>
Fri, 19 Jul 2013 22:54:04 +0000 (15:54 -0700)
services/IntegrationTests/src/test/resources/test-data/xmlreplay/imports/imports.xml
services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml
services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto.xml
services/imports/service/src/main/java/org/collectionspace/services/imports/ImportsResource.java
services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/ImportCommand.java

index 81187b2c8026110fbe4c4f303d983bc71c4c0b99..d242b11f6e2945403be3cd903a411a2d9b4835b1 100644 (file)
@@ -3,6 +3,7 @@
     <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="admin@lifesci.collectionspace.org">YWRtaW5AbGlmZXNjaS5jb2xsZWN0aW9uc3BhY2Uub3JnOkFkbWluaXN0cmF0b3I=</auth>
     </auths>
     
     <!-- ================================================================================ -->
@@ -25,7 +26,7 @@
             <method>DELETE</method>
             <uri>/cspace-services/objectexit/${importObjectExit.got("//csid")}</uri>
         </test>
-                
+                        
         <!--
             Import a single ObjectExit record, at least one of whose fields
             contains a set of special characters defined in the
             collectionspace_core part's refName field.
             
             This also tests proper handling of entity-encoded ampersands
-            contained within display name values in refNames. 9See CSPACE-5940.)
+            contained within display name values in refNames. (See CSPACE-5940.)
         -->
-<test ID="importLocationItemWithVarExpansion">
+        <test ID="importLocationItemWithVarExpansion">
             <expectedCodes>200</expectedCodes>
             <method>POST</method>
             <uri>/cspace-services/imports</uri>
 
     </testGroup>
     
+    <!--
+      By default, the demonstration 'lifesci' tenant is configured to use a separate,
+      rather than a shared, Nuxeo repository domain.
+
+      The test(s) in this test group authenticate as a user in the lifesci tenant and
+      thus verify that imports also work with separate, per-tenant repository domains.
+    -->
+    <testGroup ID="importsSeparateRepoTestGroup" autoDeletePOSTS="false">
+
+        <!-- Import a single ObjectExit record into a separate repo domain -->
+        <test ID="importObjectExitSeparateRepo" auth="admin@lifesci.collectionspace.org">
+            <expectedCodes>200</expectedCodes>
+            <method>POST</method>
+            <uri>/cspace-services/imports</uri>
+            <filename>imports/import-objectexit.xml</filename>
+            <response>
+                <expected level="TEXT" />
+                <filename>imports/res/import-objectexit.res.xml</filename>
+            </response>
+        </test>
+        <test ID="deleteObjectExitSeparateRepo" auth="admin@lifesci.collectionspace.org">
+            <expectedCodes>200</expectedCodes>
+            <method>DELETE</method>
+            <uri>/cspace-services/objectexit/${importObjectExitSeparateRepo.got("//csid")}</uri>
+        </test>
+
+    </testGroup>
+
     <!--
       Temporary test group for testing changes or additions to this control file.
       To use:
index fa1ee99d0b48e793e0e26ae9e9e6eb3e2877d64e..20c9c280ab9f292f75b9118b21135733031b9e08 100644 (file)
     <run controlFile="authrefs/authrefsSimple.xml" testGroup="AuthRefsSimple" />\r
     <run controlFile="authrefs/authrefsComplex.xml" testGroup="AuthRefsComplex" />\r
     <run controlFile="authority/authority.xml" testGroup="TestAuthoritiesMultiVocabSearch" />\r
-    <run controlFile="imports/imports.xml" testGroup="importsTestGroup" />\r
     \r
+    <run controlFile="imports/imports.xml" testGroup="importsTestGroup" />\r
+    <run controlFile="imports/imports.xml" testGroup="importsSeparateRepoTestGroup" />\r
+\r
     <run controlFile="collectionobject/collectionobject-hierarchy-csid.xml" testGroup="CreateUpdateReadStructuredObjects" />\r
     <run controlFile="collectionobject/collectionobject-hierarchy-refname.xml" testGroup="CreateUpdateReadStructuredObjects" />\r
     <run controlFile="collectionobject/collectionobject-displayname-update.xml" testGroup="DisplayNameChangesReflectedInRefNames" />\r
index 1fd1088a7efdb7a8643c8d72637f575aada5cca9..a8bc53a2bed6eb50b499da88784408e407c29098 100644 (file)
     <!-- begin prototype collectionspace.org tenant meta-data -->
     
     <tenant:tenantBinding id="-1" name="prototype.collectionspace.org" displayName="CollectionSpace Services Bindings Prototype" version="0.1">
+        <!--
+           Guide to the attributes of the repositoryDomain element, below:
+           name=CollectionSpace domain
+           repositoryName=Nuxeo repository name ('default' if not specified)
+             (for configuration see e.g. services/3rdparty/nuxeo/nuxeo-server/{version}/config/default-repo-config.xml)
+           storageName=Nuxeo domain name within that repository
+             (http://doc.nuxeo.com/display/USERDOC/Document+Management+concepts)
+           repositoryClient=repository client name
+        -->
         <tenant:repositoryDomain name="default-domain" storageName="prototype-domain" repositoryClient="nuxeo-java" />
         <tenant:properties>
             <types:item xmlns:types="http://collectionspace.org/services/config/types">
index 759e25e9d46665f7475af259eff525e9ec2115d8..c167de8d552a65ffe2a35f92972a4ca1e53c7393 100644 (file)
@@ -84,35 +84,63 @@ public class ImportsResource extends AbstractCollectionSpaceResourceImpl<PoxPayl
 
        public static final String SERVICE_NAME = "imports";
        public static final String SERVICE_PATH = "/" + SERVICE_NAME;
-       private static final int DEFAULT_TX_TIMOUT = 600; // timeout period in seconds
+        private static String NUXEO_SPACES_PATH_DELIMITER = "/";
+
+       private static final int DEFAULT_TX_TIMEOUT = 600; // timeout period in seconds
 
        /*
         * ASSUMPTION: All Nuxeo services of a given tenancy store their stuff in
-        * the same repository domain under the "workspaces" directory.
+        * a repository domain, under a "Workspaces" space within that domain.
+         * (See http://doc.nuxeo.com/display/USERDOC/Document+Management+concepts)
         * 
-        * Using the tenant ID of the currently authenticated user, this method
-        * returns the repository domain name of the current tenancy.
+        * Using the tenant associated with the currently authenticated user, this
+        * method returns a delimited path to the Workspaces space for that tenancy.
         */
-       private static String getWorkspaces() throws ConfigurationException {
+       private static String getWorkspacesPath() throws ConfigurationException {
                String result = null;
-
-               TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance()
-                               .getTenantBindingConfigReader();
-               TenantBindingType tenantBinding = tReader.getTenantBinding(AuthN.get()
-                               .getCurrentTenantId());
-               List<RepositoryDomainType> repositoryDomainList = tenantBinding
-                               .getRepositoryDomain();
+               List<RepositoryDomainType> repositoryDomainList = getRepositoryDomainList();
                if (repositoryDomainList.size() == 1) {
                        String domainName = repositoryDomainList.get(0).getStorageName()
                                        .trim();
-                       result = "/" + domainName + "/" + NuxeoUtils.Workspaces;
+                       result = NUXEO_SPACES_PATH_DELIMITER + domainName 
+                                + NUXEO_SPACES_PATH_DELIMITER + NuxeoUtils.Workspaces;
                } else {
+                        // Currently, the Imports service places all documents
+                        // imported via a single request, into the same repository
+                        // and repository domain. It doesn't currently have the
+                        // ability to assign individual documents, depending on
+                        // their associated service, to different repositories
+                        // and/or repository domains. If a tenant is configured with
+                        // more than one repository domain, the import will fail here.
                        throw new ConfigurationException(
                                        "Tenant bindings contains 0 or more than 1 repository domains.");
                }
-
                return result;
        }
+        
+        private static String getRepoName() throws ConfigurationException {
+               String repoName = null;
+               List<RepositoryDomainType> repositoryDomainList = getRepositoryDomainList();
+               if (repositoryDomainList.size() == 1) {
+                   repoName = repositoryDomainList.get(0).getRepositoryName().trim();
+               } else {
+                        // See relevant comments in getWorkspacesPath()
+                       throw new ConfigurationException(
+                                       "Tenant bindings contains 0 or more than 1 repository domains.");
+               }
+               return repoName;
+       }
+        
+        private static List<RepositoryDomainType> getRepositoryDomainList() throws ConfigurationException {
+            TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance()
+                               .getTenantBindingConfigReader();
+               TenantBindingType tenantBinding = tReader.getTenantBinding(AuthN.get()
+                               .getCurrentTenantId());
+               List<RepositoryDomainType> repositoryDomainList = tenantBinding
+                               .getRepositoryDomain();
+                return repositoryDomainList;
+        }
+        
 
        @Override
        public String getServiceName() {
@@ -162,7 +190,7 @@ public class ImportsResource extends AbstractCollectionSpaceResourceImpl<PoxPayl
        // }
 
        private int getTimeoutParam(UriInfo ui) {
-               int result = DEFAULT_TX_TIMOUT;
+               int result = DEFAULT_TX_TIMEOUT;
 
                MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
                if (queryParams != null) {
@@ -228,11 +256,12 @@ public class ImportsResource extends AbstractCollectionSpaceResourceImpl<PoxPayl
                // directory that has the expanded request.
                ImportCommand importCommand = new ImportCommand();
                // String destWorkspaces = "/default-domain/workspaces";
-               String destWorkspaces = getWorkspaces();
+               String workspacesPath = getWorkspacesPath();
+                String repoName = getRepoName();
                String result = "";
                try {
                        String report = "NORESULTS";
-                       report = importCommand.run(outputDir, destWorkspaces, timeOut);
+                       report = importCommand.run(outputDir, repoName, workspacesPath, timeOut);
                        result = "<?xml version=\"1.0\"?><import><msg>SUCCESS</msg>"
                                        + report + "</import>";
                } catch (Exception e) {
@@ -258,11 +287,12 @@ public class ImportsResource extends AbstractCollectionSpaceResourceImpl<PoxPayl
                // directory that has the expanded request.
                ImportCommand importCommand = new ImportCommand();
                // String destWorkspaces = "/default-domain/workspaces";
-               String destWorkspaces = getWorkspaces();
+               String workspacesPath = getWorkspacesPath();
+                String repoName = getRepoName();
                String result = "";
                try {
                        String report = "NORESULTS";
-                       report = importCommand.run(outputDir, destWorkspaces, timeOut);
+                       report = importCommand.run(outputDir, repoName, workspacesPath, timeOut);
                        result = "<?xml version=\"1.0\"?><import><msg>SUCCESS</msg>"
                                        + report + "</import>";
                } catch (Exception e) {
index e6aeb2fa5a7aebeae084acf24f7f07dbf41478be..53d39f0f93e947ffc4eebf0114767289d1e9f85a 100644 (file)
@@ -5,6 +5,7 @@ import java.util.Calendar;
 import java.util.HashMap;\r
 import java.util.Map;\r
 import java.util.TreeSet;\r
+import org.collectionspace.services.common.api.Tools;\r
 import org.collectionspace.services.nuxeo.client.java.NuxeoClientEmbedded;\r
 import org.collectionspace.services.nuxeo.client.java.NuxeoConnectorEmbedded;\r
 import org.nuxeo.ecm.core.api.DocumentModel;\r
@@ -22,45 +23,46 @@ import org.slf4j.LoggerFactory;
 \r
 // based loosely on package org.nuxeo.ecm.shell.commands.io.ImportCommand;\r
 public class ImportCommand {\r
-    \r
+\r
     private final Logger logger = LoggerFactory.getLogger(ImportCommand.class);\r
 \r
-    public String run(String src, String dest, int timeOut) throws Exception {\r
+    public String run(String src, String repoName, String workspacesPath, int timeOut) throws Exception {\r
         File file = new File(src);\r
         ///cspace way of configuring client and auth:\r
         NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();\r
-        RepositoryInstance  repoSession = client.openRepository(timeOut);\r
+        RepositoryInstance repoSession = null;\r
         try {\r
+            repoSession = client.openRepository(repoName, timeOut);\r
             if (logger.isDebugEnabled()) {\r
                 String msg = String.format("Start of import is Local time: %tT", Calendar.getInstance());\r
                 logger.debug(msg);\r
             }\r
-            return importTree(repoSession, file, dest);\r
+            return importTree(repoSession, file, workspacesPath);\r
         } catch (Exception e) {\r
             throw e;\r
         } finally {\r
             if (logger.isDebugEnabled()) {\r
-               String msg = String.format("End of import is Local time: %tT", Calendar.getInstance());\r
-               logger.debug(msg);\r
+                String msg = String.format("End of import is Local time: %tT", Calendar.getInstance());\r
+                logger.debug(msg);\r
             }\r
             client.releaseRepository(repoSession);\r
         }\r
     }\r
 \r
     String importTree(RepositoryInstance repoSession, File file, String toPath) throws Exception {\r
-       Exception failed = null;\r
+        Exception failed = null;\r
         DocumentReader reader = null;\r
         DocumentWriter writer = null;\r
         DocumentModel docModel = null;\r
         DocumentRef keyDocRef, valueDocRef;\r
         String docType;\r
         StringBuffer dump = new StringBuffer();\r
-        Map<String,Integer> recordsImportedForDocType = new HashMap<String,Integer>();\r
+        Map<String, Integer> recordsImportedForDocType = new HashMap<String, Integer>();\r
         Integer numRecordsImportedForDocType = new Integer(0);\r
         int totalRecordsImported = 0;\r
         try {\r
             if (logger.isInfoEnabled()) {\r
-                logger.info("importTree reading file: "+file+(file!=null ? " exists? "+file.exists() : " file param is null"));\r
+                logger.info("importTree reading file: " + file + (file != null ? " exists? " + file.exists() : " file param is null"));\r
             }\r
             reader = new LoggedXMLDirectoryReader(file);  //our overload of XMLDirectoryReader.\r
             writer = new DocumentModelWriter(repoSession, toPath, 10);\r
@@ -69,9 +71,9 @@ public class ImportCommand {
             pipe.setReader(reader);\r
             pipe.setWriter(writer);\r
             DocumentTranslationMap dtm = pipe.run();\r
-            Map<DocumentRef,DocumentRef> documentRefs = dtm.getDocRefMap(); // FIXME: Should be checking for null here!\r
+            Map<DocumentRef, DocumentRef> documentRefs = dtm.getDocRefMap(); // FIXME: Should be checking for null here!\r
             dump.append("<importedRecords>");\r
-            for (Map.Entry entry: documentRefs.entrySet()) {\r
+            for (Map.Entry entry : documentRefs.entrySet()) {\r
                 keyDocRef = (DocumentRef) entry.getKey();\r
                 valueDocRef = (DocumentRef) entry.getValue();\r
                 if (keyDocRef == null || valueDocRef == null) {\r
@@ -80,8 +82,8 @@ public class ImportCommand {
                 dump.append("<importedRecord>");\r
                 docModel = repoSession.getDocument(valueDocRef);\r
                 docType = docModel.getDocumentType().getName();\r
-                dump.append("<doctype>"+docType+"</doctype>");\r
-                dump.append("<csid>"+keyDocRef.toString()+"</csid>");\r
+                dump.append("<doctype>" + docType + "</doctype>");\r
+                dump.append("<csid>" + keyDocRef.toString() + "</csid>");\r
                 dump.append("</importedRecord>");\r
                 if (recordsImportedForDocType.containsKey(docType)) {\r
                     numRecordsImportedForDocType = (Integer) recordsImportedForDocType.get(docType);\r
@@ -94,32 +96,32 @@ public class ImportCommand {
             }\r
             dump.append("</importedRecords>");\r
         } catch (Exception e) {\r
-               failed = e;\r
+            failed = e;\r
             throw failed;\r
         } finally {\r
-               String status = failed == null ? "Success" : "Failed";\r
-               dump.append("<status>" + status + "</status>");\r
-            dump.append("<totalRecordsImported>"+totalRecordsImported+"</totalRecordsImported>");\r
+            String status = failed == null ? "Success" : "Failed";\r
+            dump.append("<status>" + status + "</status>");\r
+            dump.append("<totalRecordsImported>" + totalRecordsImported + "</totalRecordsImported>");\r
             dump.append("<numRecordsImportedByDocType>");\r
             TreeSet<String> keys = new TreeSet<String>(recordsImportedForDocType.keySet());\r
             for (String key : keys) {\r
                 dump.append("<numRecordsImported>");\r
-                dump.append("<docType>"+key+"</docType>");\r
-                dump.append("<numRecords>"+recordsImportedForDocType.get(key).intValue()+"</numRecords>");\r
+                dump.append("<docType>" + key + "</docType>");\r
+                dump.append("<numRecords>" + recordsImportedForDocType.get(key).intValue() + "</numRecords>");\r
                 dump.append("</numRecordsImported>");\r
             }\r
             dump.append("</numRecordsImportedByDocType>");\r
             if (reader != null) {\r
-                dump.append("<report>"+(((LoggedXMLDirectoryReader)reader).report())+"</report>");\r
+                dump.append("<report>" + (((LoggedXMLDirectoryReader) reader).report()) + "</report>");\r
                 reader.close();\r
             }\r
             if (writer != null) {\r
                 writer.close();\r
             }\r
-            \r
+\r
             if (failed != null) {\r
-               String msg = "The Import service encountered an exception: " + failed.getLocalizedMessage();\r
-               logger.error(msg, failed);\r
+                String msg = "The Import service encountered an exception: " + failed.getLocalizedMessage();\r
+                logger.error(msg, failed);\r
             }\r
         }\r
         return dump.toString();\r