[jboss-svn-commits] JBoss Common SVN: r4718 - in arquillian/trunk/containers/tomcat-embedded-6/src: main/java/org/jboss/arquillian/container/tomcat/embedded_6 and 1 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Sun Jul 11 03:27:38 EDT 2010


Author: dan.j.allen
Date: 2010-07-11 03:27:38 -0400 (Sun, 11 Jul 2010)
New Revision: 4718

Added:
   arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/EmbeddedContextConfig.java
Removed:
   arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/apache/
Modified:
   arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatConfiguration.java
   arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatContainer.java
   arquillian/trunk/containers/tomcat-embedded-6/src/test/resources/arquillian.xml
Log:
ARQ-189 switch to assuming context path begins with /
use temporary directory for tomcat home if not set
optimize container bootstrap
clean out unpacked WAR on undeploy
switch to using a custom, extended ContextConfig


Added: arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/EmbeddedContextConfig.java
===================================================================
--- arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/EmbeddedContextConfig.java	                        (rev 0)
+++ arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/EmbeddedContextConfig.java	2010-07-11 07:27:38 UTC (rev 4718)
@@ -0,0 +1,121 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.arquillian.container.tomcat.embedded_6;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.ServletContext;
+import org.apache.catalina.startup.Constants;
+import org.apache.catalina.startup.ContextConfig;
+import org.xml.sax.InputSource;
+
+/**
+ * A custom {@link ContextConfig} for use in the Embedded Tomcat
+ * container integration for Arquillian.
+ *
+ * <p>This configuration adds processing of the META-INF/context.xml
+ * descriptor in the web application root when the context is started.
+ * This implementation also marks an unpacked WAR for deletion when
+ * the context is stopped.</p>
+ *
+ * @author Dan Allen
+ */
+public class EmbeddedContextConfig extends ContextConfig
+{
+   /**
+    * Override as a hook to process the application context configuration.
+    */
+   @Override
+   protected void defaultWebConfig()
+   {
+      applicationContextConfig();
+      super.defaultWebConfig();
+   }
+
+   /**
+    * Process the META-INF/context.xml descriptor in the web application root.
+    * This descriptor is not processed when a webapp is added programmatically through a StandardContext
+    */
+   protected void applicationContextConfig()
+   {
+      ServletContext servletContext = context.getServletContext();
+      InputStream stream = servletContext.getResourceAsStream("/" + Constants.ApplicationContextXml);
+      if (stream == null)
+      {
+         return;
+      }
+      // this bad-practice synchronization is inherited
+      synchronized (contextDigester)
+      {
+         URL url = null;
+         try
+         {
+            url = servletContext.getResource("/" + Constants.ApplicationContextXml);
+         }
+         catch (MalformedURLException e)
+         {
+            throw new AssertionError("/" + Constants.ApplicationContextXml + " should not be considered a malformed URL");
+         }
+         InputSource is = new InputSource(url.toExternalForm());
+         is.setByteStream(stream);
+         contextDigester.push(context);
+         try
+         {
+            contextDigester.parse(is);
+         }
+         catch (Exception e)
+         {
+            ok = false;
+            log.error("Parse error in context.xml for " + context.getName(), e);
+         }
+         finally
+         {
+            contextDigester.reset();
+            try
+            {
+               if (stream != null)
+               {
+                  stream.close();
+               }
+            }
+            catch (IOException e)
+            {
+               log.error("Error closing context.xml for " + context.getName(), e);
+            }
+         }
+      }
+      log.debug("Done processing " + Constants.ApplicationContextXml + " descriptor");
+   }
+
+   /**
+    * Overridde to assign an internal field that will trigger the removal
+    * of the unpacked WAR when the context is closed.
+    */
+   @Override
+   protected void fixDocBase() throws IOException
+   {
+      super.fixDocBase();
+      // If this field is not null, the unpacked WAR is removed when
+      // the context is closed. This is normally used by the antiLocking
+      // feature, though it should have been the normal behavior, at
+      // least for an embedded container.
+      originalDocBase = context.getDocBase();
+   }
+
+}

Modified: arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatConfiguration.java
===================================================================
--- arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatConfiguration.java	2010-07-11 07:24:24 UTC (rev 4717)
+++ arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatConfiguration.java	2010-07-11 07:27:38 UTC (rev 4718)
@@ -38,9 +38,9 @@
 
    private String workDir = null;
 
-   private String serverName = "tomcat";
+   private String serverName = "arquillian-tomcat-embedded-6";
    
-   private boolean unpackArchive = true;
+   private boolean unpackArchive = false;
 
    public ContainerProfile getContainerProfile()
    {

Modified: arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatContainer.java
===================================================================
--- arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatContainer.java	2010-07-11 07:24:24 UTC (rev 4717)
+++ arquillian/trunk/containers/tomcat-embedded-6/src/main/java/org/jboss/arquillian/container/tomcat/embedded_6/TomcatContainer.java	2010-07-11 07:27:38 UTC (rev 4718)
@@ -28,9 +28,13 @@
 import org.apache.catalina.Container;
 import org.apache.catalina.Engine;
 import org.apache.catalina.Host;
+import org.apache.catalina.LifecycleListener;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.startup.ContextConfig;
 import org.apache.catalina.startup.Embedded;
+import org.apache.catalina.startup.ExpandWar;
 import org.jboss.arquillian.protocol.servlet_3.ServletMethodExecutor;
 import org.jboss.arquillian.spi.Configuration;
 import org.jboss.arquillian.spi.ContainerMethodExecutor;
@@ -42,8 +46,15 @@
 import org.jboss.shrinkwrap.tomcat.api.ShrinkWrapStandardContext;
 
 /**
- * Arquillian {@link DeployableContainer} adaptor for a target Tomcat
- * environment; responsible for lifecycle and deployment operations
+ * <p>Arquillian {@link DeployableContainer} implementation for an
+ * Embedded Tomcat server; responsible for both lifecycle and deployment
+ * operations.</p>
+ *
+ * <p>Please note that the context path set for the webapp must begin with
+ * a forward slash. Otherwise, certain path operations within Tomcat
+ * will behave inconsistently. Though it goes without saying, the host
+ * name (bindAddress) cannot have a trailing slash for the same
+ * reason.</p>
  * 
  * @author <a href="mailto:jean.deruelle at gmail.com">Jean Deruelle</a>
  * @author Dan Allen
@@ -51,14 +62,14 @@
  */
 public class TomcatContainer implements DeployableContainer
 {
+   private static final Logger log = Logger.getLogger(TomcatContainer.class.getName());
+
    private static final String ENV_VAR = "${env.";
 
    private static final String HTTP_PROTOCOL = "http";
 
-   private static final String SEPARATOR = "/";
+   private static final String TMPDIR_SYS_PROP = "java.io.tmpdir";
 
-   private static final Logger log = Logger.getLogger(TomcatContainer.class.getName());
-
    /**
     * Tomcat embedded
     */
@@ -140,18 +151,19 @@
       }
       if (embedded == null)
       {
-         throw new IllegalStateException("start has not been called!");
+         throw new IllegalStateException("Embedded container is not running");
       }
 
       try
       {
          StandardContext standardContext = archive.as(ShrinkWrapStandardContext.class);
-         standardContext.setParent(standardHost);
-         if (configuration.getTomcatWorkDir() != null)
+         standardContext.addLifecycleListener(new EmbeddedContextConfig());
+         standardContext.setUnpackWAR(configuration.isUnpackArchive());
+         if (standardContext.getUnpackWAR())
          {
-            standardContext.setWorkDir(configuration.getTomcatWorkDir());
+            deleteUnpackedWAR(standardContext);
          }
-         standardContext.setUnpackWAR(configuration.isUnpackArchive());
+
          standardHost.addChild(standardContext);
          context.add(StandardContext.class, standardContext);
       }
@@ -181,6 +193,10 @@
       if (standardContext != null)
       {
          standardHost.removeChild(standardContext);
+         if (standardContext.getUnpackWAR())
+         {
+            deleteUnpackedWAR(standardContext);
+         }
       }
    }
 
@@ -198,11 +214,9 @@
       List<String> remainingDeployments = new ArrayList<String>();
       for (String name : failedUndeployments)
       {
-
          try
          {
             undeploy(name);
-
          }
          catch (Exception e)
          {
@@ -232,47 +246,52 @@
          {
             String sysVar = tomcatHome.substring(ENV_VAR.length(), tomcatHome.length() - 1);
             tomcatHome = System.getProperty(sysVar);
-            tomcatHomeFile = new File(tomcatHome);
-            log.info("Using tomcat home from environment variable: " + tomcatHome);
+            if (tomcatHome != null && tomcatHome.length() > 0 && new File(tomcatHome).isAbsolute())
+            {
+               tomcatHomeFile = new File(tomcatHome);
+               log.info("Using tomcat home from environment variable: " + tomcatHome);
+            }
          }
-         if (tomcatHome != null)
+         else
          {
             tomcatHomeFile = new File(tomcatHome);
-            tomcatHome = tomcatHomeFile.getAbsolutePath();
-            embedded.setCatalinaBase(tomcatHome);
-            embedded.setCatalinaHome(tomcatHome);
          }
-         if (tomcatHomeFile != null)
-         {
-            tomcatHomeFile.mkdirs();
-         }
       }
-      // creates the engine == engine tag in server.xml
+
+      if (tomcatHomeFile == null)
+      {
+         tomcatHomeFile = new File(System.getProperty(TMPDIR_SYS_PROP), "tomcat-embedded-6");
+      }
+
+      tomcatHomeFile.mkdirs();
+      embedded.setCatalinaBase(tomcatHomeFile.getAbsolutePath());
+      embedded.setCatalinaHome(tomcatHomeFile.getAbsolutePath());
+     
+      // creates the engine, i.e., <engine> element in server.xml
       engine = embedded.createEngine();
       engine.setName(serverName);
       engine.setDefaultHost(bindAddress);
       engine.setService(embedded);
       embedded.setContainer(engine);
       embedded.addEngine(engine);
-      // creates the host == host tag in server.xml
-      if (tomcatHomeFile != null)
+      
+      // creates the host, i.e., <host> element in server.xml
+      File appBaseFile = new File(tomcatHomeFile, configuration.getAppBase());
+      appBaseFile.mkdirs();
+      standardHost = embedded.createHost(bindAddress, appBaseFile.getAbsolutePath());
+      if (configuration.getTomcatWorkDir() != null)
       {
-         File appBaseFile = new File(tomcatHomeFile, configuration.getAppBase());
-         appBaseFile.mkdirs();
-         standardHost = embedded.createHost(bindAddress + SEPARATOR, appBaseFile.getAbsolutePath());
+         ((StandardHost) standardHost).setWorkDir(configuration.getTomcatWorkDir());
       }
-      else
-      {
-         standardHost = embedded.createHost(bindAddress + SEPARATOR, System.getProperty("java.io.tmpdir"));
-      }
-      standardHost.setParent(engine);
+      ((StandardHost) standardHost).setUnpackWARs(configuration.isUnpackArchive());
       engine.addChild(standardHost);
-      // creates an http connector == connector in server.xml
-      // TODO externalize this stuff in the configuration
+      
+      // creates an http connector, i.e., <connector> element in server.xml
       Connector connector = embedded.createConnector(InetAddress.getByName(bindAddress), bindPort, false);
       embedded.addConnector(connector);
       connector.setContainer(engine);
-      //starts tomcat embedded
+      
+      // starts embedded tomcat
       embedded.init();
       embedded.start();
       wasStarted = true;
@@ -282,4 +301,17 @@
    {
       embedded.stop();
    }
+
+   /**
+    * Make sure an the unpacked WAR is not left behind
+    * you would think Tomcat would cleanup an unpacked WAR, but it doesn't
+    */
+   protected void deleteUnpackedWAR(StandardContext standardContext)
+   {
+      File unpackDir = new File(standardHost.getAppBase(), standardContext.getPath().substring(1));
+      if (unpackDir.exists())
+      {
+         ExpandWar.deleteDir(unpackDir);
+      }
+   }
 }

Modified: arquillian/trunk/containers/tomcat-embedded-6/src/test/resources/arquillian.xml
===================================================================
--- arquillian/trunk/containers/tomcat-embedded-6/src/test/resources/arquillian.xml	2010-07-11 07:24:24 UTC (rev 4717)
+++ arquillian/trunk/containers/tomcat-embedded-6/src/test/resources/arquillian.xml	2010-07-11 07:27:38 UTC (rev 4718)
@@ -11,12 +11,15 @@
    -->
 
 	<tomcat6:container>
+		<tomcat6:tomcatHome>target/tomcat-embedded-6</tomcat6:tomcatHome>
+      <!-- other options for setting tomcatHome -->
 		<!--tomcat6:tomcatHome>/path/to/apache-tomcat-6.0.20</tomcat6:tomcatHome-->
 		<!--tomcat6:tomcatHome>${env.CATALINA_HOME}</tomcat6:tomcatHome-->
-		<tomcat6:tomcatHome>target/tomcat</tomcat6:tomcatHome>
 		<tomcat6:workDir>work</tomcat6:workDir> 
 		<tomcat6:appBase>webapps</tomcat6:appBase> 
 		<tomcat6:bindHttpPort>8888</tomcat6:bindHttpPort>
+      <!-- unpackArchive must be true if using the Weld Servlet module -->
+		<tomcat6:unpackArchive>true</tomcat6:unpackArchive>
 	</tomcat6:container>
 
 </arquillian>



More information about the jboss-svn-commits mailing list