<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>
<!-- ================================================================================ -->
<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:
<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
<!-- 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">
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() {
// }
private int getTimeoutParam(UriInfo ui) {
- int result = DEFAULT_TX_TIMOUT;
+ int result = DEFAULT_TX_TIMEOUT;
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
if (queryParams != null) {
// 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) {
// 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) {
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
\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
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
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
}\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