--- /dev/null
+package org.collectionspace.services.common;\r
+\r
+public class ConfigurationException extends ServiceException {\r
+ /**\r
+ * \r
+ */\r
+ private static final long serialVersionUID = -6399176494104282779L;\r
+ \r
+ final public static int HTTP_CODE = 500;\r
+\r
+ /**\r
+ * Creates a new instance of <code>BadRequestException</code> without detail message.\r
+ */\r
+ public ConfigurationException() {\r
+ super(HTTP_CODE);\r
+ }\r
+\r
+ /**\r
+ * Constructs an instance of <code>BadRequestException</code> with the specified detail message.\r
+ * @param msg the detail message.\r
+ */\r
+ public ConfigurationException(String msg) {\r
+ super(msg);\r
+ setErrorCode(HTTP_CODE);\r
+ }\r
+\r
+ /**\r
+ * Constructs a new exception with the specified detail message and\r
+ * cause. <p>Note that the detail message associated with\r
+ * <code>cause</code> is <i>not</i> automatically incorporated in\r
+ * this exception's detail message.\r
+ *\r
+ * @param message the detail message (which is saved for later retrieval\r
+ * by the {@link #getMessage()} method).\r
+ * @param cause the cause (which is saved for later retrieval by the\r
+ * {@link #getCause()} method). (A <tt>null</tt> value is\r
+ * permitted, and indicates that the cause is nonexistent or\r
+ * unknown.)\r
+ * @since 1.4\r
+ */\r
+ public ConfigurationException(String message, Throwable cause) {\r
+ super(message, cause);\r
+ setErrorCode(HTTP_CODE);\r
+ }\r
+ \r
+ /**\r
+ * Constructs a new exception with the specified cause and a detail\r
+ * message of <tt>(cause==null ? null : cause.toString())</tt> (which\r
+ * typically contains the class and detail message of <tt>cause</tt>).\r
+ * This constructor is useful for exceptions that are little more than\r
+ * wrappers for other throwables (for example, {@link\r
+ * java.security.PrivilegedActionException}).\r
+ *\r
+ * @param cause the cause (which is saved for later retrieval by the\r
+ * {@link #getCause()} method). (A <tt>null</tt> value is\r
+ * permitted, and indicates that the cause is nonexistent or\r
+ * unknown.)\r
+ * @since 1.4\r
+ */\r
+ public ConfigurationException(Throwable cause) {\r
+ super(cause);\r
+ setErrorCode(HTTP_CODE);\r
+ }\r
+ \r
+}\r
public String getTenantQualifiedDoctype(String docType) {
// If they have not overridden the setting, use the type of the service
// object.
- String result = docType + ServiceContext.TENANT_SUFFIX + this.getTenantId();
+ String result = ServiceBindingUtils.getTenantQualifiedDocType(this.getTenantId(), docType);
return result;
}
public static final String SERVICE_TYPE_OBJECT = "object";\r
public static final String SERVICE_TYPE_PROCEDURE = "procedure";\r
\r
+ public static String getTenantQualifiedDocType(String tenantId, String docType) {\r
+ String result = docType + ServiceContext.TENANT_SUFFIX + tenantId;\r
+ return result;\r
+ }\r
+ \r
// TODO consider building up a hashTable of the properties for each\r
// service binding. There will be generic properties, as well as\r
// properties on each part. Could build up a key from tenant id, \r
repoSession = getRepositorySession();
DocumentRef parentDocRef = new PathRef(
"/" + domainName
- + "/" + "workspaces");
+ + "/" + NuxeoUtils.WORKSPACES);
DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
workspaceName, "Workspace");
repoSession = getRepositorySession();
DocumentRef docRef = new PathRef(
"/" + tenantDomain
- + "/" + "workspaces"
+ + "/" + NuxeoUtils.WORKSPACES
+ "/" + workspaceName);
DocumentModel workspace = repoSession.getDocument(docRef);
workspaceId = workspace.getId();
import org.collectionspace.services.client.IQueryManager;
import org.collectionspace.services.client.PoxPayloadIn;
import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.common.context.ServiceBindingUtils;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.BadRequestException;
import org.collectionspace.services.common.document.DocumentException;
// Base document type in Nuxeo is "Document"
//
public static final String BASE_DOCUMENT_TYPE = "Document";
+ public static final String WORKSPACES = "workspaces";
// Regular expressions pattern for identifying valid ORDER BY clauses.
// FIXME: Currently supports only USASCII word characters in field names.
*/
public static DocumentRef createPathRef(ServiceContext ctx, String id) {
return new PathRef("/" + ctx.getRepositoryDomainStorageName() +
- "/" + "workspaces" +
+ "/" + WORKSPACES +
"/" + ctx.getRepositoryWorkspaceName() +
"/" + id);
}
return result;
}
+ public static String getTenantQualifiedDocType(String tenantId, String docType) throws Exception {
+ String result = docType;
+
+ String tenantQualifiedDocType = ServiceBindingUtils.getTenantQualifiedDocType(tenantId, docType);
+
+ if (docTypeExists(tenantQualifiedDocType) == true) {
+ result = tenantQualifiedDocType;
+ }
+
+ return result;
+ }
+
+
public static String getTenantQualifiedDocType(ServiceContext ctx, String docType) throws Exception {
String result = docType;
<target name="deploy" depends="install"
description="deploy imports service">
<ant antfile="3rdparty/build.xml" target="deploy" inheritall="false"/>
- <copy todir="${jboss.server.cspace}/cspace/config/services/resources/templates">
+ <!-- REM - This logic should be pushed down into the "service" module -->
+ <copy todir="${jboss.server.cspace}/cspace/config/services/resources/templates">
<fileset dir="${basedir}/service/src/main/resources/templates"/>
</copy>
</target>
<artifactId>org.collectionspace.services.common</artifactId>
<version>${project.version}</version>
</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.imports.jaxb</artifactId>
*/
package org.collectionspace.services.imports;
+import org.collectionspace.services.common.ConfigurationException;
import org.collectionspace.services.common.FileUtils;
import org.collectionspace.services.common.ResourceBase;
import org.collectionspace.services.common.ServiceMain;
import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.api.ZipTools;
import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
+import org.collectionspace.services.common.tenant.RepositoryDomainType;
+import org.collectionspace.services.common.tenant.TenantBindingType;
+import org.collectionspace.authentication.AuthN;
+
import org.collectionspace.services.imports.nuxeo.ImportCommand;
+import org.collectionspace.services.nuxeo.util.NuxeoUtils;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.xml.sax.InputSource;
public static final String SERVICE_PATH = "imports";
public static final String SERVICE_NAME = "imports";
+ /*
+ * ASSUMPTION: All Nuxeo services of a given tenancy store their stuff in the same repository domain under
+ * the "workspaces" directory.
+ *
+ * Using the tenant ID of the currently authenticated user, this method returns the repository domain name of the
+ * current tenancy.
+ */
+ private static String getWorkspaces() throws ConfigurationException {
+ String result = null;
+
+ TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance().getTenantBindingConfigReader();
+ TenantBindingType tenantBinding = tReader.getTenantBinding(AuthN.get().getCurrentTenantId());
+ List<RepositoryDomainType> repositoryDomainList = tenantBinding.getRepositoryDomain();
+ if (repositoryDomainList.size() == 1) {
+ String domainName = repositoryDomainList.get(0).getStorageName().trim();
+ result = "/" + domainName + "/" + NuxeoUtils.WORKSPACES;
+ } else {
+ throw new ConfigurationException("Tenant bindings contains 0 or more than 1 repository domains.");
+ }
+
+ return result;
+ }
+
@Override
public String getServiceName(){
return SERVICE_NAME;
}
public static String createFromInputSource(InputSource inputSource) throws Exception {
+ String tenantId = AuthN.get().getCurrentTenantId();
// We must expand the request and wrap it with all kinds of Nuxeo baggage, which expandXmlPayloadToDir knows how to do.
String outputDir = FileTools.createTmpDir("imports-").getCanonicalPath();
File outpd = new File(outputDir);
outpd.mkdirs();
- expandXmlPayloadToDir(inputSource, getTemplateDir(), outpd.getCanonicalPath());
+ expandXmlPayloadToDir(tenantId, inputSource, getTemplateDir(), outpd.getCanonicalPath());
// Next, call the nuxeo import service, pointing it to our local directory that has the expanded request.
ImportCommand importCommand = new ImportCommand();
- String destWorkspaces = "/default-domain/workspaces";
+// String destWorkspaces = "/default-domain/workspaces";
+ String destWorkspaces = getWorkspaces();
String report = "NORESULTS";
try {
report = importCommand.run(outputDir, destWorkspaces);
}
public static String createFromFilename(String filename) throws Exception {
+ String tenantId = AuthN.get().getCurrentTenantId();
// We must expand the request and wrap it with all kinds of Nuxeo baggage, which expandXmlPayloadToDir knows how to do.
String outputDir = FileTools.createTmpDir("imports-").getCanonicalPath();
File outpd = new File(outputDir);
outpd.mkdirs();
- expandXmlPayloadToDir(filename, getTemplateDir(), outpd.getCanonicalPath());
+ expandXmlPayloadToDir(tenantId, filename, getTemplateDir(), outpd.getCanonicalPath());
// Next, call the nuxeo import service, pointing it to our local directory that has the expanded request.
ImportCommand importCommand = new ImportCommand();
- String destWorkspaces = "/default-domain/workspaces";
+// String destWorkspaces = "/default-domain/workspaces";
+ String destWorkspaces = getWorkspaces();
String report = importCommand.run(outputDir, destWorkspaces);
String result = "<?xml ?><import><msg>SUCCESS</msg><report></report>"+report+"</import>";
return result;
return requestFilename;
}
- public static void expandXmlPayloadToDir(String inputFilename, String templateDir, String outputDir) throws Exception {
+ public static void expandXmlPayloadToDir(String tenantId, String inputFilename, String templateDir, String outputDir) throws Exception {
System.out.println("############## TEMPLATE_DIR: "+templateDir);
System.out.println("############## OUTPUT_DIR:"+outputDir);
File file = new File(inputFilename);
FileInputStream is = new FileInputStream(file);
InputSource inputSource = new InputSource(is);
- TemplateExpander.expandInputSource(templateDir, outputDir, inputSource, "/imports/import");
+ TemplateExpander.expandInputSource(tenantId, templateDir, outputDir, inputSource, "/imports/import");
}
/** This method may be called statically from outside this class; there is a test call in
* @param templateDir The local directory where templates are to be found at runtime.
* @param outputDir The local directory where expanded files and directories are found, ready to be passed to the Nuxeo importer.
*/
- public static void expandXmlPayloadToDir(InputSource inputSource, String templateDir, String outputDir) throws Exception {
+ public static void expandXmlPayloadToDir(String tenantId, InputSource inputSource, String templateDir, String outputDir) throws Exception {
System.out.println("############## TEMPLATE_DIR: "+templateDir);
System.out.println("############## OUTPUT_DIR:"+outputDir);
- TemplateExpander.expandInputSource(templateDir, outputDir, inputSource, "/imports/import");
+ TemplateExpander.expandInputSource(tenantId, templateDir, outputDir, inputSource, "/imports/import");
//TemplateExpander.expandInputSource(templateDir, outputDir, inputFilename, "/imports/import");
}
import org.collectionspace.services.common.XmlTools;\r
import org.collectionspace.services.common.api.FileTools;\r
import org.collectionspace.services.common.api.Tools;\r
+import org.collectionspace.services.common.datetime.GregorianCalendarDateTimeUtils;\r
+import org.collectionspace.services.nuxeo.util.NuxeoUtils;\r
+\r
import org.dom4j.Document;\r
import org.dom4j.Element;\r
import org.hibernate.sql.Template;\r
return Tools.searchAndReplace(source, var(theVar), replace);\r
}\r
\r
- public static String doOneService(String outDir, String partTmpl, String wrapperTmpl,\r
+ public static String doOneService(String tenantId, String outDir, String partTmpl, String wrapperTmpl,\r
String SERVICE_TYPE, String SERVICE_NAME, String CSID) throws Exception {\r
String docID;\r
if (Tools.notBlank(CSID)){\r
\r
wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("Schema"), part);\r
wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("docID"), docID);\r
+ wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("tenantID"), tenantId);\r
wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("ServiceType"), SERVICE_TYPE);\r
wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("ServiceName"), SERVICE_NAME);\r
//TODO: set timestamp via creating a ${created} variable.\r
+ String nowTime = GregorianCalendarDateTimeUtils.timestampUTC();\r
+ wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("createdDate"), nowTime);\r
+ wrapperTmpl = Tools.searchAndReplace(wrapperTmpl, var("updatedDate"), nowTime);\r
\r
String serviceDir = outDir+'/'+docID;\r
FileTools.saveFile(serviceDir, "document.xml", wrapperTmpl, true/*true=create parent dirs*/);\r
* @param CSID An optional parameter which forces the document CSID, otherwise the CSID is set to a random UUID.\r
* @throws Exception\r
*/\r
- public static void createDocInWorkspace(String partTmpl,\r
- String SERVICE_NAME,\r
- String SERVICE_TYPE,\r
- String TEMPLATE_DIR,\r
- String OUTPUT_DIR,\r
- String CSID) throws Exception {\r
+ public static void createDocInWorkspace(\r
+ String tenantId,\r
+ String partTmpl,\r
+ String SERVICE_NAME,\r
+ String SERVICE_TYPE,\r
+ String TEMPLATE_DIR,\r
+ String OUTPUT_DIR,\r
+ String CSID) throws Exception {\r
String wrapperTmpl = FileTools.readFile(TEMPLATE_DIR,"service-document.xml");\r
String outputDir = OUTPUT_DIR+'/'+SERVICE_NAME;\r
- doOneService(outputDir, partTmpl, wrapperTmpl, SERVICE_TYPE, SERVICE_NAME, CSID);\r
+ doOneService(tenantId, outputDir, partTmpl, wrapperTmpl, SERVICE_TYPE, SERVICE_NAME, CSID);\r
}\r
\r
- public static void expand(String TEMPLATE_DIR, String outputDir, String requestFilename, String chopPath){\r
- FragmentHandlerImpl callback = new FragmentHandlerImpl(TEMPLATE_DIR, outputDir);\r
+ public static void expand(String tenantId, String TEMPLATE_DIR, String outputDir, String requestFilename, String chopPath){\r
+ FragmentHandlerImpl callback = new FragmentHandlerImpl(tenantId, TEMPLATE_DIR, outputDir);\r
XmlSaxFragmenter.parse(requestFilename, chopPath, callback, false);\r
}\r
\r
- public static void expandInputSource(String TEMPLATE_DIR, String outputDir, InputSource requestSource, String chopPath){\r
- FragmentHandlerImpl callback = new FragmentHandlerImpl(TEMPLATE_DIR, outputDir);\r
+ public static void expandInputSource(String tenantId, String TEMPLATE_DIR, String outputDir, InputSource requestSource, String chopPath){\r
+ FragmentHandlerImpl callback = new FragmentHandlerImpl(tenantId, TEMPLATE_DIR, outputDir);\r
XmlSaxFragmenter.parse(requestSource, chopPath, callback, false);\r
}\r
\r
* <import ID="1" service="Personauthorities" type="Personauthority">\r
*/\r
public static class FragmentHandlerImpl implements IFragmentHandler {\r
+ public String SERVICE_NAME = ""; //You can provide a default.\r
+ public String SERVICE_TYPE = ""; //You can provide a default.\r
+ public String TEMPLATE_DIR = ""; //You MUST provide a default via constructor.\r
+ public String OUPUT_DIR = ""; //You MUST provide a default via constructor.\r
+ public String TENANT_ID = "";\r
+\r
//============IFragmentHandler===========================================================\r
public void onFragmentReady(Document context, Element fragmentParent, String currentPath, int fragmentIndex, String fragment){\r
try {\r
dump(context, currentPath, fragmentIndex, fragment);\r
String serviceName = checkAttribute(fragmentParent, "service", SERVICE_NAME);\r
String serviceType = checkAttribute(fragmentParent, "type", SERVICE_TYPE);\r
+ serviceType = NuxeoUtils.getTenantQualifiedDocType(TENANT_ID, serviceType); //REM - Ensure a tenant qualified Nuxeo doctype\r
String CSID = fragmentParent.attributeValue("CSID");\r
- TemplateExpander.createDocInWorkspace(fragment, serviceName, serviceType, TEMPLATE_DIR, OUPUT_DIR, CSID);\r
+ TemplateExpander.createDocInWorkspace(TENANT_ID, fragment, serviceName, serviceType, TEMPLATE_DIR, OUPUT_DIR, CSID);\r
} catch (Exception e){\r
System.err.println("ERROR calling expandXmlPayloadToDir"+e);\r
e.printStackTrace();\r
System.out.println("====TemplateExpander DONE============\r\n"+ XmlTools.prettyPrint(document)+"================");\r
}\r
//============helper methods==============================================================\r
- public FragmentHandlerImpl(String templateDir, String outputDir){\r
+ public FragmentHandlerImpl(String tenantId, String templateDir, String outputDir){\r
TEMPLATE_DIR = templateDir;\r
OUPUT_DIR = outputDir;\r
+ TENANT_ID = tenantId;\r
}\r
- public String SERVICE_NAME = ""; //You can provide a default.\r
- public String SERVICE_TYPE = ""; //You can provide a default.\r
- public String TEMPLATE_DIR = ""; //You MUST provide a default via constructor.\r
- public String OUPUT_DIR = ""; //You MUST provide a default via constructor.\r
private String checkAttribute(Element fragmentParent, String attName, String defaultVal){\r
String val = fragmentParent.attributeValue(attName);\r
if (Tools.notEmpty(val)){\r
<size/>\r
</schema>\r
<schema xmlns:collectionspace_core="http://collectionspace.org/collectionspace_core/" name="collectionspace_core">\r
- <collectionspace_core:updatedAt>2011-03-05T00:06:17Z</collectionspace_core:updatedAt>\r
- <collectionspace_core:createdAt>2011-03-05T00:06:17Z</collectionspace_core:createdAt>\r
- <collectionspace_core:tenantId>1</collectionspace_core:tenantId>\r
+ <collectionspace_core:updatedAt>${updatedDate}</collectionspace_core:updatedAt>\r
+ <collectionspace_core:createdAt>${createdDate}</collectionspace_core:createdAt>\r
+ <collectionspace_core:tenantId>${tenantID}</collectionspace_core:tenantId>\r
</schema>\r
${Schema}\r
</document>\r
//These paths won't work when deployed in jboss, but they will work in the build in the source tree, which is what this test is for.
public static final String TEMPLATES_REL_DIR_TO_MODULE = "./src/main/resources/templates";
public static final String REQUESTS_REL_DIR_TO_MODULE = "./src/test/resources/requests";
+ public static final String BOGUS_TENANT_ID = "-1";
/** this test just attempts to expand a single file upload to nuxeo's import/export file/directory format,
* but does not do the import, so that this test may be run without a nuxeo instance running.
String xmlPayload = FileTools.readFile(REQUESTS_DIR,"authority-request.xml");
InputSource inputSource = ImportsResource.payloadToInputSource(xmlPayload);
- ImportsResource.expandXmlPayloadToDir(inputSource, TEMPLATE_DIR, outputDir);
+ ImportsResource.expandXmlPayloadToDir(BOGUS_TENANT_ID, inputSource, TEMPLATE_DIR, outputDir);
//TODO: inspect dir, then *cleanup*!!
}
<?xml version="1.0" encoding="UTF-8"?>\r
<imports>\r
<import seq="1" service="CollectionObjects" type="CollectionObject">\r
- <schema xmlns:collectionobjects_naturalhistory="http://collectionspace.org/collectionobject/" name="collectionobjects_naturalhistory">\r
- <collectionobjects_naturalhistory:nh-int/>\r
- <collectionobjects_naturalhistory:nh-note/>\r
- <collectionobjects_naturalhistory:nh-string/>\r
- <collectionobjects_naturalhistory:nh-long/>\r
- <collectionobjects_naturalhistory:nh-date/>\r
- </schema>\r
<schema xmlns:collectionobjects_common="http://collectionspace.org/collectionobject/" name="collectionobjects_common">\r
<collectionobjects_common:assocCulturalContextGroupList/>\r
<collectionobjects_common:assocCulturalContextGroupList/>\r