]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-4789: Added support for a query param impTimout that specifies a timeout perio...
authorRichard Millet <remillet@berkeley.edu>
Wed, 20 Jun 2012 20:54:49 +0000 (13:54 -0700)
committerRichard Millet <remillet@berkeley.edu>
Wed, 20 Jun 2012 20:54:49 +0000 (13:54 -0700)
services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml
services/client/src/main/java/org/collectionspace/services/client/IClientQueryParams.java
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
services/query/service/src/main/java/org/collectionspace/services/query/QueryResource.java

index 5f166ffaeed4afe78d12fbf9435148450d12d7a8..afd1e00a23f9c2f592ed611d279f0db69defb1ba 100644 (file)
          File below this line have been ported. -->\r
     <!-- ============================================= -->\r
     \r
-<!--     \r
     <run controlFile="./security.xml" testGroup="deleteBug" />\r
     <run controlFile="objectexit/object-exit.xml" testGroup="makeone" />\r
     <run controlFile="objectexit/object-exit.xml" testGroup="checkList" />\r
     <run controlFile="objectexit/object-exit-display.xml" testGroup="refNameDisplayNameOnly" />\r
- -->\r
  \r
-<!--\r
     <run controlFile="collectionobject/collectionobject-adv-search.xml" testGroup="advSearchCommonSchema" />\r
     <run controlFile="collectionobject/collectionobject-adv-search.xml" testGroup="advSearchExtensionSchema" />\r
     <run controlFile="acquisitions/acquisitions.xml" testGroup="makeone" />\r
     <run controlFile="acquisitions/acquisitions.xml" testGroup="testList" />\r
     <run controlFile="relation/relation.xml" testGroup="makeRelations" />\r
--->\r
 \r
 <!-- No - this test is broken\r
        <run controlFile="relation/relation.xml" testGroup="r2only" />\r
 -->\r
 \r
-<!-- \r
     <run controlFile="person/person.xml" testGroup="postPerson" />\r
     <run controlFile="person/person.xml" testGroup="updatePerson" />\r
- -->    \r
     <run controlFile="person/person.xml" testGroup="PersonAddRelsDeleteRels" />\r
 \r
-<!-- \r
     <run controlFile="location/location-hierarchy.xml" testGroup="HierarchicLocation" />\r
     <run controlFile="organization/organization-hierarchy.xml" testGroup="HierarchicOrganization" />\r
  \r
@@ -69,7 +62,6 @@
     <run controlFile="authrefs/authrefsSimple.xml" testGroup="AuthRefsSimple" />\r
     <run controlFile="authrefs/authrefsComplex.xml" testGroup="AuthRefsComplex" />\r
     <run controlFile="imports/imports.xml" testGroup="importsTestGroup" />\r
- -->\r
      \r
 </xmlReplayMaster>\r
 \r
index 5b7077b7a2d4e6cdb1227bdba7f3135f8a9fe942..40a67a8b86e159ba569ad7c0a3160c8ddb44d0be 100644 (file)
@@ -31,5 +31,6 @@ public interface IClientQueryParams {
     public static final String PAGE_SIZE_PARAM = "pgSz";\r
     public static final String START_PAGE_PARAM = "pgNum";\r
     public static final String SORT_BY_PARAM = "sortBy";\r
+    public static final String IMPORT_TIMEOUT_PARAM = "impTimout";\r
     \r
 }\r
index 64dc39b0158c41a63dbc7861bed16f3981198e0a..158efbbf275816df94c99c2c929382a9eeb62c99 100644 (file)
@@ -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.Produces;
 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 @@ import java.util.Map;
  * @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;
        }
 }
index faeddfecf0217c88e6837598a3ca9f00f2a291c0..186625c52283099d1545cfb04154d6b5b334d40a 100644 (file)
@@ -23,13 +23,12 @@ import org.nuxeo.ecm.core.io.impl.plugins.DocumentModelWriter;
 // based loosely on package org.nuxeo.ecm.shell.commands.io.ImportCommand;\r
 public class ImportCommand {\r
     private static final Log logger = LogFactory.getLog(ImportCommand.class);\r
-    private static final int DEFAULT_TX_TIMOUT = 600; //timeout period in seconds\r
 \r
-    public String run(String src, String dest) throws Exception {\r
+    public String run(String src, String dest, 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(DEFAULT_TX_TIMOUT);\r
+        RepositoryInstance  repoSession = client.openRepository(timeOut);\r
         try {\r
                String msg = String.format("Start of import is Local time: %tT", Calendar.getInstance());\r
                logger.debug(msg);\r
index c6f6d6057646682fa6f5e3724f3cb89748df9c6f..7d1eb95230450d1d925a70371358aaae200588c0 100644 (file)
@@ -27,15 +27,9 @@ import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;\r
 import javax.ws.rs.Path;\r
 import javax.ws.rs.Produces;\r
-import javax.ws.rs.DELETE;\r
-import javax.ws.rs.POST;\r
-import javax.ws.rs.PUT;\r
 import javax.ws.rs.PathParam;\r
 import javax.ws.rs.WebApplicationException;\r
-import javax.ws.rs.core.Context;\r
 import javax.ws.rs.core.Response;\r
-import javax.ws.rs.core.UriBuilder;\r
-import javax.ws.rs.core.UriInfo;\r
 //import javax.xml.bind.JAXBContext;\r
 //import javax.xml.bind.Marshaller;\r
 \r