[CVS spice] Initial version of GroovyJettyContainerBuilder and JUnit test

sjoberg-yCVjj/[email protected] 19 Oct 2005 15:08:05 -0000
Newsgroups gmane.comp.java.spice.cvs
Message-ID <[email protected]>
<html>
<head>
<style><!--
  body {background-color:#ffffff;}
  .file {border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;}
  .pathname {font-family:monospace; float:right;}
  .fileheader {margin-bottom:.5em;}
  .diff {margin:0;}
  .tasklist {padding:4px;border:1px dashed #000000;margin-top:1em;}
  .tasklist ul {margin-top:0;margin-bottom:0;}
  tr.alt {background-color:#eeeeee}
  #added {background-color:#ddffdd;}
  #addedchars {background-color:#99ff99;font-weight:bolder;}
  tr.alt #added {background-color:#ccf7cc;}
  #removed {background-color:#ffdddd;}
  #removedchars {background-color:#ff9999;font-weight:bolder;}
  tr.alt #removed {background-color:#f7cccc;}
  #info {color:#888888;}
  #context {background-color:#eeeeee;}
  td {padding-left:.3em;padding-right:.3em;}
  tr.head {border-bottom-width:1px;border-bottom-style:solid;}
  tr.head td {padding:0;padding-top:.2em;}
  .task {background-color:#ffff00;}
  .comment {padding:4px;border:1px dashed #000000;background-color:#ffffdd}
  .error {color:red;}
  hr {border-width:0px;height:2px;background:black;}
--></style>
</head>
<body>
<table cellspacing="0" cellpadding="0" border="0" rules="cols">
<tr class="head"><td colspan="4">Commit in <b><tt>spice/components/jervlet</tt></b><span id="info"> on MAIN</span></td></tr>
<tr><td><tt>src/java/org/codehaus/spice/jervlet/containers/jetty/pico/<a href="#file1"><span id="added">GroovyJettyContainerBuilder.java</span></a></tt></td><td align="right" id="added">+385</td><td></td><td nowrap="nowrap" align="right">added 1.1</td></tr>
<tr class="alt"><td><tt>src/java/org/codehaus/spice/jervlet/containers/jetty/JettyFilterHolder.java</tt></td><td colspan="2" align="center"><small id="info">[empty]</small></td><td nowrap="nowrap" align="center">1.1 -&gt; 1.2</td></tr>
<tr><td><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/JettyServletHolder.java</tt></td><td colspan="2" align="center"><small id="info">[empty]</small></td><td nowrap="nowrap" align="center">1.1 -&gt; 1.2</td></tr>
<tr class="alt"><td><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/ShieldingJettyContainer.java</tt></td><td colspan="2" align="center"><small id="info">[empty]</small></td><td nowrap="nowrap" align="center">1.1 -&gt; 1.2</td></tr>
<tr><td><tt>src/test/org/codehaus/spice/jervlet/containers/jetty/pico/<a href="#file5"><span id="added">GroovyJettyContainerBuilderTestCase.java</span></a></tt></td><td align="right" id="added">+125</td><td></td><td nowrap="nowrap" align="right">added 1.1</td></tr>
<tr class="alt"><td><tt>project.xml</tt></td><td colspan="2" align="center"><small id="info">[empty]</small></td><td nowrap="nowrap" align="center">1.5 -&gt; 1.6</td></tr>
<tr><td></td><td align="right" id="added">+510</td><td></td><td></td></tr>
</table>
<small id="info">2 added + 4 modified, total 6 files</small><br />
<div class="tasklist"><ul>
<li><a href="#task1">TODO: Sould PicoJettyContainer also implement ContextHandler for a default and open ContextHandler?</a></li>
</ul></div>
<pre class="comment">
Initial version of GroovyJettyContainerBuilder and JUnit test
</pre>
<hr /><a name="file1" /><div class="file">
<span class="pathname" id="added">spice/components/jervlet/src/java/org/codehaus/spice/jervlet/containers/jetty/pico<br /></span>
<div class="fileheader" id="added"><big><b>GroovyJettyContainerBuilder.java</b></big> <small id="info">added at 1.1</small></div>
<pre class="diff"><small id="info">diff -N GroovyJettyContainerBuilder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ GroovyJettyContainerBuilder.java	19 Oct 2005 15:08:04 -0000	1.1
@@ -0,0 +1,385 @@
</small></pre><pre class="diff" id="added">+/*
+ * Copyright (C) The Spice Group. All rights reserved.
+ *
+ * This software is published under the terms of the Spice
+ * Software License version 1.1, a copy of which has been included
+ * with this distribution in the LICENSE.txt file.
+ */
+package org.codehaus.spice.jervlet.containers.jetty.pico;
+
+import groovy.util.BuilderSupport;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.io.File;
+
+import org.codehaus.spice.jervlet.ContextMonitor;
+import org.codehaus.spice.jervlet.ListenerMonitor;
+import org.codehaus.spice.jervlet.Listener;
+import org.codehaus.spice.jervlet.ListenerException;
+import org.codehaus.spice.jervlet.Context;
+import org.codehaus.spice.jervlet.Instantiator;
+import org.codehaus.spice.jervlet.ContextException;
+import org.codehaus.spice.jervlet.impl.DefaultListener;
+import org.codehaus.spice.jervlet.impl.DefaultContext;
+
+/**
+ * Groovy container builder using
+ * &lt;code&gt;PicoJettyContainer&lt;/code&gt; under the hood.
+ *
+ * @author Johan Sjoberg
+ * @author Paul Hammant
+ */
+public class GroovyJettyContainerBuilder extends BuilderSupport
+{
+    public GroovyJettyContainerBuilder()
+    {
+    }
+
+    /**
+     * Set a child object on its parent
+     * &lt;br/&gt;&lt;br/&gt;
+     * Possible parent - child combinations are:
+     * &lt;ul&gt;
+     *  &lt;li&gt;PicoJettyContainer - JettyContainerConfiguration&lt;/li&gt;
+     *  &lt;li&gt;DefaultJettyContainerConfiguration - Properties&lt;/li&gt;
+     *  &lt;li&gt;PicoJettyContainer - Listener&lt;/li&gt;
+     *  &lt;li&gt;PicoJettyContainer - Context&lt;/li&gt;
+     * &lt;/ul&gt;
+     * If a &lt;code&gt;Context&lt;/code&gt; is added as a child to a
+     * &lt;code&gt;PicoJettyContainer&lt;/code&gt; a new &lt;code&gt;ContextHandler&lt;/code&gt;
+     * is created and used for the new context. There is no way of
+     * getting a reference to this context handler again. If access to
+     * the context or context handler is needed, create a new context
+     * handler using a &lt;code&gt;PicoJettyContainer&lt;/code&gt; and deploy contexts
+     * directly to it.
+     *
<a name="task1" />+     * <span class="task">TODO</span>: Sould PicoJettyContainer also implement ContextHandler for a default and open ContextHandler?
+     *
+     * @param object the parent
+     * @param object1 the child
+     */
+    protected void setParent( Object object, Object object1 )
+    {
+        if( object instanceof PicoJettyContainer
+          &amp;&amp; object1 instanceof JettyContainerConfiguration )
+        {
+            PicoJettyContainer container = (PicoJettyContainer)object;
+            DefaultJettyContainerConfiguration configuration =
+              (DefaultJettyContainerConfiguration)object1;
+            container.setConfiguration( configuration );
+        }
+        else if( object instanceof DefaultJettyContainerConfiguration
+          &amp;&amp; object1 instanceof Properties )
+        {
+            Properties property = (Properties)object1;
+            DefaultJettyContainerConfiguration configuration =
+              (DefaultJettyContainerConfiguration)object;
+            if( null == configuration.getProperties() )
+            {
+                configuration.setProperties( property );
+            }
+            else
+            {
+                configuration.getProperties().putAll( property );
+            }
+        }
+        else if( object instanceof PicoJettyContainer
+          &amp;&amp; object1 instanceof Listener )
+        {
+            try
+            {
+                PicoJettyContainer container = (PicoJettyContainer)object;
+                container.initialize();
+                container.addListener( (Listener)object1 );
+            }
+            catch( ListenerException le )
+            {
+                throw new RuntimeException( "The given listener couldn't be added.", le );
+            }
+        }
+        else if( object instanceof PicoJettyContainer
+          &amp;&amp; object1 instanceof Context )
+        {
+            try
+            {
+                PicoJettyContainer container = (PicoJettyContainer)object;
+                container.initialize();
+                container.createContextHandler().addContext( (Context)object1 );
+            }
+            catch( ContextException ce )
+            {
+                throw new RuntimeException( "The given context couldn't be added.", ce );
+            }
+        }
+    }
+
+    /**
+     * Create a new instance of something.
+     *
+     * @param name the command
+     * @return a new instance of some type or null
+     */
+    protected Object createNode( Object name )
+    {
+        return createNode( name, Collections.EMPTY_MAP );
+    }
+
+    /**
+     * Not used
+     *
+     * @param name
+     * @param value
+     * @return null
+     */
+    protected Object createNode( Object name, Object value )
+    {
+        return null;
+    }
+
+    /**
+     * Create a new instance of something.
+     * &lt;br/&gt;&lt;br/&gt;
+     * Possible commands are:
+     * &lt;ul&gt;
+     *  &lt;li&gt;picoJettyContainer&lt;/li&gt;
+     *  &lt;li&gt;configuration&lt;/li&gt;
+     *  &lt;li&gt;parameter&lt;/li&gt;
+     *  &lt;li&gt;listener&lt;/li&gt;
+     *  &lt;li&gt;context&lt;/li&gt;
+     * &lt;/ul&gt;
+     *
+     * @param object the command
+     * @param map parameters
+     * @return a new instance of some type or null
+     */
+    protected Object createNode( Object object, Map map )
+    {
+        if( object instanceof String )
+        {
+            final String command = (String)object;
+            if( "picoJettyContainer".equals( command ) )
+            {
+                return getPicoJettyContainer( map );
+            }
+            else if( "configuration".equals( command ) )
+            {
+                return getConfiguration( map );
+            }
+            else if( "parameter".equals( command ) )
+            {
+                return getParameter( map );
+            }
+            else if( "listener".equals( command ) )
+            {
+                return getListener( map );
+            }
+            else if( "context".equals( command ) )
+            {
+                return getContext( map );
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Not used
+     *
+     * @param name
+     * @param attributes
+     * @param object1
+     * @return null
+     */
+    protected Object createNode( Object name, Map attributes, Object object1 )
+    {
+        return null;
+    }
+
+    /**
+     * Create a PicoJettyContainer
+     * &lt;br/&gt;&lt;br/&gt;
+     * Possible parameters are:
+     * &lt;ul&gt;
+     *  &lt;li&gt;contextMonitor&lt;/li&gt;
+     *  &lt;li&gt;listenerMonitor&lt;/li&gt;
+     * &lt;/ul&gt;
+     * @param map a map of parameters. Used keys are
+     *        &lt;code&gt;contextMonitor&lt;/code&gt; and &lt;code&gt;listenerMonitor&lt;/code&gt;.
+     * @return a new PicoJettyContainer, initialized with the
+     *         optional monitors.
+     */
+    private PicoJettyContainer getPicoJettyContainer( Map map )
+    {
+        ContextMonitor contextMonitor = (ContextMonitor)map.get( "contextMonitor" );
+        ListenerMonitor listenerMonitor = (ListenerMonitor)map.get( "listenerMonitor" );
+        return new PicoJettyContainer( contextMonitor, listenerMonitor );
+    }
+
+    /**
+     * Create a JettyContainerConfiguration
+     *
+     * @param map a map of parameters. Used keys are
+     *        &lt;code&gt;configuration&lt;/code&gt; and &lt;code&gt;configurationURL&lt;/code&gt;.
+     * @return a new instance of a &lt;code&gt;DefaultJettyContainerConfiguration&lt;/code&gt;.
+     * @throws IllegalArgumentException if
+     */
+    private JettyContainerConfiguration getConfiguration( Map map )
+    {
+        if( map.containsKey( "configuration" ) &amp;&amp;
+          map.containsKey( "configurationURL" ) )
+        {
+            throw new IllegalArgumentException( "Either 'configuration' or "
+              + "'configurationURL' can be given. Not both." );
+        }
+        DefaultJettyContainerConfiguration configuration = new DefaultJettyContainerConfiguration();
+        if( map.containsKey( "configuration" ) )
+        {
+            configuration.setConfiguration( map.get( "configuration" ) );
+        }
+        else if( map.containsKey( "configurationURL" ) )
+        {
+            try
+            {
+                URL url = new URL( (String)map.get( "configurationURL" ) );
+                configuration.setConfiguration( url );
+            }
+            catch( MalformedURLException mue )
+            {
+                throw new IllegalArgumentException( "The given URL [" +
+                  map.get( "configurationURL" ) + "] was not well formed. " +
+                  "Error message was [" + mue.getMessage() + "]." );
+            }
+        }
+        return configuration;
+    }
+
+    /**
+     * Fetch a Jetty configuration parameter from a given map
+     *
+     * @param map a map including the keys &lt;code&gt;key&lt;/code&gt;
+     *        and &lt;code&gt;value&lt;/code&gt;.
+     * @return a new Properties instance with one key value pair
+     * @throws IllegalArgumentException if 'key' or 'value' was missing
+     *         in the given map
+     */
+    private Properties getParameter( Map map )
+    {
+        if( !map.containsKey( "key" ) || !map.containsKey( "value" ) )
+        {
+            throw new IllegalArgumentException( "Missing argument. "
+              + "Both 'key' and 'value' are needed." );
+        }
+        Properties properties = new Properties();
+        properties.setProperty( (String)map.get( "key" ), (String)map.get( "value" ) );
+        return properties;
+    }
+
+    /**
+     * Create a listener
+     *
+     * @param map with at least the parameters &lt;code&gt;port&lt;/code&gt;
+     *        and &lt;code&gt;type&lt;/code&gt;. &lt;code&gt;host&lt;/code&gt; is also
+     *        supported.
+     * @return a new &lt;code&gt;DefaultListener&lt;/code&gt; instance
+     */
+    private Listener getListener( Map map )
+    {
+        //System.out.println( "getListener [" + map + "]" );
+        if( !map.containsKey( "port" ) || !map.containsKey( "type" ) )
+        {
+            throw new IllegalArgumentException( "Missing argument. "
+              + "At least 'port' and 'type' must be given." );
+        }
+        int type = -1;
+        final String typeString = (String)map.get( "type" );
+        if( typeString.equalsIgnoreCase( "http" ) )
+        {
+            type = Listener.HTTP;
+        }
+        else if( typeString.equalsIgnoreCase( "tsl") || typeString.equalsIgnoreCase( "ssl" ) )
+        {
+            type = Listener.TSL;
+        }
+        else if( typeString.equalsIgnoreCase( "ajp13" ) )
+        {
+            type = Listener.AJP13;
+        }
+        if( -1 == type )
+        {
+            throw new IllegalArgumentException( "Unknown listener type [" +
+              typeString + "]." );
+        }
+        return new DefaultListener( (String)map.get( "host" ),
+                                    Integer.parseInt( (String)map.get( "port" ) ),
+                                    type );
+    }
+
+    /**
+     * Create a context
+     *
+     * @param map map of needed arguments
+     * @return a new context
+     * @throws IllegalArgumentException if a mandatory
+     *         parameter was missing in the given map
+     *         or if the parameters had errors
+     */
+    private Context getContext( Map map )
+    {
+        if( !map.containsKey( "webPath" ) ||
+            !map.containsKey( "warPath" ) ||
+            !map.containsKey( "instantiator" ) )
+        {
+            throw new IllegalArgumentException( "Missing argument. At least" +
+              " 'instantiator', 'webPath' and 'warPath' must be given." );
+        }
+        String webPath = (String)map.get( "webPath" );
+        String[] hosts = getHosts( (String)map.get( "hosts" ) );
+        URL resource;
+        boolean extractWar = false;
+        Instantiator instantiator = (Instantiator)map.get( "instantiator" );
+        try
+        {
+            File resourceFile = new File( (String)map.get( "warPath" ) );
+            if( !resourceFile.exists() )
+            {
+                throw new IllegalArgumentException( "File [" +
+                  map.get( "warParh" ) + "] given in parameter 'warPath' doesn't exist." );
+            }
+            resource = resourceFile.toURL();
+        }
+        catch( MalformedURLException mue )
+        {
+            throw new IllegalArgumentException( "Couldn't translate parameter "
+              + "'warPath' into a URL. Message was [" + mue.getMessage() + "]." );
+        }
+        return new DefaultContext( webPath,
+                                   hosts,
+                                   resource,
+                                   extractWar,
+                                   instantiator );
+    }
+
+    /**
+     * Create an array from the ',' separated host list.
+     *
+     * @param hostString the string to split up
+     * @return a new string array or null
+     */
+    private String[] getHosts( final String hostString )
+    {
+        if( null == hostString || "".equals( hostString ) )
+        {
+            return null;
+        }
+        String[] hosts = hostString.split( "," );
+        for( int i = 0; i &lt; hosts.length; i++ )
+        {
+            hosts[i] = hosts[i].trim();
+            System.out.println( hosts[i] );
+        }
+        return hosts;
+    }
+}
</pre><pre class="diff"><small id="info">\ No newline at end of file
</small></pre></div>
<hr /><a name="file5" /><div class="file">
<span class="pathname" id="added">spice/components/jervlet/src/test/org/codehaus/spice/jervlet/containers/jetty/pico<br /></span>
<div class="fileheader" id="added"><big><b>GroovyJettyContainerBuilderTestCase.java</b></big> <small id="info">added at 1.1</small></div>
<pre class="diff"><small id="info">diff -N GroovyJettyContainerBuilderTestCase.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ GroovyJettyContainerBuilderTestCase.java	19 Oct 2005 15:08:04 -0000	1.1
@@ -0,0 +1,125 @@
</small></pre><pre class="diff" id="added">+/*
+ * Copyright (C) The Spice Group. All rights reserved.
+ *
+ * This software is published under the terms of the Spice
+ * Software License version 1.1, a copy of which has been included
+ * with this distribution in the LICENSE.txt file.
+ */
+package org.codehaus.spice.jervlet.containers.jetty.pico;
+
+import junit.framework.TestCase;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.Script;
+import groovy.lang.Binding;
+
+/**
+ * Test cases for &lt;code&gt;GroovyJettyContainerBuilder&lt;/code&gt;
+ *
+ * @author Johan Sjoberg
+ * @author Paul Hammant
+ */
+public class GroovyJettyContainerBuilderTestCase extends TestCase
+{
+    private static final String m_jettyConfiguration =
+      "../../testdata/jetty/jetty.xml";
+    private static final String m_plainWebapp =
+      "../../testdata/webapps/plain";
+    private static final String m_plainWebappWAR =
+      "../../testdata/webapps/plain.war";
+    private static final String m_picoWebapp =
+      "../../testdata/webapps/pico";
+
+    /**
+     * Test various parts of &lt;code&gt;GroovyJettyContainerBuilder&lt;/code&gt;
+     *
+     * @throws CompilationFailedException if the groovy script couldn't be compiled
+     */
+    public void testContainerBuilder() throws CompilationFailedException
+    {
+        final Reader script = new StringReader(
+          "package org.codehaus.spice.jervlet.containers.jetty.pico\n" +
+          "import org.picocontainer.defaults.DefaultPicoContainer\n" +
+          "import org.codehaus.spice.jervlet.containers.jetty.pico.GroovyJettyContainerBuilder\n" +
+          "import org.codehaus.spice.jervlet.containers.jetty.pico.PicoJettyContainer\n" +
+          "import org.codehaus.spice.jervlet.impl.pico.PicoInstantiator\n" +
+          "import org.codehaus.spice.jervlet.impl.Pinger\n" +
+          "import org.codehaus.spice.jervlet.impl.DefaultContext\n" +
+          "import org.codehaus.spice.jervlet.impl.SystemOutContextMonitor\n" +
+          "import org.codehaus.spice.jervlet.impl.NoopListenerMonitor\n" +
+
+          "def pico = new DefaultPicoContainer()\n" +
+          "def pinger = new Pinger()\n" +
+          "pinger.ping( '' +  System.currentTimeMillis() )\n" +
+          "pico.registerComponentInstance( pinger )\n" +
+          "def builder = new GroovyJettyContainerBuilder()\n" +
+          "def instantiator = new PicoInstantiator( pico )\n" +
+          "def contextMonitor = new SystemOutContextMonitor()\n" +
+          "def listenerMonitor = new NoopListenerMonitor()\n" +
+
+          "def webServer = builder.picoJettyContainer( contextMonitor:contextMonitor, listenerMonitor:listenerMonitor )\n" +
+          "{\n" +
+              "configuration( configuration:'" + m_jettyConfiguration + "' )\n" +
+              "{\n" +
+                  "parameter( key:'jetty.port', value:'16842' )\n" +
+              "}\n" +
+              "listener( port:'16843', type:'http' )\n" +
+              "listener( port:'16844', type:'ajp13' )\n" +
+              "context( webPath:'pico1', warPath:'" + m_picoWebapp + "', extractWar:false, instantiator:instantiator, hosts:'localhost' )\n" +
+          "}\n" +
+
+          "def contextHandler = webServer.createContextHandler()\n" +
+          "def context2 = builder.context( webPath:'pico2',\n" +
+                                          "warPath:'" + m_picoWebapp + "',\n" +
+                                          "extractWar:false,\n" +
+                                          "instantiator:instantiator,\n" +
+                                          "hosts:'localhost, 127.0.0.1' )\n" +
+          "contextHandler.addContext( context2 )\n" +
+
+          "webServer.start()\n" +
+
+          "def context3 = builder.context( webPath:'pico3', warPath:'" + m_picoWebapp + "', extractWar:false, instantiator:instantiator )\n" +
+          "contextHandler.addContext( context3 )\n" +
+          "contextHandler.startContext( context3 )\n" +
+          "contextHandler.stopContext( context3 )\n" +
+          "contextHandler.removeContext( context3 )\n" +
+
+          "webServer.stop()" );
+
+        doGroovy( new InputStream()
+                      {
+                          public int read() throws IOException
+                          {
+                             return script.read();
+                          }
+                      } );
+        assertEquals( "", "" );
+    }
+
+    /**
+     * Run a groovy script
+     *
+     * @param is the input stream holding the script
+     * @throws CompilationFailedException if the script couldn't be compiled
+     */
+    protected void doGroovy( InputStream is ) throws CompilationFailedException
+    {
+        GroovyClassLoader loader = new GroovyClassLoader( getClass().getClassLoader() );
+        GroovyCodeSource groovyCodeSource = new GroovyCodeSource(
+          is,"nanocontainer.groovy", "groovyGeneratedForNanoContainer" );
+        Class scriptClass = loader.parseClass( groovyCodeSource );
+        Script groovyScript = InvokerHelper.createScript( scriptClass, null );
+        Binding binding = new Binding();
+        groovyScript.setBinding( binding );
+        groovyScript.run();
+    }
+}
</pre></div>
<center><small><a href="http://www.badgers-in-foil.co.uk/projects/cvsspam/" title="commit -&gt; email">CVSspam</a> 0.2.8</small></center>
</body></html>