Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 3 commits
  • 6 files changed
  • 0 commit comments
  • 2 contributors
Commits on Jun 20, 2012
Richard Millet CSPACE-4789: Call to start a new Nuxeo transaction now takes an optio…
…nal timeout period paramter.
45d0635
Richard Millet CSPACE-4789: Added support for a query param impTimout that specifies…
… a timeout period in seconds -the default is 600

Conflicts:

	services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml
5037105
@ray-lee ray-lee Merge branch 'ucb-deploy_2.4' into pahma_2.4 2c9cce2
View
5 services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml
@@ -37,16 +37,12 @@
<run controlFile="objectexit/object-exit.xml" testGroup="makeone" />
<run controlFile="objectexit/object-exit.xml" testGroup="checkList" />
<run controlFile="objectexit/object-exit-display.xml" testGroup="refNameDisplayNameOnly" />
-<!--
- -->
<run controlFile="collectionobject/collectionobject-adv-search.xml" testGroup="advSearchCommonSchema" />
<run controlFile="collectionobject/collectionobject-adv-search.xml" testGroup="advSearchExtensionSchema" />
<run controlFile="acquisitions/acquisitions.xml" testGroup="makeone" />
<run controlFile="acquisitions/acquisitions.xml" testGroup="testList" />
<run controlFile="relation/relation.xml" testGroup="makeRelations" />
-<!--
--->
<!-- No - this test is broken
<run controlFile="relation/relation.xml" testGroup="r2only" />
@@ -66,6 +62,5 @@
<run controlFile="authrefs/authrefsSimple.xml" testGroup="AuthRefsSimple" />
<run controlFile="authrefs/authrefsComplex.xml" testGroup="AuthRefsComplex" />
<run controlFile="imports/imports.xml" testGroup="importsTestGroup" />
-
</xmlReplayMaster>
View
1  services/client/src/main/java/org/collectionspace/services/client/IClientQueryParams.java
@@ -31,5 +31,6 @@
public static final String PAGE_SIZE_PARAM = "pgSz";
public static final String START_PAGE_PARAM = "pgNum";
public static final String SORT_BY_PARAM = "sortBy";
+ public static final String IMPORT_TIMEOUT_PARAM = "impTimout";
}
View
65 services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/NuxeoClientEmbedded.java
@@ -19,27 +19,21 @@
package org.collectionspace.services.nuxeo.client.java;
-import java.security.Principal;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+import java.util.Map.Entry;
import java.util.Vector;
-import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.login.LoginContext;
+import javax.transaction.TransactionManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.remoting.InvokerLocator;
import org.nuxeo.common.collections.ListenerList;
-import org.nuxeo.ecm.core.api.ClientException;
-import org.nuxeo.ecm.core.api.local.ClientLoginModule;
-import org.nuxeo.ecm.core.api.local.LoginStack;
import org.nuxeo.ecm.core.api.repository.Repository;
import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
import org.nuxeo.ecm.core.api.repository.RepositoryInstanceHandler;
@@ -73,7 +67,7 @@
private LoginHandler loginHandler;
- private final List<RepositoryInstance> repositoryInstances;
+ private final HashMap<String, RepositoryInstance> repositoryInstances;
private final ListenerList connectionListeners;
@@ -100,7 +94,7 @@ public NuxeoClientEmbedded() {
cfg = new AutoConfigurationService();
loginHandler = loginHandler == null ? new DefaultLoginHandler()
: loginHandler;
- repositoryInstances = new Vector<RepositoryInstance>();
+ repositoryInstances = new HashMap<String, RepositoryInstance>();
}
public static NuxeoClientEmbedded getInstance() {
@@ -280,11 +274,11 @@ private void doDisconnect() throws Exception {
locator = null;
serverName = null;
// close repository sessions if any
- Iterator<RepositoryInstance> it = repositoryInstances.iterator();
+ Iterator<Entry<String, RepositoryInstance>> it = repositoryInstances.entrySet().iterator();
while (it.hasNext()) {
- RepositoryInstance repo = it.next();
+ Entry<String, RepositoryInstance> repo = it.next();
try {
- repo.close();
+ repo.getValue().close();
} catch (Exception e) {
log.debug("Error while trying to close " + repo, e);
}
@@ -382,11 +376,24 @@ public Repository getRepository(String name) throws Exception {
return getRepositoryManager().getRepository(name);
}
+ public RepositoryInstance openRepository(int timeoutSeconds) throws Exception {
+ return openRepository(null, timeoutSeconds);
+ }
+
public RepositoryInstance openRepository() throws Exception {
- return openRepository(null);
+ return openRepository(-1 /*default timeout period*/);
}
- public RepositoryInstance openRepository(String name) throws Exception {
+ public RepositoryInstance openRepository(String name, int timeoutSeconds) throws Exception {
+ if (timeoutSeconds > 0) {
+ TransactionManager transactionMgr = TransactionHelper.lookupTransactionManager();
+ transactionMgr.setTransactionTimeout(timeoutSeconds);
+ if (logger.isInfoEnabled()) {
+ logger.info(String.format("Changing current request's transaction timeout period to %d seconds",
+ timeoutSeconds));
+ }
+ }
+
boolean startTransaction = TransactionHelper.startTransaction();
if (startTransaction == false) {
logger.warn("Could not start a Nuxeo transaction with the TransactionHelper class.");
@@ -399,27 +406,43 @@ public RepositoryInstance openRepository(String name) throws Exception {
repository = getRepositoryManager().getDefaultRepository();
}
RepositoryInstance repo = newRepositoryInstance(repository);
- repositoryInstances.add(repo);
+ String key = repo.getSessionId();
+ repositoryInstances.put(key, repo);
+ if (logger.isTraceEnabled()) {
+ logger.trace("Added a new repository instance to our repo list. Current count is now: "
+ + repositoryInstances.size());
+ }
return repo;
}
public void releaseRepository(RepositoryInstance repo) throws Exception {
+ String key = repo.getSessionId();
+
try {
repo.save();
repo.close();
} catch (Exception e) {
- logger.error("Could not save and/or release the repository.", e);
+ logger.error("Possible data loss. Could not save and/or release the repository.", e);
throw e;
} finally {
- repositoryInstances.remove(repo);
+ RepositoryInstance wasRemoved = repositoryInstances.remove(key);
+ if (logger.isTraceEnabled()) {
+ if (wasRemoved != null) {
+ logger.trace("Removed a repository instance from our repo list. Current count is now: "
+ + repositoryInstances.size());
+ } else {
+ logger.trace("Could not remove a repository instance from our repo list. Current count is now: "
+ + repositoryInstances.size());
+ }
+ }
TransactionHelper.commitOrRollbackTransaction();
}
}
- public RepositoryInstance[] getRepositoryInstances() {
- return repositoryInstances.toArray(new RepositoryInstance[repositoryInstances.size()]);
- }
+// public RepositoryInstance[] getRepositoryInstances() {
+// return repositoryInstances.toArray(new RepositoryInstance[repositoryInstances.size()]);
+// }
public static RepositoryInstance newRepositoryInstance(Repository repository) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
View
694 services/imports/service/src/main/java/org/collectionspace/services/imports/ImportsResource.java
@@ -24,6 +24,7 @@
package org.collectionspace.services.imports;
import org.collectionspace.authentication.AuthN;
+import org.collectionspace.services.client.IClientQueryParams;
import org.collectionspace.services.client.PoxPayloadIn;
import org.collectionspace.services.client.PoxPayloadOut;
import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
@@ -56,7 +57,7 @@
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import java.io.ByteArrayInputStream;
@@ -73,303 +74,400 @@
* @author Laramie Crocker
*/
@Path(ImportsResource.SERVICE_PATH)
-@Produces({"application/xml"})
-@Consumes({"application/xml"})
-public class ImportsResource extends AbstractCollectionSpaceResourceImpl {
-
- public static final String SERVICE_NAME = "imports";
- public static final String SERVICE_PATH = "/" + SERVICE_NAME;
-
- /*
- * 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;
- }
-
- @Override
- protected String getVersionString() {
- final String lastChangeRevision = "$LastChangedRevision: 2108 $";
- return lastChangeRevision;
- }
-
- @Override
- public Class<?> getCommonPartClass() {
- return ImportsCommon.class;
- }
-
- @Override
- public ServiceContextFactory<PoxPayloadIn, PoxPayloadOut> getServiceContextFactory() {
- return MultipartServiceContextFactory.get();
- }
-
- private static String _templateDir = null;
- public static String getTemplateDir(){
- if (_templateDir == null){
- TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance().getTenantBindingConfigReader();
- _templateDir = tReader.getResourcesDir()+File.separator+"templates";
- }
- return _templateDir;
- }
-
- @POST
- public Response create(@Context UriInfo ui, String xmlPayload) {
- try {
- return this.create(xmlPayload);
- } catch (Exception e) {
- throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
- }
- }
- /** you can test this with something like:
- * curl -X POST http://localhost:8180/cspace-services/imports -i -u "Admin@collectionspace.org:Administrator" -H "Content-Type: application/xml" -T in.xml
- * -T /src/trunk/services/imports/service/src/main/resources/templates/authority-request.xml
- */
- @POST
- @Consumes("application/xml")
- @Produces("application/xml")
- public javax.ws.rs.core.Response create(String xmlPayload) {
- String result;
- javax.ws.rs.core.Response.ResponseBuilder rb;
- try {
- //InputSource inputSource = payloadToInputSource(xmlPayload);
- //result = createFromInputSource(inputSource);
- String inputFilename = payloadToFilename(xmlPayload);
- result = createFromFilename(inputFilename);
- rb = javax.ws.rs.core.Response.ok();
- } catch (Exception e) {
- result = Tools.errorToString(e, true);
- rb = javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
- }
- rb.entity(result);
- return rb.build();
- }
-
- 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(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 = getWorkspaces();
- String result = "";
- try {
- String report = "NORESULTS";
- report = importCommand.run(outputDir, destWorkspaces);
- result = "<?xml version=\"1.0\"?><import><msg>SUCCESS</msg>"+report+"</import>";
- } catch (Exception e){
- result = "<?xml version=\"1.0\"?><import><msg>ERROR</msg><report>"+Tools.errorToString(e, true)+"</report></import>";
- }
- return result;
- }
-
- 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(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 = getWorkspaces();
- String result = "";
- try {
- String report = "NORESULTS";
- report = importCommand.run(outputDir, destWorkspaces);
- result = "<?xml version=\"1.0\"?><import><msg>SUCCESS</msg>"+report+"</import>";
- } catch (Exception e){
- result = "<?xml version=\"1.0\"?><import><msg>ERROR</msg><report>"+Tools.errorToString(e, true)+"</report></import>";
- }
- return result;
- }
-
-
- /** @param xmlPayload A request file has a specific format, you can look at:
- * trunk/services/imports/service/src/test/resources/requests/authority-request.xml
- */
- public static InputSource payloadToInputSource(String xmlPayload) throws Exception {
- xmlPayload = encodeAmpersands(xmlPayload);
- String requestDir = FileTools.createTmpDir("imports-request-").getCanonicalPath();
- File requestFile =
- FileTools.saveFile(requestDir, "request.xml", xmlPayload, FileTools.FORCE_CREATE_PARENT_DIRS, FileTools.UTF8_ENCODING);
- if (requestFile == null){
- throw new FileNotFoundException("Could not create file in requestDir: "+requestDir);
- }
- String requestFilename = requestFile.getCanonicalPath();
- InputSource inputSource = new InputSource(requestFilename);
- System.out.println("############## REQUEST_FILENAME: "+requestFilename);
- return inputSource;
- }
-
- public static String payloadToFilename(String xmlPayload) throws Exception {
- xmlPayload = encodeAmpersands(xmlPayload);
- String requestDir = FileTools.createTmpDir("imports-request-").getCanonicalPath();
- File requestFile =
- FileTools.saveFile(requestDir, "request.xml", xmlPayload, FileTools.FORCE_CREATE_PARENT_DIRS, FileTools.UTF8_ENCODING);
- if (requestFile == null){
- throw new FileNotFoundException("Could not create file in requestDir: "+requestDir);
- }
- String requestFilename = requestFile.getCanonicalPath();
- System.out.println("############## REQUEST_FILENAME: "+requestFilename);
- return requestFilename;
- }
-
- /**
- * Encodes each ampersand ('&') in the incoming XML payload by replacing
- * it with the predefined XML entity for an ampersand ('&amp;').
- *
- * This is a workaround for the issue described in CSPACE-3911. Its
- * intended effect is to have these added ampersand XML entities being
- * resolved to 'bare' ampersands during the initial parse, thus preserving
- * any XML entities in the payload, which will then be resolved correctly
- * during the second parse.
- *
- * (This is not designed to compensate for instances where the incoming
- * XML payload contains 'bare' ampersands - that is, used in any other
- * context than as the initial characters in XML entities. In those cases,
- * the payload may not be a legal XML document.)
- *
- * @param xmlPayload
- * @return The original XML payload, with each ampersand replaced by
- * the predefined XML entity for an ampersand.
- */
- private static String encodeAmpersands(String xmlPayload) {
- return xmlPayload.replace("&", "&amp;");
- }
-
- 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(tenantId, templateDir, outputDir, inputSource, "/imports/import");
- }
-
- /** This method may be called statically from outside this class; there is a test call in
- * org.collectionspace.services.test.ImportsServiceTest
- *
- * @param inputSource A wrapper around a request file, either a local file or a stream;
- * the file has a specific format, you can look at:
- * trunk/services/imports/service/src/test/resources/requests/authority-request.xml
- * @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(String tenantId, InputSource inputSource, String templateDir, String outputDir) throws Exception {
- System.out.println("############## TEMPLATE_DIR: "+templateDir);
- System.out.println("############## OUTPUT_DIR:"+outputDir);
- TemplateExpander.expandInputSource(tenantId, templateDir, outputDir, inputSource, "/imports/import");
- //TemplateExpander.expandInputSource(templateDir, outputDir, inputFilename, "/imports/import");
- }
-
- /** you can test like this:
- * curl -F "file=@out.zip;type=application/zip" --basic -u "Admin@collectionspace.org:Administrator" http://localhost:8280/cspace-services/imports
- */
- @POST
- @Consumes("multipart/form-data")
- @Produces("application/xml")
- public javax.ws.rs.core.Response acceptUpload(@Context HttpServletRequest req,
- MultipartFormDataInput partFormData) {
- javax.ws.rs.core.Response response = null;
- StringBuffer resultBuf = new StringBuffer();
- try {
- InputStream fileStream = null;
- String preamble = partFormData.getPreamble();
- System.out.println("Preamble type is:" + preamble);
- Map<String, List<InputPart>> partsMap = partFormData.getFormDataMap();
- List<InputPart> fileParts = partsMap.get("file");
- for (InputPart part : fileParts){
- String mediaType = part.getMediaType().toString();
- System.out.println("Media type is:" + mediaType);
- if (mediaType.equalsIgnoreCase(MediaType.APPLICATION_XML) || mediaType.equalsIgnoreCase(MediaType.TEXT_XML)){
- // FIXME For an alternate approach, potentially preferable, see:
- // http://stackoverflow.com/questions/4586222/right-way-of-formatting-an-input-stream
- String str = encodeAmpersands(part.getBodyAsString());
- InputStream stream = new ByteArrayInputStream(str.getBytes("UTF8"));
- InputSource inputSource = new InputSource(stream);
- // InputSource inputSource = new InputSource(part.getBody(InputStream.class, null));
- String result = createFromInputSource(inputSource);
- resultBuf.append(result);
- continue;
- }
- if (mediaType.equalsIgnoreCase("application/zip")){
- fileStream = part.getBody(InputStream.class, null);
-
- File zipfile = FileUtils.createTmpFile(fileStream, getServiceName() + "_");
- String zipfileName = zipfile.getCanonicalPath();
- System.out.println("Imports zip file saved to:" + zipfileName);
-
- String baseOutputDir = FileTools.createTmpDir("imports-").getCanonicalPath();
- File indir = new File(baseOutputDir+"/in");
- indir.mkdir();
- ZipTools.unzip(zipfileName, indir.getCanonicalPath());
- String result = "\r\n<zipResult>Zipfile " + zipfileName + "extracted to: " + indir.getCanonicalPath()+"</zipResult>";
- System.out.println(result);
-
- long start = System.currentTimeMillis();
- //TODO: now call import service...
- resultBuf.append(result);
- continue;
- }
- }
- javax.ws.rs.core.Response.ResponseBuilder rb = javax.ws.rs.core.Response.ok();
- rb.entity(resultBuf.toString());
- response = rb.build();
- } catch (Exception e) {
- throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
- }
- return response;
- }
-
- String page = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
- + "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"
- + " <head>\n"
- + " <title>CollectionSpace Import</title>\n"
- + " <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />\n"
- + " <meta http-equiv='Accept' content='multipart/form-data,application/xml,text/xml' />\n"
- + " <meta http-equiv='Accept-Charset' content='utf-8' />\n"
- + " </head>\n"
- + " <body>\n"
- + " <form enctype='multipart/form-data' accept-charset='utf-8' \n"
- + " action='/cspace-services/imports?type=xml' method='post'>\n"
- + " Choose a file to import:"
- + " <input name='file' type='file' accept='application/xml,text/xml' />\n"
- + " <br />\n"
- + " <input type='submit' value='Upload File' />\n"
- + " </form>\n"
- + " </body>\n"
- + "</html>\n";
- @GET
- @Produces("text/html")
+@Produces({ "application/xml" })
+@Consumes({ "application/xml" })
+public class ImportsResource extends AbstractCollectionSpaceResourceImpl<PoxPayloadIn, PoxPayloadOut> {
+
+ 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
+
+ /*
+ * 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;
+ }
+
+ @Override
+ protected String getVersionString() {
+ final String lastChangeRevision = "$LastChangedRevision: 2108 $";
+ return lastChangeRevision;
+ }
+
+ @Override
+ public Class<?> getCommonPartClass() {
+ return ImportsCommon.class;
+ }
+
+ @Override
+ public ServiceContextFactory<PoxPayloadIn, PoxPayloadOut> getServiceContextFactory() {
+ return MultipartServiceContextFactory.get();
+ }
+
+ private static String _templateDir = null;
+
+ public static String getTemplateDir() {
+ if (_templateDir == null) {
+ TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance()
+ .getTenantBindingConfigReader();
+ _templateDir = tReader.getResourcesDir() + File.separator
+ + "templates";
+ }
+ return _templateDir;
+ }
+
+ // @POST
+ // public Response create(@Context UriInfo ui, String xmlPayload) {
+ // try {
+ // return this.create(xmlPayload);
+ // } catch (Exception e) {
+ // throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
+ // }
+ // }
+
+ private int getTimeoutParam(UriInfo ui) {
+ int result = DEFAULT_TX_TIMOUT;
+
+ MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
+ if (queryParams != null) {
+ String timeoutString = queryParams
+ .getFirst(IClientQueryParams.IMPORT_TIMEOUT_PARAM);
+ if (timeoutString != null)
+ try {
+ result = Integer.parseInt(timeoutString);
+ } catch (NumberFormatException e) {
+ logger.warn(
+ "Timeout period parameter could not be parsed. The characters in the parameter string must all be decimal digits. The Import service will use the default timeout period instead.",
+ e);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * you can test this with something like: curl -X POST
+ * http://localhost:8180/cspace-services/imports -i -u
+ * "Admin@collectionspace.org:Administrator" -H
+ * "Content-Type: application/xml" -T in.xml -T
+ * /src/trunk/services/imports/service
+ * /src/main/resources/templates/authority-request.xml
+ */
+ @POST
+ @Consumes("application/xml")
+ @Produces("application/xml")
+ public javax.ws.rs.core.Response create(@Context UriInfo ui,
+ String xmlPayload) {
+ String result = null;
+ javax.ws.rs.core.Response.ResponseBuilder rb;
+ try {
+ int timeout = getTimeoutParam(ui);
+ // InputSource inputSource = payloadToInputSource(xmlPayload);
+ // result = createFromInputSource(inputSource);
+ String inputFilename = payloadToFilename(xmlPayload);
+ result = createFromFilename(inputFilename, timeout);
+ rb = javax.ws.rs.core.Response.ok();
+ } catch (Exception e) {
+ result = Tools.errorToString(e, true);
+ rb = javax.ws.rs.core.Response
+ .status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ rb.entity(result);
+ return rb.build();
+ }
+
+ public static String createFromInputSource(InputSource inputSource,
+ int timeOut) 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(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 = getWorkspaces();
+ String result = "";
+ try {
+ String report = "NORESULTS";
+ report = importCommand.run(outputDir, destWorkspaces, timeOut);
+ result = "<?xml version=\"1.0\"?><import><msg>SUCCESS</msg>"
+ + report + "</import>";
+ } catch (Exception e) {
+ result = "<?xml version=\"1.0\"?><import><msg>ERROR</msg><report>"
+ + Tools.errorToString(e, true) + "</report></import>";
+ }
+ return result;
+ }
+
+ public static String createFromFilename(String filename, int timeOut)
+ 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(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 = getWorkspaces();
+ String result = "";
+ try {
+ String report = "NORESULTS";
+ report = importCommand.run(outputDir, destWorkspaces, timeOut);
+ result = "<?xml version=\"1.0\"?><import><msg>SUCCESS</msg>"
+ + report + "</import>";
+ } catch (Exception e) {
+ result = "<?xml version=\"1.0\"?><import><msg>ERROR</msg><report>"
+ + Tools.errorToString(e, true) + "</report></import>";
+ }
+ return result;
+ }
+
+ /**
+ * @param xmlPayload
+ * A request file has a specific format, you can look at:
+ * trunk/services
+ * /imports/service/src/test/resources/requests/authority
+ * -request.xml
+ */
+ public static InputSource payloadToInputSource(String xmlPayload)
+ throws Exception {
+ xmlPayload = encodeAmpersands(xmlPayload);
+ String requestDir = FileTools.createTmpDir("imports-request-")
+ .getCanonicalPath();
+ File requestFile = FileTools.saveFile(requestDir, "request.xml",
+ xmlPayload, FileTools.FORCE_CREATE_PARENT_DIRS,
+ FileTools.UTF8_ENCODING);
+ if (requestFile == null) {
+ throw new FileNotFoundException(
+ "Could not create file in requestDir: " + requestDir);
+ }
+ String requestFilename = requestFile.getCanonicalPath();
+ InputSource inputSource = new InputSource(requestFilename);
+ System.out.println("############## REQUEST_FILENAME: "
+ + requestFilename);
+ return inputSource;
+ }
+
+ public static String payloadToFilename(String xmlPayload) throws Exception {
+ xmlPayload = encodeAmpersands(xmlPayload);
+ String requestDir = FileTools.createTmpDir("imports-request-")
+ .getCanonicalPath();
+ File requestFile = FileTools.saveFile(requestDir, "request.xml",
+ xmlPayload, FileTools.FORCE_CREATE_PARENT_DIRS,
+ FileTools.UTF8_ENCODING);
+ if (requestFile == null) {
+ throw new FileNotFoundException(
+ "Could not create file in requestDir: " + requestDir);
+ }
+ String requestFilename = requestFile.getCanonicalPath();
+ System.out.println("############## REQUEST_FILENAME: "
+ + requestFilename);
+ return requestFilename;
+ }
+
+ /**
+ * Encodes each ampersand ('&') in the incoming XML payload by replacing it
+ * with the predefined XML entity for an ampersand ('&amp;').
+ *
+ * This is a workaround for the issue described in CSPACE-3911. Its intended
+ * effect is to have these added ampersand XML entities being resolved to
+ * 'bare' ampersands during the initial parse, thus preserving any XML
+ * entities in the payload, which will then be resolved correctly during the
+ * second parse.
+ *
+ * (This is not designed to compensate for instances where the incoming XML
+ * payload contains 'bare' ampersands - that is, used in any other context
+ * than as the initial characters in XML entities. In those cases, the
+ * payload may not be a legal XML document.)
+ *
+ * @param xmlPayload
+ * @return The original XML payload, with each ampersand replaced by the
+ * predefined XML entity for an ampersand.
+ */
+ private static String encodeAmpersands(String xmlPayload) {
+ return xmlPayload.replace("&", "&amp;");
+ }
+
+ 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(tenantId, templateDir, outputDir,
+ inputSource, "/imports/import");
+ }
+
+ /**
+ * This method may be called statically from outside this class; there is a
+ * test call in org.collectionspace.services.test.ImportsServiceTest
+ *
+ * @param inputSource
+ * A wrapper around a request file, either a local file or a
+ * stream; the file has a specific format, you can look at:
+ * trunk/services/imports/service/src/test/resources/requests/
+ * authority-request.xml
+ * @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(String tenantId,
+ InputSource inputSource, String templateDir, String outputDir)
+ throws Exception {
+ System.out.println("############## TEMPLATE_DIR: " + templateDir);
+ System.out.println("############## OUTPUT_DIR:" + outputDir);
+ TemplateExpander.expandInputSource(tenantId, templateDir, outputDir,
+ inputSource, "/imports/import");
+ // TemplateExpander.expandInputSource(templateDir, outputDir,
+ // inputFilename, "/imports/import");
+ }
+
+ /**
+ * you can test like this: curl -F "file=@out.zip;type=application/zip"
+ * --basic -u "admin@core.collectionspace.org:Administrator"
+ * http://localhost:8180/cspace-services/imports
+ */
+ @POST
+ @Consumes("multipart/form-data")
+ @Produces("application/xml")
+ public javax.ws.rs.core.Response acceptUpload(@Context UriInfo ui,
+ @Context HttpServletRequest req, MultipartFormDataInput partFormData) {
+ javax.ws.rs.core.Response response = null;
+ StringBuffer resultBuf = new StringBuffer();
+ try {
+ InputStream fileStream = null;
+ String preamble = partFormData.getPreamble();
+ System.out.println("Preamble type is:" + preamble);
+ Map<String, List<InputPart>> partsMap = partFormData
+ .getFormDataMap();
+ List<InputPart> fileParts = partsMap.get("file");
+ int timeout = this.getTimeoutParam(ui);
+ for (InputPart part : fileParts) {
+ String mediaType = part.getMediaType().toString();
+ System.out.println("Media type is:" + mediaType);
+ if (mediaType.equalsIgnoreCase(MediaType.APPLICATION_XML)
+ || mediaType.equalsIgnoreCase(MediaType.TEXT_XML)) {
+ // FIXME For an alternate approach, potentially preferable,
+ // see:
+ // http://stackoverflow.com/questions/4586222/right-way-of-formatting-an-input-stream
+ String str = encodeAmpersands(part.getBodyAsString());
+ InputStream stream = new ByteArrayInputStream(
+ str.getBytes("UTF8"));
+ InputSource inputSource = new InputSource(stream);
+ // InputSource inputSource = new
+ // InputSource(part.getBody(InputStream.class, null));
+ String result = createFromInputSource(inputSource, timeout);
+ resultBuf.append(result);
+ continue;
+ }
+
+ //
+ // This code was never finished to support the import of a zipped directory
+ //
+ if (mediaType.equalsIgnoreCase("application/zip")) {
+ logger.error("The Import service does not yet support .zip files."); //We should also send back a meaningful error message and status code here.
+
+ fileStream = part.getBody(InputStream.class, null);
+
+ File zipfile = FileUtils.createTmpFile(fileStream,
+ getServiceName() + "_");
+ String zipfileName = zipfile.getCanonicalPath();
+ System.out.println("Imports zip file saved to:"
+ + zipfileName);
+
+ String baseOutputDir = FileTools.createTmpDir("imports-")
+ .getCanonicalPath();
+ File indir = new File(baseOutputDir + "/in");
+ indir.mkdir();
+ ZipTools.unzip(zipfileName, indir.getCanonicalPath());
+ String result = "\r\n<zipResult>Zipfile " + zipfileName
+ + "extracted to: " + indir.getCanonicalPath()
+ + "</zipResult>";
+ System.out.println(result);
+
+ long start = System.currentTimeMillis();
+ // TODO: now call import service...
+ resultBuf.append(result);
+ continue;
+ }
+ }
+ javax.ws.rs.core.Response.ResponseBuilder rb = javax.ws.rs.core.Response
+ .ok();
+ rb.entity(resultBuf.toString());
+ response = rb.build();
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
+ }
+ return response;
+ }
+
+ String page = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
+ + "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"
+ + " <head>\n"
+ + " <title>CollectionSpace Import</title>\n"
+ + " <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />\n"
+ + " <meta http-equiv='Accept' content='multipart/form-data,application/xml,text/xml' />\n"
+ + " <meta http-equiv='Accept-Charset' content='utf-8' />\n"
+ + " </head>\n"
+ + " <body>\n"
+ + " <form enctype='multipart/form-data' accept-charset='utf-8' \n"
+ + " action='/cspace-services/imports?type=xml' method='post'>\n"
+ + " Choose a file to import:"
+ + " <input name='file' type='file' accept='application/xml,text/xml' />\n"
+ + " <br />\n"
+ + " <input type='submit' value='Upload File' />\n"
+ + " </form>\n" + " </body>\n" + "</html>\n";
+
+ @GET
+ @Produces("text/html")
public String getInputForm(@QueryParam("form") String form) {
- return page;
+ return page;
}
}
View
12 services/imports/service/src/main/java/org/collectionspace/services/imports/nuxeo/ImportCommand.java
@@ -1,6 +1,7 @@
package org.collectionspace.services.imports.nuxeo;
import java.io.File;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
@@ -23,17 +24,22 @@
public class ImportCommand {
private static final Log logger = LogFactory.getLog(ImportCommand.class);
- public String run(String src, String dest) throws Exception {
+ public String run(String src, String dest, int timeOut) throws Exception {
File file = new File(src);
///cspace way of configuring client and auth:
NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
- RepositoryInstance repoSession = client.openRepository();
+ RepositoryInstance repoSession = client.openRepository(timeOut);
try {
+ String msg = String.format("Start of import is Local time: %tT", Calendar.getInstance());
+ logger.debug(msg);
+ System.out.println(msg);
return importTree(repoSession, file, dest);
} catch (Exception e) {
throw e;
} finally {
-// repository.close();
+ String msg = String.format("End of import is Local time: %tT", Calendar.getInstance());
+ logger.debug(msg);
+ System.out.println(msg);
client.releaseRepository(repoSession);
}
}
View
6 services/query/service/src/main/java/org/collectionspace/services/query/QueryResource.java
@@ -27,15 +27,9 @@
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
//import javax.xml.bind.JAXBContext;
//import javax.xml.bind.Marshaller;

No commit comments for this range

Something went wrong with that request. Please try again.