[jervlet-patch] Make Jervlet-Jetty accept external configurations

Johan Sjöberg <johan.sjoberg-KK16lzWueydWk0Htik3J/[email protected]> Tue, 11 Nov 2003 09:18:26 +0200
Newsgroups gmane.comp.java.spice.devel
Message-ID <[email protected]>
Hi!

Here is the first patchset to make Jetty-Jervlet accept external 
configurations.

This has been done so far:

-Addition of two new Jetty Server creators
-Configuration logic added to AvalonJettyJervlet to except external 
configurations
-Addition of a new AvalonJettyJervlet configuration schema (was missing!)
-Addition of an example configuration file
-Possibility to set the system parameter "jetty.home" (can be considered 
bad by some)
-Small cleanups to the tops of AbstractJettyJervlet and 
AvalonJettyJervlet plus fixes to other files that these broke.
-demoserver now uses AvalonJettyJervlet instead of JettyJervlet
-Minimal tests of AvalonJettyJervlet in Loom-current and a slightly 
older version.


Theoretically nothing in PicoJettyJervlet should be broken and 
demoserver now seems to work again. Next I would like to:

-Make the log redirecting and access logging configurable in 
AvalonJettyJervlet
-Remove JettyJervlet (that only extends AvalonJettyJervlet) and its 
configuration schema
-Change demoserver (alt create new module) to be more release like for 
the avalon/loom release already now. This means a new name, and empty 
documented configuration files, etc. Otherwise very close to demoserver.
-Change the configuration in AvalonJervletJetty to take something like:
<socketlisteners>
   <socketlistener>
      <host/>
      <port/>
      <maxthreads/>
      <minthreads/>
   </socketlistener>
</socketlisteners>
instead of all those in the root level. This way many listeners could be 
added to a Jetty Server.
-Set the default port (8080) in AvalonJervletJetty to -1.
-Clean up some parts of the code according to some standard (what should 
be used btw?)


Could someone give some input on this?


Cheers,

//
Johan
AbstractJettyJervlet.java.patch (text/plain, 3.3 KB)
Index: sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AbstractJettyJervlet.java
===================================================================
RCS file: /cvsroot/spice/spice/sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AbstractJettyJervlet.java,v
retrieving revision 1.1
diff -u -r1.1 AbstractJettyJervlet.java
--- sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AbstractJettyJervlet.java	6 Nov 2003 20:25:46 -0000	1.1
+++ sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AbstractJettyJervlet.java	11 Nov 2003 06:35:00 -0000
@@ -3,38 +3,84 @@
 import org.mortbay.jetty.Server;
 import org.mortbay.http.SocketListener;
 import org.mortbay.util.MultiException;
+import org.mortbay.xml.XmlConfiguration;
+
 import org.jcomponent.jervlet.JervletConfig;
 import org.jcomponent.jervlet.JervletException;
+
 import org.apache.avalon.framework.CascadingRuntimeException;
 
+import org.xml.sax.SAXException;
+
 import java.net.UnknownHostException;
 import java.util.HashMap;
+import java.io.IOException;
 
-public class AbstractJettyJervlet {
-
-    protected JervletConfig config;
+public class AbstractJettyJervlet
+{
+    protected JervletConfig m_config;
     protected Server m_server;
     protected HashMap m_webcontexts = new HashMap();
 
+
+    /**
+     * Create a new Jetty HTTP server
+     */
     protected final Server createHttpServer()
     {
         return new Server();
     }
 
+
+    /**
+     * Create a new Jetty HTTP server from a Jetty configuration file.
+     *
+     * @param filename The URL or name of the configuration file.
+     * @throws IOException if the configuration file couldn't be read.
+     */
+    protected final Server createHttpServerFromFile( final String filename ) throws IOException
+    {
+        return new Server( filename );
+    }
+
+
+    /**
+     * Create a new Jetty HTTP server from a Jetty XML configuration.
+     *
+     * @param xmlConfiguration A String of Jetty XML configuration commands
+     *        excluding the normal XML preamble. The String should start with
+     *        a "<Configure ...." element.
+     * @throws Exception if any problems occur
+     */
+    protected final Server createHttpServerFromConfiguration( final String xmlConfiguration )
+      throws Exception
+    {
+        try
+        {
+            return (Server) new XmlConfiguration( xmlConfiguration ).newInstance();
+        }
+        catch( Exception e )
+        {
+            throw e;
+        }
+    }
+
+
     protected final SocketListener createSocketListener() throws UnknownHostException
     {
         SocketListener listener = new SocketListener();
 
-        if( null != config.getHostName() )
+        if( null != m_config.getHostName() )
         {
-            listener.setHost( config.getHostName() );
+            listener.setHost( m_config.getHostName() );
         }
 
-        listener.setPort( config.getPort() );
-        listener.setMinThreads( config.getMinThreads() );
-        listener.setMaxThreads( config.getMaxThreads() );
+        listener.setPort( m_config.getPort() );
+        listener.setMinThreads( m_config.getMinThreads() );
+        listener.setMaxThreads( m_config.getMaxThreads() );
         return listener;
     }
+
 
     /**
      * Start
assembly.xml.patch (text/plain, 823 B)
Index: sandbox/jervlet/demoserver/src/conf/assembly.xml
===================================================================
RCS file: /cvsroot/spice/spice/sandbox/jervlet/demoserver/src/conf/assembly.xml,v
retrieving revision 1.1
diff -u -r1.1 assembly.xml
--- sandbox/jervlet/demoserver/src/conf/assembly.xml	28 Oct 2003 05:07:36 -0000	1.1
+++ sandbox/jervlet/demoserver/src/conf/assembly.xml	11 Nov 2003 06:32:14 -0000
@@ -3,7 +3,7 @@
 	<block name="jervlet-jetty-logger"
 		   class="org.jcomponent.jervlet.blocks.jetty.NullRequestLogger"/>
 	<block name="jervlet-jetty"
-		   class="org.jcomponent.jervlet.blocks.jetty.JettyJervlet">
+		   class="org.jcomponent.jervlet.blocks.jetty.AvalonJettyJervlet">
 	   <provide
 	   		name="jervlet-jetty-logger"
 	   		role="org.jcomponent.jervlet.blocks.jetty.RequestLogger"/>
AvalonJettyJervlet.java.patch (text/plain, 9.5 KB)
Index: sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AvalonJettyJervlet.java
===================================================================
RCS file: /cvsroot/spice/spice/sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AvalonJettyJervlet.java,v
retrieving revision 1.2
diff -u -r1.2 AvalonJettyJervlet.java
--- sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AvalonJettyJervlet.java	6 Nov 2003 22:06:03 -0000	1.2
+++ sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/AvalonJettyJervlet.java	11 Nov 2003 06:36:43 -0000
@@ -54,6 +54,7 @@
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfigurationSerializer;
 import org.apache.avalon.framework.context.Context;
 import org.apache.avalon.framework.context.ContextException;
 import org.apache.avalon.framework.context.Contextualizable;
@@ -88,23 +89,43 @@
 public class AvalonJettyJervlet extends AbstractJettyJervlet
     implements Jervlet, Startable, Contextualizable, Configurable, Initializable, Serviceable, LogEnabled
 {
+    private final static String c_appHome = "${app-home}";
+
+    /** Jetty's configuration */
+    private String m_jettyConfiguration;
+
+    /** Jetty's configuration file */
+    private String m_jettyConfFile;
 
     private File m_sarRootDir;
     private AvalonJervletContext m_jervletContext;
     private Context m_context;
     private Logger m_logger;
 
-    public void enableLogging(Logger logger) {
+
+    /**
+     * Get the Avalon logger
+     */
+    public void enableLogging( Logger logger )
+    {
         m_logger = logger;
     }
 
-    protected Logger getLogger() {
+
+    /**
+     * Fetch the logger
+     */
+    protected Logger getLogger()
+    {
         return m_logger;
     }
 
+
     /**
+     * Get the Avalon service manager
+     *
      * @param serviceManager
-     * @throws ServiceException
+     * @throws ServiceException if any problems occur
      *
      * @phoenix:dependency name="org.jcomponent.jervlet.blocks.jetty.RequestLogger"
      */
@@ -113,8 +134,10 @@
         m_jervletContext = new AvalonJervletContext( m_context, serviceManager, getLogger() );
     }
 
+
     /**
-     * Contextualize
+     * Contextualize the component
+     *
      * @param context the context
      */
     public void contextualize( final Context context ) throws ContextException
@@ -123,37 +146,117 @@
         m_sarRootDir = (File)context.get( "app.home" );
     }
 
+
     /**
-     * Configure
+     * Configure the compoenent
+     *
      * @param configuration the configuration
-     * @throws ConfigurationException if a problem
+     * @throws ConfigurationException if any problems occur
      *
      * @phoenix:configuration-schema type="http://relaxng.org/ns/structure/1.0"
      */
     public void configure( final Configuration configuration ) throws ConfigurationException
     {
         JervletConfigBean config = new JervletConfigBean();
-
-        config.setHostName(configuration.getChild( "hostname" ).getValue( null ));
-        config.setPort(configuration.getChild( "port" ).getValueAsInteger( 8080 ));
-        config.setMinThreads(configuration.getChild( "minthreads" ).getValueAsInteger( 5 ));
-        config.setMaxThreads(configuration.getChild( "maxthreads" ).getValueAsInteger( 250 ));
-        config.setExtractWarFile(configuration.getChild( "extract-war" ).getValueAsBoolean( true ));
-
+        config.setHostName( configuration.getChild( "hostname" ).getValue( null ) );
+        config.setPort( configuration.getChild( "port" ).getValueAsInteger( 8080 ) );
+        config.setMinThreads( configuration.getChild( "minthreads" ).getValueAsInteger( 5 ) );
+        config.setMaxThreads( configuration.getChild( "maxthreads" ).getValueAsInteger( 250 ) );
+        config.setExtractWarFile( configuration.getChild( "extract-war" )
+          .getValueAsBoolean( true ) );
         if( config.getMaxThreads() < config.getMinThreads() )
         {
             throw new ConfigurationException( "maxthreads must be greater than minthreads" );
         }
+        m_config = config;
+
+        m_jettyConfFile = configuration.getChild( "jetty-config-file" ).getValue( null );
+        if( null != m_jettyConfFile )
+        {
+            getLogger().info( "Configurating Jetty from file [" + m_jettyConfFile + "]." );
+            if( m_jettyConfFile.startsWith( c_appHome ) )
+            {
+                m_jettyConfFile = m_sarRootDir.getAbsolutePath() +
+                  m_jettyConfFile.substring( c_appHome.length() );
+            }
+            if( m_jettyConfFile.startsWith( c_appHome ) )
+            {
+                m_jettyConfFile = m_jettyConfFile.substring( c_appHome.length() );
+            }
+            m_jettyConfFile = m_jettyConfFile.replace( '\\', File.separatorChar );
+            m_jettyConfFile = m_jettyConfFile.replace( '/', File.separatorChar );
+        }
+        else
+        {
+            m_jettyConfiguration = configuration.getChild( "jetty-config" ).getValue( null );
+            if( null == m_jettyConfiguration )
+            {
+                Configuration jettyConf = configuration.getChild( "jetty-config" )
+                  .getChild( "Configure", false );
+                if( null != jettyConf )
+                {
+                    try
+                    {
+                        DefaultConfigurationSerializer serializer =
+                          new DefaultConfigurationSerializer();
+                        m_jettyConfiguration =  serializer.serialize( jettyConf );
+                    }
+                    catch( Exception e )
+                    {
+                        final String message = "Serialization of Jetty's configuration failed.";
+                        getLogger().error( message, e );
+                        throw new ConfigurationException( message, e );
+                    }
+                }
+            }
+            if( null != m_jettyConfiguration )
+            {
+                getLogger().info( "Configurating Jetty from component configuration." );
+                if( m_jettyConfiguration.indexOf ("?>") >= 0 )
+                {
+                    m_jettyConfiguration = m_jettyConfiguration.substring(
+                      m_jettyConfiguration.indexOf ("?>") + 2 );
+                }
+            }
+        }
+
+        String jettyHome = configuration.getChild( "jetty-home" ).getValue( "" );
+        if( !"".equals( jettyHome ) )
+        {
+            if( jettyHome.startsWith( c_appHome ) )
+            {
+                jettyHome = m_sarRootDir.getAbsolutePath()
+                  + jettyHome.substring( c_appHome.length() );
+            }
+            getLogger().info( "Setting system property 'jetty.home' to [" + jettyHome + "]." );
+            System.setProperty( "jetty.home", jettyHome );
+        }
     }
 
+
     /**
      * Initialize
-     * @throws Exception if a problem
+     * @throws Exception if any problems occur
      */
     public void initialize() throws Exception
     {
-        m_server = createHttpServer();
-        m_server.addListener( createSocketListener() );
+        if( null != m_jettyConfiguration && !"".equals( m_jettyConfiguration ) )
+        {
+             m_server = createHttpServerFromConfiguration( m_jettyConfiguration );
+        }
+        else if( null != m_jettyConfFile && !"".equals( m_jettyConfFile ) )
+        {
+             m_server = createHttpServerFromFile( m_jettyConfFile );
+        }
+        else
+        {
+            m_server = createHttpServer();
+        }
+
+        if( m_config.getPort() > 0 )
+        {
+            m_server.addListener( createSocketListener() );
+        }
 
         AvalonLogSink logSink = new AvalonLogSink();
         logSink.enableLogging( getLogger() );
@@ -161,8 +264,8 @@
         // unsatisfactory as is static
         Log.instance().add( logSink );
 
-        RequestLogger logger = (RequestLogger)
-            m_jervletContext.getServiceManager().lookup( RequestLogger.ROLE );
+        RequestLogger logger = ( RequestLogger )m_jervletContext.getServiceManager()
+         .lookup( RequestLogger.ROLE );
         m_server.setRequestLog( new JettyRequestLogAdapter( logger ) );
     }
 
@@ -201,7 +304,7 @@
                                                       pathToWebAppFolder,
                                                       jervletContext,
                                                       m_sarRootDir,
-                                                      config.getExtractWarFile() );
+                                                      m_config.getExtractWarFile() );
             m_webcontexts.put( context, holder );
         }
         catch( Exception e )
@@ -332,12 +435,13 @@
 
         try
         {
-            m_server.addContext( config.getHostName(), holder.create() );
+            m_server.addContext( m_config.getHostName(), holder.create() );
 
             if( getLogger().isInfoEnabled() )
                 getLogger().info( "deploying context=" + context + ", webapp="
                                   + holder.getWebappUrl() + " to host="
-                                  + ( config.getHostName() == null ? "(All Hosts)" : config.getHostName() ) );
+                                  + ( m_config.getHostName() == null ? "(All Hosts)" :
+                                    m_config.getHostName() ) );
 
             holder.start();
         }
AvalonJettyJervlet-schema.xml (text/xml, 1 KB)
<?xml version="1.0"?>
<element name="root" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <interleave>
    <optional>
      <element name="hostname">
        <text/>
      </element>
    </optional>
    <optional>
      <element name="port">
        <data type="integer"/>
      </element>
    </optional>
    <optional>
      <element name="minthreads">
        <data type="integer"/>
      </element>
    </optional>
    <optional>
      <element name="maxthreads">
        <data type="integer"/>
      </element>
    </optional>
    <optional>
      <element name="extract-war">
        <data type="boolean"/>
      </element>
    </optional>
    <optional>
      <element name="jetty-config-file">
        <text/>
      </element>
    </optional>
    <optional>
      <element name="jetty-config">
        <text/>
      </element>
    </optional>
    <optional>
      <element name="jetty-home">
        <text/>
      </element>
    </optional>
  </interleave>
</element>
BeanJettyJervlet.java.patch (text/plain, 2.1 KB)
Index: sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/BeanJettyJervlet.java
===================================================================
RCS file: /cvsroot/spice/spice/sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/BeanJettyJervlet.java,v
retrieving revision 1.2
diff -u -r1.2 BeanJettyJervlet.java
--- sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/BeanJettyJervlet.java	6 Nov 2003 22:06:03 -0000	1.2
+++ sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/BeanJettyJervlet.java	11 Nov 2003 06:37:58 -0000
@@ -89,7 +89,7 @@
     private LogSink logSink;
 
     public void setJervletConfig(JervletConfig config) {
-        super.config = config;
+        super.m_config = config;
     }
 
     public void setRequestLogger(RequestLogger requestLogger) {
@@ -160,7 +160,7 @@
                                                       pathToWebAppFolder,
                                                       jervletContext,
                                                       appRootDir,
-                                                      config.getExtractWarFile() );
+                                                      m_config.getExtractWarFile() );
             m_webcontexts.put( context, holder );
         }
         catch( Exception e )
@@ -283,16 +283,16 @@
 
         try
         {
-            m_server.addContext( config.getHostName(), holder.create() );
+            m_server.addContext( m_config.getHostName(), holder.create() );
 
-            monitor.deployingContext(this.getClass(), context, holder.getWebappUrl(), config.getHostName());
+            monitor.deployingContext(this.getClass(), context, holder.getWebappUrl(), m_config.getHostName());
 
             holder.start();
         }
         catch( Exception e )
         {
 
-            monitor.deployingException(this.getClass(), context, holder.getWebappUrl(), config.getHostName(), e);
+            monitor.deployingException(this.getClass(), context, holder.getWebappUrl(), m_config.getHostName(), e);
 
         }
     }
config.xml (text/xml, 2.7 KB)
<?xml version="1.0"?>
<config>
  <jervlet-jetty>
    <!--
         HTTP server host

         Jetty managed web applications will be deployed to this virtual
         host. If it doesn't exist or is left empty the applications will
         be deployed to all existing hosts. The default is null (all hosts).
     -->
    <!--<hostname>localhost</hostname>-->

    <!--
         HTTP server port

         The port to bind the HTTP server to. If no port is defined it is
         assumed that the port or ports are configured in the Jetty
         configuration file. The default is 8080. If you use external
         Jetty configurations, don't configure the same port twice.
     -->
    <!--<port>8080</port>-->

    <!--
         HTTP server Min threads

         Minimum amount of threads for the HTTP server. The default is 5.
     -->
    <!--<minthreads>5</minthreads>-->

    <!--
         HTTP server Max threads

         Maximum amount of threads for the HTTP server. The default is 250.
     -->
    <!--<maxthreads>250</maxthreads>-->

    <!--
         Extract war files

         Define if Jetty managed Web Application Archives should be extracted.
		 The default is true.
     -->
    <!--<extract-war>true</extract-war>-->

    <!--
         Jetty's home directory

         Configure Jetty's home directory.  This is useful if Jetty's original
         configuration files are used. If the value begins with "${app-home}",
         it will be prefixed with this components's home directory.
     -->
    <!--<jetty-home>${app-home}</jetty-home>-->

    <!--
         Jetty's configuration file

         Include an external Jetty configuration file. This file must follow
         Jetty's own configuration format. If the configuration file begins with
         "${app-home}", it will be prefixed with this component's home directory.
         Note that web archives and archive directories defined in Jetty's own
         configuration will not be handled by Jervlet.
     -->
    <!--<jetty-config-file>${app-home}/etc/jetty.xml</jetty-config-file>-->

    <!--
         Jetty's configuration

         If no jetty-config-file element exists, Jetty can be configured with
         an external configuration inside the following element. Note that the
         configuration always begins with a <Configure> element and must follow
         Jetty's own configuration format. In case it includes nested XML data
         you will have to wrap the configuration within a <![CDATA[ ..... ]]>
         element. Also note that web archives and archive directories defined
         in Jetty's own configuration will not be handled by Jervlet.
     -->
    <!--<jetty-config></jetty-config>-->
  </jervlet-jetty>
</config>
PicoJettyJervlet.java.patch (text/plain, 2.5 KB)
Index: sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/PicoJettyJervlet.java
===================================================================
RCS file: /cvsroot/spice/spice/sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/PicoJettyJervlet.java,v
retrieving revision 1.3
diff -u -r1.3 PicoJettyJervlet.java
--- sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/PicoJettyJervlet.java	6 Nov 2003 22:06:03 -0000	1.3
+++ sandbox/jervlet/jervlet-jetty/src/java/org/jcomponent/jervlet/blocks/jetty/PicoJettyJervlet.java	11 Nov 2003 06:39:47 -0000
@@ -93,7 +93,7 @@
     public PicoJettyJervlet(JervletConfig config, JervletMonitor monitor, MutablePicoContainer parentContainer,
                             File appRootDir, RequestLogger requestLogger,
                             LogSink logSink) throws UnknownHostException {
-        super.config = config;
+        super.m_config = config;
         this.monitor = monitor;
         this.appRootDir = appRootDir;
         this.logSink = logSink;
@@ -146,7 +146,7 @@
                                                       pathToWebAppFolder,
                                                       jervletContext,
                                                       appRootDir,
-                                                      config.getExtractWarFile() );
+                                                      m_config.getExtractWarFile() );
             m_webcontexts.put( context, holder );
         }
         catch( Exception e )
@@ -266,20 +266,17 @@
 
         //Set the context classloader because the current classloader will be that of the
         Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
-
         try
         {
-            m_server.addContext( config.getHostName(), holder.create() );
-
-            monitor.deployingContext(this.getClass(), context, holder.getWebappUrl(), config.getHostName());
-
+            m_server.addContext( m_config.getHostName(), holder.create() );
+            monitor.deployingContext( this.getClass(), context, holder.getWebappUrl(),
+              m_config.getHostName() );
             holder.start();
         }
         catch( Exception e )
         {
-
-            monitor.deployingException(this.getClass(), context, holder.getWebappUrl(), config.getHostName(), e);
-
+            monitor.deployingException(this.getClass(), context, holder.getWebappUrl(),
+              m_config.getHostName(), e);
         }
     }