adammurdoch    02/04/03 02:58:20

  Modified:    proposal/myrmidon build.xml
               proposal/myrmidon/docs todo.html
               
proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader
                        DefaultClassLoaderManager.java Resources.properties
               
proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer
                        DefaultDeployer.java
               
proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor
                        DefaultEmbeddor.java Resources.properties
               
proposal/myrmidon/src/java/org/apache/myrmidon/components/extensions
                        DefaultExtensionManager.java
               proposal/myrmidon/src/java/org/apache/myrmidon/frontends
                        CLIMain.java EmbeddedAnt.java Resources.properties
               
proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/classloader
                        ClassLoaderManager.java
               
proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/extensions
                        ExtensionManager.java
               proposal/myrmidon/src/test/org/apache/myrmidon
                        AbstractMyrmidonTest.java AbstractProjectTest.java
               proposal/myrmidon/src/test/org/apache/myrmidon/components
                        AbstractComponentTest.java
               
proposal/myrmidon/src/test/org/apache/myrmidon/components/embeddor/test
                        DefaultEmbeddorTest.java
               proposal/myrmidon/src/xdocs todo.xml
  Added:       
proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader
                        MultiParentURLClassLoader.java
               
proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test
                        DefaultClassLoaderManagerTestCase.java
               
proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs
                        cycle-extension-1.mf cycle-extension-2.mf
                        one-dependency.mf simple-extension.mf
               
proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/extn
                        ExtnClass.java extn.txt
               
proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/shared
                        SharedClass.java shared.txt
               
proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/unshared
                        UnsharedClass.java unshared.txt
  Log:
  ClassLoader hierarchy changes:
  
  * Use multi-parent ClassLoaders for antlibs and extensions, so that each
    extension jar is loaded by a single ClassLoader in the hierarchy.  Allows
    classes from extensions to be shared across dependent antlibs and 
extensions.
  
  * Changed contract of ClassLoaderManager.createClassLoader( File[] ), so that
    it creates a new ClassLoader each time it is called.
  
  * Changed ExtensionManager, so that it no longer extends PackageRepository.
  
  * Added a few test cases for DefaultClassLoaderManager.
  
  * Moved responsibility for checking myrmidon.home and building the various 
paths,
    from DefaultEmbeddor and DefaultExtensionManager to EmbeddedAnt.  Use the
    platform path separator for the paths, rather than the | char.
  
  * Use EmbeddedAnt in AbstractProjectTest, rather than using an Embeddor 
directly.
  
  * AbstractComponentTest was not parameterising or initialising the test
    components.
  
  Revision  Changes    Path
  1.102     +56 -1     jakarta-ant/proposal/myrmidon/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/build.xml,v
  retrieving revision 1.101
  retrieving revision 1.102
  diff -u -r1.101 -r1.102
  --- build.xml 2 Apr 2002 12:06:37 -0000       1.101
  +++ build.xml 3 Apr 2002 10:58:18 -0000       1.102
  @@ -67,6 +67,7 @@
       <property name="test.dir" value="${build.dir}/test"/>
       <property name="test.working.dir" value="${test.dir}/test"/>
       <property name="test.classes" value="${test.dir}/classes"/>
  +    <property name="test.fork" value="true"/>
   
       <property name="constants.file" 
value="org/apache/myrmidon/Constants.java"/>
   
  @@ -544,6 +545,9 @@
   
       <!-- Compiles and runs the unit tests -->
       <target name="run-tests" depends="dist-lite" if="junit.present">
  +
  +        <property name="test.classloader.pkg" 
value="org/apache/myrmidon/components/classloader/test/libs"/>
  +
           <!-- Compile the unit tests -->
           <mkdir dir="${test.classes}"/>
           <javac srcdir="src/test"
  @@ -558,6 +562,7 @@
   
               <exclude name="**/SmbFileSystemTestCase.java" 
unless="jcifs.present"/>
               <exclude name="**/FtpFileSystemTestCase.java" 
unless="netcomp.present"/>
  +            <exclude name="${test.classloader.pkg}/**"/>
           </javac>
   
           <!-- Prepare test files -->
  @@ -602,6 +607,56 @@
               <fileset dir="${test.classes}" 
includes="org/apache/myrmidon/interfaces/type/test/MyType1.class"/>
           </jar>
   
  +        <!-- Prepare the class loader manager tests -->
  +        <property name="test.classloader.dir" 
value="${test.working.dir}/${test.classloader.pkg}/.."/>
  +        <property name="test.classloader.classes" 
value="${test.dir}/classloader"/>
  +        <mkdir dir="${test.classloader.dir}"/>
  +        <mkdir dir="${test.classloader.dir}/ext"/>
  +        <mkdir dir="${test.classloader.classes}"/>
  +        <javac srcdir="src/test"
  +            destdir="${test.classloader.classes}"
  +            debug="${debug}"
  +            deprecation="${deprecation}">
  +            <include name="${test.classloader.pkg}/**"/>
  +        </javac>
  +        <copy todir="${test.classloader.classes}">
  +            <fileset dir="src/test">
  +                <include name="${test.classloader.pkg}/**"/>
  +                <exclude name="**/*.java"/>
  +            </fileset>
  +        </copy>
  +        <jar jarfile="${test.classloader.dir}/common.jar">
  +            <fileset dir="${test.classloader.classes}">
  +                <include name="**/shared/**"/>
  +            </fileset>
  +        </jar>
  +        <jar jarfile="${test.classloader.dir}/no-dependencies.jar">
  +            <fileset dir="${test.classloader.classes}">
  +                <include name="**/shared/**"/>
  +                <include name="**/unshared/**"/>
  +            </fileset>
  +        </jar>
  +        <jar jarfile="${test.classloader.dir}/one-dependency.jar"
  +             manifest="src/test/${test.classloader.pkg}/one-dependency.mf">
  +            <fileset dir="${test.classloader.classes}">
  +                <include name="**/shared/**"/>
  +                <include name="**/unshared/**"/>
  +            </fileset>
  +        </jar>
  +        <copy file="${test.classloader.dir}/one-dependency.jar"
  +              tofile="${test.classloader.dir}/one-dependency-2.jar"/>
  +        <jar jarfile="${test.classloader.dir}/ext/simple-extension.jar"
  +             manifest="src/test/${test.classloader.pkg}/simple-extension.mf" 
>
  +            <fileset dir="${test.classloader.classes}">
  +                <include name="**/shared/**"/>
  +                <include name="**/extn/**"/>
  +            </fileset>
  +        </jar>
  +        <jar jarfile="${test.classloader.dir}/ext/cycle-extension-1.jar"
  +             
manifest="src/test/${test.classloader.pkg}/cycle-extension-1.mf" />
  +        <jar jarfile="${test.classloader.dir}/ext/cycle-extension-2.jar"
  +             
manifest="src/test/${test.classloader.pkg}/cycle-extension-2.mf" />
  +
           <!-- Prepare the project tests -->
           <antlib-descriptor libName="unittests"
               destdir="${gen.dir}"
  @@ -616,7 +671,7 @@
   
           <!-- Run all the tests -->
           <junit printsummary="on"
  -               fork="true" failureProperty="test.failed">
  +               fork="${test.fork}" failureProperty="test.failed">
               <formatter type="brief" usefile="false"/>
               <classpath>
                   <fileset dir="${test.working.dir}/dist/bin/lib" 
includes="**/*.jar"/>
  
  
  
  1.23      +13 -11    jakarta-ant/proposal/myrmidon/docs/todo.html
  
  Index: todo.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/docs/todo.html,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- todo.html 1 Apr 2002 00:46:26 -0000       1.22
  +++ todo.html 3 Apr 2002 10:58:18 -0000       1.23
  @@ -837,23 +837,12 @@
                           <code>&lt;socket&gt;</code>
                       conditions to an antlib.  Need to resolve how these will 
be passed a logger.
                       </li>
  -                    <li>Make the
  -                        <code>&lt;uptodate&gt;</code> task a condition, and 
move to
  -                    an antlib.
  -                    </li>
  -                    <li>Split up
  -                        <code>&lt;is-set&gt;</code> condition into is-set 
and is-true conditions.
  -                    </li>
                       <li>Allow the
                           <code>&lt;if&gt;</code> task to take any condition 
implementation.
                       </li>
                       <li>Add an else block to the
                           <code>&lt;if&gt;</code> task.
                       </li>
  -                    <li>Split the
  -                        <code>&lt;available&gt;</code> condition into 
separate conditions
  -                    that test for the availability of a class, or a resource.
  -                    </li>
                       <li>Move
                           <code>crimson.jar</code> to
                           <code>bin/lib</code> in the distribution,
  @@ -863,6 +852,19 @@
                       <li>Add a <code>--type</code> command-line option, to 
allow
                           the project builder to be manually selected.
                       </li>
  +                    <li>Change <code>ProjectBuilder</code>
  +                        and <code>Embeddor</code> to throw something more
  +                        specialised than Exception.
  +                    </li>
  +                    <li>Change <code>DefaultClassLoaderManager</code> to 
handle
  +                        directories as part of a library classpath.
  +                    </li>
  +                    <li><code>&lt;condition&gt;</code> should set the 
property
  +                    value to <code>false</code> when the condition is 
false.</li>
  +                    <li>Split the <code>&lt;uptodate&gt;</code> condition 
into
  +                    a condition that checks against a single target file,
  +                    and one which checks using a destdir/mapper.</li>
  +                    <li>Add a task to unset a property.</li>
                       <li>Unit tests.</li>
                   </ul>
                       </blockquote>
  
  
  
  1.5       +154 -87   
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java
  
  Index: DefaultClassLoaderManager.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/DefaultClassLoaderManager.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- DefaultClassLoaderManager.java    29 Mar 2002 12:56:03 -0000      1.4
  +++ DefaultClassLoaderManager.java    3 Apr 2002 10:58:19 -0000       1.5
  @@ -8,19 +8,17 @@
   package org.apache.myrmidon.components.classloader;
   
   import java.io.File;
  -import java.net.JarURLConnection;
   import java.net.MalformedURLException;
   import java.net.URL;
  -import java.net.URLClassLoader;
   import java.util.ArrayList;
  -import java.util.Arrays;
   import java.util.HashMap;
   import java.util.Map;
  -import java.util.List;
  +import java.util.Set;
  +import java.util.HashSet;
   import java.util.jar.Manifest;
  +import java.util.jar.JarFile;
   import org.apache.avalon.excalibur.extension.Extension;
   import org.apache.avalon.excalibur.extension.OptionalPackage;
  -import org.apache.avalon.excalibur.extension.PackageManager;
   import org.apache.avalon.excalibur.i18n.ResourceManager;
   import org.apache.avalon.excalibur.i18n.Resources;
   import org.apache.avalon.framework.activity.Initializable;
  @@ -28,8 +26,8 @@
   import org.apache.avalon.framework.service.ServiceException;
   import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.avalon.framework.service.Serviceable;
  -import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager;
   import org.apache.myrmidon.interfaces.classloader.ClassLoaderException;
  +import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager;
   import org.apache.myrmidon.interfaces.deployer.DeploymentException;
   import org.apache.myrmidon.interfaces.extensions.ExtensionManager;
   import org.apache.tools.todo.types.PathUtil;
  @@ -38,6 +36,7 @@
    * A default implementation of a ClassLoader manager.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
  + * @version $Revision: 1.5 $ $Date: 2002/04/03 10:58:19 $
    */
   public class DefaultClassLoaderManager
       extends AbstractLogEnabled
  @@ -47,13 +46,22 @@
           ResourceManager.getPackageResources( DefaultClassLoaderManager.class 
);
   
       /**
  -     * Map from File to the ClassLoader for that file.
  +     * Map from File/ArrayList to the ClassLoader for that file/files.
        */
  -    private final Map m_fileDeployers = new HashMap();
  +    private final Map m_classLoaders = new HashMap();
   
  -    private PackageManager m_packageManager;
  +    private ExtensionManager m_extensionManager;
       private ClassLoader m_commonClassLoader;
   
  +    public DefaultClassLoaderManager()
  +    {
  +    }
  +
  +    public DefaultClassLoaderManager( final ClassLoader commonClassLoader )
  +    {
  +        m_commonClassLoader = commonClassLoader;
  +    }
  +
       public void initialize() throws Exception
       {
           if( null == m_commonClassLoader )
  @@ -68,18 +76,7 @@
       public void service( final ServiceManager serviceManager )
           throws ServiceException
       {
  -        final ExtensionManager extensionManager =
  -            (ExtensionManager)serviceManager.lookup( ExtensionManager.ROLE );
  -        m_packageManager = new PackageManager( extensionManager );
  -    }
  -
  -    /**
  -     * Sets the ClassLoader to use as the parent for all classloaders
  -     * created by this ClassLoader manager.
  -     */
  -    public void setCommonClassLoader( final ClassLoader classLoader )
  -    {
  -        m_commonClassLoader = classLoader;
  +        m_extensionManager = (ExtensionManager)serviceManager.lookup( 
ExtensionManager.ROLE );
       }
   
       /**
  @@ -94,9 +91,27 @@
       /**
        * Creates a class loader for a Jar file.
        */
  -    public ClassLoader createClassLoader( final File file ) throws 
ClassLoaderException
  +    public ClassLoader getClassLoader( final File file ) throws 
ClassLoaderException
       {
  -        return createClassLoader( new File[] { file } );
  +        try
  +        {
  +            final File canonFile = file.getCanonicalFile();
  +
  +            // Check for cached classloader, creating it if required
  +            ClassLoader loader = (ClassLoader)m_classLoaders.get( canonFile 
);
  +            if( loader == null )
  +            {
  +                checkFile( canonFile );
  +                final OptionalPackage optionalPackage = toOptionalPackage( 
canonFile );
  +                loader = buildClassLoader( optionalPackage, new HashSet() );
  +            }
  +            return loader;
  +        }
  +        catch( final Exception e )
  +        {
  +            final String message = REZ.getString( 
"create-classloader-for-file.error", file );
  +            throw new ClassLoaderException( message, e );
  +        }
       }
   
       /**
  @@ -106,113 +121,165 @@
       {
           try
           {
  -            // Build a list of canonical file names
  -            final ArrayList canonFiles = new ArrayList( files.length );
  -            for( int i = 0; i < files.length; i++ )
  +            if( files == null || files.length == 0 )
               {
  -                canonFiles.add( files[ i ].getCanonicalFile() );
  +                return m_commonClassLoader;
               }
   
  -            // Locate cached classloader, creating it if necessary
  -            ClassLoader classLoader = (ClassLoader)m_fileDeployers.get( 
canonFiles );
  -            if( classLoader == null )
  +            // Build a list of optional packages for the files
  +            final OptionalPackage[] packages = new OptionalPackage[ 
files.length ];
  +            for( int i = 0; i < files.length; i++ )
               {
  -                classLoader = buildClassLoader( canonFiles );
  -                m_fileDeployers.put( canonFiles, classLoader );
  +                final File canonFile = files[ i ].getCanonicalFile();
  +                checkFile( canonFile );
  +                packages[ i ] = toOptionalPackage( canonFile );
               }
  -            return classLoader;
  +
  +            // Build the classloaders for the required extensions
  +            final ClassLoader[] parentClassLoaders = 
buildParentClassLoaders( packages, new HashSet() );
  +
  +            // Build the classloader
  +            final URL[] urls = buildClasspath( files );
  +            return new MultiParentURLClassLoader( urls, parentClassLoaders );
           }
           catch( final Exception e )
           {
               final String fileNames = PathUtil.formatPath( files );
  -            final String message = REZ.getString( 
"create-classloader-for-file.error", fileNames );
  +            final String message = REZ.getString( 
"create-classloader-for-files.error", fileNames );
               throw new ClassLoaderException( message, e );
           }
       }
   
       /**
  -     * Builds the classloader for a set of files.
  +     * Builds the classloader for an optional package.
  +     */
  +    private ClassLoader buildClassLoader( final OptionalPackage pkg,
  +                                          final Set pending )
  +        throws Exception
  +    {
  +        final File jarFile = pkg.getFile();
  +
  +        // Check for cached classloader
  +        ClassLoader classLoader = (ClassLoader)m_classLoaders.get( jarFile );
  +        if( classLoader != null )
  +        {
  +            return classLoader;
  +        }
  +
  +        // Check for cyclic dependency
  +        if( pending.contains( jarFile ) )
  +        {
  +            final String message = REZ.getString( "dependency-cycle.error", 
jarFile );
  +            throw new Exception( message );
  +        }
  +        pending.add( jarFile );
  +
  +        // Build the classloaders for the extensions required by this 
optional
  +        // package
  +        final ClassLoader[] parentClassLoaders =
  +            buildParentClassLoaders( new OptionalPackage[] { pkg }, pending 
);
  +
  +        // Create and cache the classloader
  +        final URL[] urls = { jarFile.toURL() };
  +        classLoader = new MultiParentURLClassLoader( urls, 
parentClassLoaders );
  +        m_classLoaders.put( jarFile, classLoader );
  +        pending.remove( jarFile );
  +        return classLoader;
  +    }
  +
  +    /**
  +     * Builds the parent classloaders for a set of optional packages.  That 
is,
  +     * the classloaders for all of the extensions required by the given set
  +     * of optional packages.
        */
  -    private ClassLoader buildClassLoader( final ArrayList files )
  +    private ClassLoader[] buildParentClassLoaders( final OptionalPackage[] 
packages,
  +                                                   final Set pending )
           throws Exception
       {
  -        final ArrayList allFiles = new ArrayList( files );
  -        final int count = files.size();
  -        for( int i = 0; i < count; i++ )
  +        final ArrayList classLoaders = new ArrayList();
  +
  +        // Include the common class loader
  +        classLoaders.add( m_commonClassLoader );
  +
  +        // Build the classloader for each optional package, filtering out 
duplicates
  +        for( int i = 0; i < packages.length; i++ )
           {
  -            final File file = (File)files.get(i );
  -            checkFile( file );
  -            getOptionalPackagesFor( file, allFiles );
  +            final OptionalPackage optionalPackage = packages[ i ];
  +
  +            // Locate the dependencies for this jar file
  +            final OptionalPackage[] requiredPackages = 
getOptionalPackagesFor( optionalPackage );
  +
  +            // Build the classloader for the package
  +            for( int j = 0; j < requiredPackages.length; j++ )
  +            {
  +                final OptionalPackage requiredPackage = requiredPackages[j ];
  +                final ClassLoader classLoader = buildClassLoader( 
requiredPackage, pending );
  +                if( ! classLoaders.contains( classLoader ) )
  +                {
  +                    classLoaders.add( classLoader );
  +                }
  +            }
           }
   
  -        final URL[] urls = buildClasspath( allFiles );
  -        return new URLClassLoader( urls, m_commonClassLoader );
  +        return (ClassLoader[])classLoaders.toArray( new 
ClassLoader[classLoaders.size() ] );
       }
   
       /**
        * Assembles a set of files into a URL classpath.
        */
  -    private URL[] buildClasspath( final ArrayList files )
  +    private URL[] buildClasspath( final File[] files )
           throws MalformedURLException
       {
  -        final URL[] urls = new URL[ files.size() ];
  -        final int count = files.size();
  -        for( int i = 0; i < count; i++ )
  +        final URL[] urls = new URL[ files.length ];
  +        for( int i = 0; i < files.length; i++ )
           {
  -            final File file = (File)files.get( i );
  -            urls[ i ] = file.toURL();
  +            urls[ i ]  = files[i ].toURL();
           }
   
           return urls;
       }
   
       /**
  -     * Retrieve the files for the optional packages required by
  -     * the specified typeLibrary jar.
  +     * Builds an OptionalPackage for a Jar file.
        *
  -     * @param jarFile the typeLibrary
  -     * @param packages used to return the files that need to be added to 
ClassLoader.
  +     * @param file the jar.
        */
  -    private void getOptionalPackagesFor( final File jarFile, final List 
packages )
  +    private OptionalPackage toOptionalPackage( final File file )
           throws Exception
       {
  -        final URL url = new URL( "jar:" + jarFile.getCanonicalFile().toURL() 
+ "!/" );
  -        final JarURLConnection connection = 
(JarURLConnection)url.openConnection();
  -        final Manifest manifest = connection.getManifest();
  -        final Extension[] available = Extension.getAvailable( manifest );
  +        // Determine the extensions required by this file
  +        final JarFile jarFile = new JarFile( file );
  +        final Manifest manifest = jarFile.getManifest();
           final Extension[] required = Extension.getRequired( manifest );
  +        return new OptionalPackage( file, new Extension[0], required );
  +    }
   
  -        if( getLogger().isDebugEnabled() )
  -        {
  -            final String message1 =
  -                REZ.getString( "available-extensions.notice", Arrays.asList( 
available ) );
  -            getLogger().debug( message1 );
  -            final String message2 =
  -                REZ.getString( "required-extensions.notice", Arrays.asList( 
required ) );
  -            getLogger().debug( message2 );
  -        }
  -
  -        final ArrayList dependencies = new ArrayList();
  -        final ArrayList unsatisfied = new ArrayList();
  -
  -        m_packageManager.scanDependencies( required,
  -                                           available,
  -                                           dependencies,
  -                                           unsatisfied );
  -
  -        if( 0 != unsatisfied.size() )
  +    /**
  +     * Locates the optional packages required by an optional package.
  +     */
  +    private OptionalPackage[] getOptionalPackagesFor( final OptionalPackage 
pkg )
  +        throws Exception
  +    {
  +        // Locate the optional packages that provide the required extesions
  +        final Extension[] required = pkg.getRequiredExtensions();
  +        final ArrayList packages = new ArrayList();
  +        for( int i = 0; i < required.length; i++ )
           {
  -            final String message =
  -                REZ.getString( "unsatisfied.extensions.error", new Integer( 
unsatisfied.size() ) );
  -            throw new Exception( message );
  +            final Extension extension = required[i ];
  +            final OptionalPackage optionalPackage = 
m_extensionManager.getOptionalPackage( extension );
  +            if( optionalPackage == null )
  +            {
  +                final String message =
  +                    REZ.getString( "unsatisfied.extension.error",
  +                                   pkg.getFile(),
  +                                   extension.getExtensionName(),
  +                                   extension.getSpecificationVersion() );
  +                throw new Exception( message );
  +            }
  +            packages.add( optionalPackage );
           }
   
  -        final int count = dependencies.size();
  -        for( int i = 0; i < count; i++ )
  -        {
  -            final OptionalPackage optionalPackage = 
(OptionalPackage)dependencies.get(i );
  -            packages.add( optionalPackage.getFile() );
  -        }
  +        return (OptionalPackage[])packages.toArray( new 
OptionalPackage[packages.size() ] );
       }
   
       /**
  
  
  
  1.3       +5 -6      
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/Resources.properties,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Resources.properties      27 Mar 2002 07:04:16 -0000      1.2
  +++ Resources.properties      3 Apr 2002 10:58:19 -0000       1.3
  @@ -1,6 +1,5 @@
  -create-classloader-for-file.error=Could not create ClassLoader for files: 
{0}.
  -available-extensions.notice=The list of available extensions for type 
library includes; {0}
  -required-extensions.notice=The list of required extensions for type library 
includes; {0}
  -unsatisfied.extensions.error=Missing {0} extensions for type library.
  -no-file.error=Could not find type library "{0}".
  -file-is-dir.error=Type library "{0}" is a directory.
  +create-classloader-for-file.error=Could not create a ClassLoader for "{0}".
  +create-classloader-for-files.error=Could not create a ClassLoader for {0}.
  +unsatisfied.extension.error=Library "{0}" requires unknown extension "{1}" ( 
version {2}).
  +no-file.error=Could not find library "{0}".
  +file-is-dir.error=Library "{0}" is a directory.
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/classloader/MultiParentURLClassLoader.java
  
  Index: MultiParentURLClassLoader.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.components.classloader;
  
  import java.io.IOException;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Enumeration;
  import java.util.List;
  import java.util.Set;
  import java.util.HashSet;
  
  /**
   * A URLClassLoader with more than one parent.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/03 10:58:19 $
   */
  public class MultiParentURLClassLoader
      extends URLClassLoader
  {
      private final ClassLoader[] m_parents;
  
      /**
       * Constructs a new URLClassLoader for the given URLs.
       *
       * @param urls the URLs from which to load classes and resources
       * @param parents the parent class loaderer for delegation
       */
      public MultiParentURLClassLoader( final URL[] urls, final ClassLoader[] 
parents )
      {
          super( urls );
          m_parents = parents;
      }
  
      /**
       * Finds a class.
       *
       * @param name the name of the class
       * @return the resulting class
       * @exception ClassNotFoundException if the class could not be found
       */
      protected Class findClass( final String name )
          throws ClassNotFoundException
      {
          // Try the parent classloaders first
          for( int i = 0; i < m_parents.length; i++ )
          {
              try
              {
                  final ClassLoader parent = m_parents[ i ];
                  return parent.loadClass( name );
              }
              catch( ClassNotFoundException e )
              {
                  // Ignore - continue to the next ClassLoader
              }
          }
  
          // Now this classloader
          return super.findClass( name );
      }
  
      /**
       * Finds a resource.
       *
       * @param name the name of the resource
       * @return a <code>URL</code> for the resource, or <code>null</code>
       * if the resource could not be found.
       */
      public URL findResource( final String name )
      {
          // Try the parent classloaders first
          for( int i = 0; i < m_parents.length; i++ )
          {
              final ClassLoader parent = m_parents[ i ];
              final URL resource = parent.getResource( name );
              if( resource != null )
              {
                  return resource;
              }
          }
  
          // Now this classloader
          return super.findResource( name );
      }
  
      /**
       * Returns an Enumeration of URLs representing all of the resources
       * having the specified name.
       *
       * @param name the resource name
       * @throws IOException if an I/O exception occurs
       * @return an <code>Enumeration</code> of <code>URL</code>s
       */
      public Enumeration findResources( final String name ) throws IOException
      {
          // Need to filter out duplicate resources
          final ArrayList urls = new ArrayList();
          final Set urlSet = new HashSet();
  
          // Gather the resources from the parent classloaders
          for( int i = 0; i < m_parents.length; i++ )
          {
              final ClassLoader parent = m_parents[ i ];
              final Enumeration enum = parent.getResources( name );
              addUrls( enum, urls, urlSet );
          }
  
          // Gather the resources from this classloader
          addUrls( super.findResources( name ), urls, urlSet );
  
          return Collections.enumeration( urls );
      }
  
      /**
       * Adds those URLs not already present.
       */
      private void addUrls( final Enumeration enum,
                            final List urls,
                            final Set urlSet )
      {
          while( enum.hasMoreElements() )
          {
              final URL url = (URL)enum.nextElement();
              final String urlStr = url.toExternalForm();
              if( !urlSet.contains( urlStr ) )
              {
                  urls.add( url );
                  urlSet.add( urlStr );
              }
          }
      }
  }
  
  
  
  1.36      +2 -2      
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java
  
  Index: DefaultDeployer.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -r1.35 -r1.36
  --- DefaultDeployer.java      29 Mar 2002 12:56:03 -0000      1.35
  +++ DefaultDeployer.java      3 Apr 2002 10:58:19 -0000       1.36
  @@ -36,7 +36,7 @@
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
  - * @version $Revision: 1.35 $ $Date: 2002/03/29 12:56:03 $
  + * @version $Revision: 1.36 $ $Date: 2002/04/03 10:58:19 $
    */
   public class DefaultDeployer
       extends AbstractLogEnabled
  @@ -108,7 +108,7 @@
       {
           try
           {
  -            final ClassLoader classLoader = 
m_classLoaderManager.createClassLoader( file );
  +            final ClassLoader classLoader = 
m_classLoaderManager.getClassLoader( file );
               return createDeployment( classLoader, file.toURL() );
           }
           catch( final Exception e )
  
  
  
  1.41      +3 -105    
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java
  
  Index: DefaultEmbeddor.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java,v
  retrieving revision 1.40
  retrieving revision 1.41
  diff -u -r1.40 -r1.41
  --- DefaultEmbeddor.java      1 Apr 2002 09:56:26 -0000       1.40
  +++ DefaultEmbeddor.java      3 Apr 2002 10:58:19 -0000       1.41
  @@ -52,7 +52,7 @@
    * Instantiate this to embed inside other applications.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
  - * @version $Revision: 1.40 $ $Date: 2002/04/01 09:56:26 $
  + * @version $Revision: 1.41 $ $Date: 2002/04/03 10:58:19 $
    */
   public class DefaultEmbeddor
       extends AbstractLogEnabled
  @@ -71,10 +71,7 @@
       private List m_components = new ArrayList();
       private DefaultServiceManager m_serviceManager = new 
DefaultServiceManager();
       private Parameters m_parameters;
  -    private Parameters m_defaults;
   
  -    private File m_homeDir;
  -    private File m_taskLibDir;
       private static final String MYRMIDON_HOME = "myrmidon.home";
   
       /**
  @@ -163,9 +160,6 @@
       public void initialize()
           throws Exception
       {
  -        // setup default properties
  -        m_defaults = createDefaultParameters();
  -
           // setup the root components
           setupComponents();
   
  @@ -183,9 +177,6 @@
           m_workspaceServiceManager = new MultiSourceServiceManager();
           m_workspaceServiceManager.add( projServiceManager );
           m_workspaceServiceManager.add( m_serviceManager );
  -
  -        // setup
  -        setupFiles();
       }
   
       public void start()
  @@ -198,7 +189,8 @@
   
           // Deploy all type libraries in the lib directory
           final ExtensionFileFilter filter = new ExtensionFileFilter( ".atl" );
  -        deployFromDirectory( m_deployer, m_taskLibDir, filter );
  +        final File taskLibDir = new File( m_parameters.getParameter( 
"myrmidon.lib.path" ) );
  +        deployFromDirectory( m_deployer, taskLibDir, filter );
       }
   
       /**
  @@ -230,26 +222,6 @@
           m_deployer = null;
           m_serviceManager = null;
           m_parameters = null;
  -        m_defaults = null;
  -        m_homeDir = null;
  -        m_taskLibDir = null;
  -    }
  -
  -    /**
  -     * Create default properties which includes default names of all 
components.
  -     * Overide this in sub-classes to change values.
  -     *
  -     * @return the Parameters
  -     */
  -    private Parameters createDefaultParameters()
  -    {
  -        final Parameters defaults = new Parameters();
  -
  -        //create all the default properties for files/directories
  -        defaults.setParameter( "myrmidon.bin.path", "bin" );
  -        defaults.setParameter( "myrmidon.lib.path", "lib" );
  -
  -        return defaults;
       }
   
       /**
  @@ -294,80 +266,6 @@
           m_serviceManager.put( roleType.getName(), component );
           m_components.add( component );
           return component;
  -    }
  -
  -    /**
  -     * Setup all the files attributes.
  -     */
  -    private void setupFiles()
  -        throws Exception
  -    {
  -        String filepath = null;
  -
  -        filepath = getParameter( MYRMIDON_HOME );
  -        m_homeDir = ( new File( filepath ) ).getAbsoluteFile();
  -        checkDirectory( m_homeDir, "home-dir.name" );
  -
  -        filepath = getParameter( "myrmidon.lib.path" );
  -        m_taskLibDir = resolveDirectory( filepath, "task-lib-dir.name" );
  -    }
  -
  -    /**
  -     * Retrieve value of named property.
  -     * First access passed in properties and then the default properties.
  -     *
  -     * @param name the name of property
  -     * @return the value of property or null
  -     */
  -    private String getParameter( final String name )
  -    {
  -        String value = m_parameters.getParameter( name, null );
  -
  -        if( null == value )
  -        {
  -            value = m_defaults.getParameter( name, null );
  -        }
  -
  -        return value;
  -    }
  -
  -    /**
  -     * Resolve a directory relative to another base directory.
  -     *
  -     * @param dir the base directory
  -     * @param name the relative directory
  -     * @return the created File
  -     * @exception Exception if an error occurs
  -     */
  -    private File resolveDirectory( final String dir, final String name )
  -        throws Exception
  -    {
  -        final File file = FileUtil.resolveFile( m_homeDir, dir );
  -        checkDirectory( file, name );
  -        return file;
  -    }
  -
  -    /**
  -     * Verify file is a directory else throw an exception.
  -     *
  -     * @param file the File
  -     * @param name the name of file type (used in error messages)
  -     */
  -    private void checkDirectory( final File file, final String name )
  -        throws Exception
  -    {
  -        if( !file.exists() )
  -        {
  -            final String nameStr = REZ.getString( name );
  -            final String message = REZ.getString( "file-no-exist.error", 
nameStr, file );
  -            throw new Exception( message );
  -        }
  -        else if( !file.isDirectory() )
  -        {
  -            final String nameStr = REZ.getString( name );
  -            final String message = REZ.getString( "file-not-dir.error", 
nameStr, file );
  -            throw new Exception( message );
  -        }
       }
   
       /**
  
  
  
  1.5       +0 -4      
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/Resources.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Resources.properties      11 Mar 2002 06:02:22 -0000      1.4
  +++ Resources.properties      3 Apr 2002 10:58:19 -0000       1.5
  @@ -1,10 +1,6 @@
  -file-no-exist.error={0} ({1}) does not exist.
  -file-not-dir.error={0} ({1}) is not a directory.
   bad-type.error=Object {0} is not an instance of {1}.
   bad-ctor.error=Non-public constructor for {0} {1}.
   no-instantiate.error=Error instantiating class for {0} {1}.
   no-class.error=Could not find the class for {0} ({1}).
   bad-filename.error=Unable to retrieve filename for file {0}.
  -home-dir.name=Myrmidon home directory
  -task-lib-dir.name=Task library directory
   create-project.error=Could not load the project definition from {0}.
  
  
  
  1.8       +26 -7     
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/extensions/DefaultExtensionManager.java
  
  Index: DefaultExtensionManager.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/extensions/DefaultExtensionManager.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- DefaultExtensionManager.java      29 Mar 2002 12:55:04 -0000      1.7
  +++ DefaultExtensionManager.java      3 Apr 2002 10:58:19 -0000       1.8
  @@ -27,7 +27,7 @@
    * PhoenixPackageRepository
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
  - * @version $Revision: 1.7 $ $Date: 2002/03/29 12:55:04 $
  + * @version $Revision: 1.8 $ $Date: 2002/04/03 10:58:19 $
    */
   public class DefaultExtensionManager
       extends DefaultPackageRepository
  @@ -50,7 +50,6 @@
           File.separator + "lib" + File.separator + "tools.jar";
   
       private Logger m_logger;
  -
       private String m_path;
   
       public DefaultExtensionManager()
  @@ -58,6 +57,11 @@
           super( new File[ 0 ] );
       }
   
  +    public DefaultExtensionManager( final File[] path )
  +    {
  +        super( path );
  +    }
  +
       public void enableLogging( final Logger logger )
       {
           m_logger = logger;
  @@ -66,16 +70,13 @@
       public void parameterize( final Parameters parameters )
           throws ParameterException
       {
  -        final String phoenixHome = parameters.getParameter( "myrmidon.home" 
);
  -        final String defaultExtPath = phoenixHome + File.separator + "ext";
  -        m_path = parameters.getParameter( "myrmidon.ext.path", 
defaultExtPath );
  +        m_path = parameters.getParameter( "myrmidon.ext.path" );
       }
   
       public void initialize()
           throws Exception
       {
  -        final String[] pathElements = StringUtil.split( m_path, "|" );
  -
  +        final String[] pathElements = StringUtil.split( m_path, 
File.pathSeparator );
           final File[] dirs = new File[ pathElements.length ];
           for( int i = 0; i < dirs.length; i++ )
           {
  @@ -86,6 +87,7 @@
   
           scanPath();
   
  +        // Add the JVM's tools.jar as an extension
           final Extension extension = createToolsExtension();
           final File jar = getToolsJar();
           final Extension[] available = new Extension[]{extension};
  @@ -97,6 +99,23 @@
       public void dispose()
       {
           clearCache();
  +    }
  +
  +    /**
  +     * Locates the optional package which best matches a required extension.
  +     *
  +     * @param extension the extension to locate an optional package
  +     * @return the optional package, or null if not found.
  +     */
  +    public OptionalPackage getOptionalPackage( final Extension extension )
  +    {
  +        final OptionalPackage[] packages = getOptionalPackages( extension );
  +
  +        if( null == packages || 0 == packages.length ) return null;
  +
  +        //TODO: Use heurisitic to find which is best package
  +
  +        return packages[ 0 ];
       }
   
       protected void debug( final String message )
  
  
  
  1.37      +4 -4      
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/frontends/CLIMain.java
  
  Index: CLIMain.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/frontends/CLIMain.java,v
  retrieving revision 1.36
  retrieving revision 1.37
  diff -u -r1.36 -r1.37
  --- CLIMain.java      29 Mar 2002 12:56:03 -0000      1.36
  +++ CLIMain.java      3 Apr 2002 10:58:19 -0000       1.37
  @@ -32,7 +32,7 @@
    * to run project.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
  - * @version $Revision: 1.36 $ $Date: 2002/03/29 12:56:03 $
  + * @version $Revision: 1.37 $ $Date: 2002/04/03 10:58:19 $
    */
   public class CLIMain
   {
  @@ -277,10 +277,10 @@
                       break;
   
                   case LISTENER_OPT:
  -                    m_embedded.setListener( option.getArgument() );
  +                    m_embedded.setProjectListener( option.getArgument() );
                       break;
                   case NO_PREFIX_OPT:
  -                    m_embedded.setListener( "noprefix" );
  +                    m_embedded.setProjectListener( "noprefix" );
                       break;
   
                   case DEFINE_OPT:
  @@ -310,7 +310,7 @@
           try
           {
               // Set system properties set up by launcher
  -            m_embedded.setEmbeddorProperty( "myrmidon.home", properties.get( 
"myrmidon.home" ) );
  +            m_embedded.setHomeDirectory( (File)properties.get( 
"myrmidon.home" ) );
   
               // Command line
               if( !parseCommandLineOptions( args ) )
  
  
  
  1.6       +84 -25    
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/frontends/EmbeddedAnt.java
  
  Index: EmbeddedAnt.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/frontends/EmbeddedAnt.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- EmbeddedAnt.java  29 Mar 2002 12:56:03 -0000      1.5
  +++ EmbeddedAnt.java  3 Apr 2002 10:58:19 -0000       1.6
  @@ -8,8 +8,10 @@
   package org.apache.myrmidon.frontends;
   
   import java.io.File;
  +import java.util.ArrayList;
   import org.apache.avalon.excalibur.i18n.ResourceManager;
   import org.apache.avalon.excalibur.i18n.Resources;
  +import org.apache.avalon.excalibur.io.FileUtil;
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.activity.Initializable;
   import org.apache.avalon.framework.activity.Startable;
  @@ -33,7 +35,7 @@
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
  - * @version $Revision: 1.5 $ $Date: 2002/03/29 12:56:03 $
  + * @version $Revision: 1.6 $ $Date: 2002/04/03 10:58:19 $
    */
   public class EmbeddedAnt
       extends AbstractLogEnabled
  @@ -47,12 +49,25 @@
       private String m_projectFile = "build.ant";
       private Project m_project;
       private String m_listenerName = "default";
  -    private ProjectListener m_listener;
  +    private ArrayList m_listeners = new ArrayList();
       private Parameters m_workspaceProps = new Parameters();
       private Parameters m_builderProps = new Parameters();
       private Parameters m_embeddorParameters = new Parameters();
       private ClassLoader m_sharedClassLoader;
       private Embeddor m_embeddor;
  +    private File m_homeDir;
  +
  +    /**
  +     * Sets the Myrmidon home directory.  Default is to use the current
  +     * directory.
  +     * 
  +     * @todo Autodetect myrmidon home, rather than using current directory 
  +     *       as the default (which is a dud default).
  +     */
  +    public void setHomeDirectory( final File homeDir )
  +    {
  +        m_homeDir = homeDir.getAbsoluteFile();
  +    }
   
       /**
        * Sets the project file to execute.  Default is 'build.ant'.
  @@ -75,21 +90,20 @@
       }
   
       /**
  -     * Sets the name of the project listener to use.
  +     * Sets the name of the project listener to use.  Set to null to disable
  +     * the project listener.
        */
  -    public void setListener( final String listener )
  +    public void setProjectListener( final String listener )
       {
           m_listenerName = listener;
  -        m_listener = null;
       }
   
       /**
  -     * Sets the project listener to use.
  +     * Adds a project listener.
        */
  -    public void setListener( final ProjectListener listener )
  +    public void addProjectListener( final ProjectListener listener )
       {
  -        m_listenerName = null;
  -        m_listener = listener;
  +        m_listeners.add( listener );
       }
   
       /**
  @@ -99,7 +113,7 @@
       public void setWorkspaceProperty( final String name, final Object value )
       {
           // TODO - Make properties Objects, not Strings
  -        m_workspaceProps.setParameter( name, (String)value );
  +        m_workspaceProps.setParameter( name, value.toString() );
       }
   
       /**
  @@ -109,7 +123,7 @@
       public void setBuilderProperty( final String name, final Object value )
       {
           // TODO - Make properties Objects, not Strings
  -        m_builderProps.setParameter( name, (String)value );
  +        m_builderProps.setParameter( name, value.toString() );
       }
   
       /**
  @@ -145,14 +159,13 @@
   
           checkHomeDir();
   
  -        // Prepare the embeddor, project listener and project model
  +        // Prepare the embeddor, and project model
           final Embeddor embeddor = prepareEmbeddor();
  -        final ProjectListener listener = prepareListener( embeddor );
           final Project project = prepareProjectModel( embeddor );
   
           // Create a new workspace
           final Workspace workspace = embeddor.createWorkspace( 
m_workspaceProps );
  -        workspace.addProjectListener( listener );
  +        prepareListeners( embeddor, workspace );
   
           //execute the project
           executeTargets( workspace, project, targets );
  @@ -181,7 +194,7 @@
           {
               m_embeddor = null;
               m_project = null;
  -            m_listener = null;
  +            m_listeners.clear();
           }
       }
   
  @@ -213,19 +226,26 @@
        */
       private void checkHomeDir() throws Exception
       {
  -        final String home = m_embeddorParameters.getParameter( 
"myrmidon.home" );
  -        final File homeDir = ( new File( home ) ).getAbsoluteFile();
  -        if( !homeDir.isDirectory() )
  +        if( m_homeDir == null )
           {
  -            final String message = REZ.getString( "home-not-dir.error", 
homeDir );
  -            throw new Exception( message );
  +            m_homeDir = new File( "." ).getAbsoluteFile();
           }
  +        checkDirectory( m_homeDir, "home-dir.name" );
  +        m_embeddorParameters.setParameter( "myrmidon.home", 
m_homeDir.getAbsolutePath() );
   
           if( getLogger().isInfoEnabled() )
           {
  -            final String message = REZ.getString( "homedir.notice", homeDir 
);
  +            final String message = REZ.getString( "homedir.notice", 
m_homeDir );
               getLogger().info( message );
           }
  +
  +        String path = m_embeddorParameters.getParameter( 
"myrmidon.lib.path", "lib" );
  +        File dir = resolveDirectory( m_homeDir, path, "task-lib-dir.name" );
  +        m_embeddorParameters.setParameter( "myrmidon.lib.path", 
dir.getAbsolutePath() );
  +
  +        path = m_embeddorParameters.getParameter( "myrmidon.ext.path", "ext" 
);
  +        dir = resolveDirectory( m_homeDir, path, "ext-dir.name" );
  +        m_embeddorParameters.setParameter( "myrmidon.ext.path", 
dir.getAbsolutePath() );
       }
   
       /**
  @@ -267,14 +287,21 @@
       /**
        * Prepares and returns the project listener to use.
        */
  -    private ProjectListener prepareListener( final Embeddor embeddor )
  +    private void prepareListeners( final Embeddor embeddor,
  +                                   final Workspace workspace )
           throws Exception
       {
  -        if( m_listener == null )
  +        if( m_listenerName != null )
           {
  -            m_listener = embeddor.createListener( m_listenerName );
  +            final ProjectListener listener = embeddor.createListener( 
m_listenerName );
  +            workspace.addProjectListener( listener );
  +        }
  +        final int count = m_listeners.size();
  +        for( int i = 0; i < count; i++ )
  +        {
  +            final ProjectListener listener = 
(ProjectListener)m_listeners.get(i );
  +            workspace.addProjectListener( listener );
           }
  -        return m_listener;
       }
   
       /**
  @@ -310,4 +337,36 @@
   
           return projectFile;
       }
  +
  +    /**
  +     * Resolve a directory relative to another base directory.
  +     */
  +    private File resolveDirectory( final File baseDir, final String dir, 
final String name )
  +        throws Exception
  +    {
  +        final File file = FileUtil.resolveFile( baseDir, dir );
  +        checkDirectory( file, name );
  +        return file;
  +    }
  +
  +    /**
  +     * Verify file is a directory else throw an exception.
  +     */
  +    private void checkDirectory( final File file, final String name )
  +        throws Exception
  +    {
  +        if( !file.exists() )
  +        {
  +            final String nameStr = REZ.getString( name );
  +            final String message = REZ.getString( "file-no-exist.error", 
nameStr, file );
  +            throw new Exception( message );
  +        }
  +        else if( !file.isDirectory() )
  +        {
  +            final String nameStr = REZ.getString( name );
  +            final String message = REZ.getString( "file-not-dir.error", 
nameStr, file );
  +            throw new Exception( message );
  +        }
  +    }
  +
   }
  
  
  
  1.8       +5 -1      
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/frontends/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/frontends/Resources.properties,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Resources.properties      26 Mar 2002 02:14:02 -0000      1.7
  +++ Resources.properties      3 Apr 2002 10:58:19 -0000       1.8
  @@ -16,7 +16,8 @@
   build.opt=Define a builder parameter (ie -Bfoo=var).
   dry-run.opt=Do not execute tasks - just print them out.
   
  -home-not-dir.error=myrmidon-home ({0}) is not a directory.
  +file-no-exist.error={0} {1} does not exist.
  +file-not-dir.error={0} {1} is not a directory.
   bad-file.error=File {0} is not a file or doesn't exist.
   bad-loglevel.error=Unknown log level - {0}.
   build-failed.error=BUILD FAILED.
  @@ -26,3 +27,6 @@
   
   homedir.notice=Ant Home Directory: {0}
   buildfile.notice=Ant Build File: {0}
  +home-dir.name=Ant home directory
  +task-lib-dir.name=Task library directory
  +ext-dir.name=Extension library directory
  
  
  
  1.4       +15 -6     
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/classloader/ClassLoaderManager.java
  
  Index: ClassLoaderManager.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/classloader/ClassLoaderManager.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ClassLoaderManager.java   1 Apr 2002 09:56:26 -0000       1.3
  +++ ClassLoaderManager.java   3 Apr 2002 10:58:19 -0000       1.4
  @@ -13,6 +13,7 @@
    * Manages a classloader hierarchy.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
  + * @version $Revision: 1.4 $ $Date: 2002/04/03 10:58:19 $
    */
   public interface ClassLoaderManager
   {
  @@ -20,15 +21,22 @@
       String ROLE = ClassLoaderManager.class.getName();
   
       /**
  -     * Builds the ClassLoader for a Jar file, resolving dependencies.
  +     * Returns the ClassLoader for a Jar file.  The ClassLoader is created,
  +     * if necessary.  The ClassLoader's parent will include the common
  +     * ClassLoader, along with any extensions required by the Jar file.
  +     * It is guaranteed that each extension will appear at most once in the
  +     * ClassLoader hierarchy, so that classes from the extension can be
  +     * shared across the ClassLoaders returned by this method.
  +     *
        * @param jar the jar file containing the classes to load
  -     * @return the created classloader
  +     * @return the classloader
        * @throws ClassLoaderException on error
        */
  -    ClassLoader createClassLoader( File jar ) throws ClassLoaderException;
  +    ClassLoader getClassLoader( File jar ) throws ClassLoaderException;
   
       /**
  -     * Builds the ClassLoader for a set of files, resolving dependencies.
  +     * Creates a ClassLoader for a set of files.  See [EMAIL PROTECTED] 
#getClassLoader}
  +     * for details.
        *
        * @param jars The Jar/zip files to create the classloader for.  Use null
        *             or an empty array to use the common classloader.
  @@ -38,9 +46,10 @@
       ClassLoader createClassLoader( File[] jars ) throws ClassLoaderException;
   
       /**
  -     * Provides the common ClassLoader, which is the parent of all 
classloaders
  +     * Returns the common ClassLoader, which is the parent of all 
classloaders
        * built by this ClassLoaderManager.
  -     * @return the common ClassLoader
  +     *
  +     * @return the common ClassLoader.
        */
       ClassLoader getCommonClassLoader();
   }
  
  
  
  1.7       +12 -4     
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/extensions/ExtensionManager.java
  
  Index: ExtensionManager.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/extensions/ExtensionManager.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ExtensionManager.java     1 Apr 2002 09:56:27 -0000       1.6
  +++ ExtensionManager.java     3 Apr 2002 10:58:19 -0000       1.7
  @@ -7,17 +7,25 @@
    */
   package org.apache.myrmidon.interfaces.extensions;
   
  -import org.apache.avalon.excalibur.extension.PackageRepository;
  +import org.apache.avalon.excalibur.extension.Extension;
  +import org.apache.avalon.excalibur.extension.OptionalPackage;
   
   /**
  - * PackageRepository
  + * Maintains a set of optional packages.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
  - * @version $Revision: 1.6 $ $Date: 2002/04/01 09:56:27 $
  + * @version $Revision: 1.7 $ $Date: 2002/04/03 10:58:19 $
    */
   public interface ExtensionManager
  -    extends PackageRepository
   {
       /** Role name for this interface. */
       String ROLE = ExtensionManager.class.getName();
  +
  +    /**
  +     * Locates the optional package which best matches a required extension.
  +     *
  +     * @param extension the extension to locate an optional package
  +     * @return the optional package, or null if not found.
  +     */
  +    public OptionalPackage getOptionalPackage( Extension extension );
   }
  
  
  
  1.12      +35 -29    
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java
  
  Index: AbstractMyrmidonTest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- AbstractMyrmidonTest.java 28 Mar 2002 06:35:21 -0000      1.11
  +++ AbstractMyrmidonTest.java 3 Apr 2002 10:58:20 -0000       1.12
  @@ -29,28 +29,21 @@
       private final File m_baseDir;
       private Logger m_logger;
   
  -    protected static final Resources getResourcesForTested( final Class 
clazz )
  +    public AbstractMyrmidonTest( final String name )
       {
  -        final Package pkg = clazz.getPackage();
  -
  -        String baseName;
  -        if( null == pkg )
  -        {
  -            final String name = clazz.getName();
  -            if( -1 == name.lastIndexOf( "." ) )
  -            {
  -                baseName = "";
  -            }
  -            else
  -            {
  -                baseName = name.substring( 0, name.lastIndexOf( "." ) );
  -            }
  -        }
  -        else
  -        {
  -            baseName = pkg.getName();
  -        }
  +        super( name );
  +        final String baseDirProp = System.getProperty( "test.basedir" );
  +        m_baseDir = getCanonicalFile( new File( baseDirProp ) );
  +        final String packagePath = getPackageName( getClass() ).replace( 
'.', File.separatorChar );
  +        m_testBaseDir = getCanonicalFile( new File( m_baseDir, packagePath ) 
);
  +    }
   
  +    /**
  +     * Locates the error message resources for a class.
  +     */
  +    protected static final Resources getResourcesForTested( final Class 
clazz )
  +    {
  +        String baseName = getPackageName( clazz );
           if( baseName.endsWith( ".test" ) )
           {
               baseName = baseName.substring( 0, baseName.length() - 5 );
  @@ -59,16 +52,29 @@
           return ResourceManager.getBaseResources( baseName + ".Resources", 
AbstractMyrmidonTest.class.getClassLoader() );
       }
   
  -    public AbstractMyrmidonTest( String name )
  +    /**
  +     * Returns the name of the package containing a class.
  +     *
  +     * @return The . delimited package name, or an empty string if the class
  +     *         is in the default package.
  +     */
  +    protected static String getPackageName( final Class clazz )
       {
  -        super( name );
  -        final String baseDirProp = System.getProperty( "test.basedir" );
  -        m_baseDir = getCanonicalFile( new File( baseDirProp ) );
  -        String packagePath = getClass().getName();
  -        int idx = packagePath.lastIndexOf( '.' );
  -        packagePath = packagePath.substring( 0, idx );
  -        packagePath = packagePath.replace( '.', File.separatorChar );
  -        m_testBaseDir = getCanonicalFile( new File( m_baseDir, packagePath ) 
);
  +        final Package pkg = clazz.getPackage();
  +        if( null != pkg )
  +        {
  +            return pkg.getName();
  +        }
  +
  +        final String name = clazz.getName();
  +        if( -1 == name.lastIndexOf( "." ) )
  +        {
  +            return "";
  +        }
  +        else
  +        {
  +            return name.substring( 0, name.lastIndexOf( "." ) );
  +        }
       }
   
       /**
  
  
  
  1.7       +13 -52    
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractProjectTest.java
  
  Index: AbstractProjectTest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractProjectTest.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- AbstractProjectTest.java  28 Mar 2002 06:35:21 -0000      1.6
  +++ AbstractProjectTest.java  3 Apr 2002 10:58:20 -0000       1.7
  @@ -8,68 +8,24 @@
   package org.apache.myrmidon;
   
   import java.io.File;
  -import org.apache.avalon.framework.logger.Logger;
  -import org.apache.avalon.framework.parameters.Parameters;
  -import org.apache.myrmidon.components.embeddor.DefaultEmbeddor;
  -import org.apache.myrmidon.interfaces.embeddor.Embeddor;
  -import org.apache.myrmidon.interfaces.model.Project;
  -import org.apache.myrmidon.interfaces.workspace.Workspace;
  +import org.apache.myrmidon.frontends.EmbeddedAnt;
   import org.apache.myrmidon.listeners.ProjectListener;
   
   /**
    * A base class for test cases which need to execute projects.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
  - * @version $Revision: 1.6 $ $Date: 2002/03/28 06:35:21 $
  + * @version $Revision: 1.7 $ $Date: 2002/04/03 10:58:20 $
    */
   public class AbstractProjectTest
       extends AbstractMyrmidonTest
   {
  -    private DefaultEmbeddor m_embeddor;
  -
       public AbstractProjectTest( final String name )
       {
           super( name );
       }
   
       /**
  -     * Tear-down the test.
  -     */
  -    protected void tearDown() throws Exception
  -    {
  -        if( m_embeddor != null )
  -        {
  -            m_embeddor.dispose();
  -            m_embeddor = null;
  -        }
  -    }
  -
  -    /**
  -     * Returns an embeddor which can be used to build and execute projects.
  -     */
  -    protected Embeddor getEmbeddor() throws Exception
  -    {
  -        if( m_embeddor == null )
  -        {
  -            // Need to set the context classloader - The default embeddor 
uses it
  -            Thread.currentThread().setContextClassLoader( 
getClass().getClassLoader() );
  -
  -            final Logger logger = getLogger();
  -            m_embeddor = new DefaultEmbeddor();
  -            m_embeddor.enableLogging( logger );
  -
  -            final Parameters params = new Parameters();
  -            final File instDir = getInstallDirectory();
  -            params.setParameter( "myrmidon.home", instDir.getAbsolutePath() 
);
  -            m_embeddor.parameterize( params );
  -            m_embeddor.initialize();
  -            m_embeddor.start();
  -        }
  -
  -        return m_embeddor;
  -    }
  -
  -    /**
        * Executes a target in a project, and asserts that it fails with the
        * given error message.
        */
  @@ -117,22 +73,27 @@
           throws Exception
       {
           // Create the project and workspace
  -        final Embeddor embeddor = getEmbeddor();
  -        final Project project = embeddor.createProject( 
projectFile.getAbsolutePath(), null, null );
  -        final Workspace workspace = embeddor.createWorkspace( new 
Parameters() );
  +        final EmbeddedAnt embeddor = new EmbeddedAnt();
  +        embeddor.setHomeDirectory( getInstallDirectory() );
  +        embeddor.enableLogging( getLogger() );
  +        embeddor.setSharedClassLoader( getClass().getClassLoader() );
  +        embeddor.setProjectFile( projectFile.getAbsolutePath() );
  +        embeddor.setProjectListener( null );
   
           // Add a listener to make sure all is good
           final TrackingProjectListener tracker = new 
TrackingProjectListener();
  -        workspace.addProjectListener( tracker );
  +        embeddor.addProjectListener( tracker );
   
           // Add supplied listener
           if( listener != null )
           {
  -            workspace.addProjectListener( listener );
  +            embeddor.addProjectListener( listener );
           }
   
           // Now execute the target
  -        workspace.executeProject( project, targetName );
  +        embeddor.executeTargets( new String[] { targetName } );
  +
  +        embeddor.stop();
   
           // Make sure all expected events were delivered
           tracker.assertComplete();
  
  
  
  1.21      +48 -5     
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java
  
  Index: AbstractComponentTest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- AbstractComponentTest.java        27 Mar 2002 07:04:17 -0000      1.20
  +++ AbstractComponentTest.java        3 Apr 2002 10:58:20 -0000       1.21
  @@ -10,12 +10,16 @@
   import java.util.ArrayList;
   import java.util.Iterator;
   import java.util.List;
  +import java.io.File;
   import org.apache.aut.converter.Converter;
   import org.apache.avalon.framework.logger.LogEnabled;
   import org.apache.avalon.framework.logger.Logger;
   import org.apache.avalon.framework.service.DefaultServiceManager;
   import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.avalon.framework.service.Serviceable;
  +import org.apache.avalon.framework.parameters.Parameters;
  +import org.apache.avalon.framework.parameters.Parameterizable;
  +import org.apache.avalon.framework.activity.Initializable;
   import org.apache.myrmidon.AbstractMyrmidonTest;
   import org.apache.myrmidon.components.classloader.DefaultClassLoaderManager;
   import org.apache.myrmidon.components.configurer.DefaultConfigurer;
  @@ -93,10 +97,9 @@
               m_serviceManager.put( Executor.ROLE, component );
               components.add( component );
   
  -            final DefaultClassLoaderManager classLoaderMgr = new 
DefaultClassLoaderManager();
  -            classLoaderMgr.setCommonClassLoader( getClass().getClassLoader() 
);
  -            m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr );
  -            components.add( classLoaderMgr );
  +            component = createComponent( ClassLoaderManager.ROLE, 
DefaultClassLoaderManager.class );
  +            m_serviceManager.put( ClassLoaderManager.ROLE, component );
  +            components.add( component );
   
               component = createComponent( ExtensionManager.ROLE, 
DefaultExtensionManager.class );
               m_serviceManager.put( ExtensionManager.ROLE, component );
  @@ -132,6 +135,29 @@
                   }
               }
   
  +            // Parameterise the components
  +            final Parameters parameters = getParameters();
  +            for( Iterator iterator = components.iterator(); 
iterator.hasNext(); )
  +            {
  +                Object obj = iterator.next();
  +                if( obj instanceof Parameterizable )
  +                {
  +                    final Parameterizable parameterizable = 
(Parameterizable)obj;
  +                    parameterizable.parameterize( parameters );
  +                }
  +            }
  +
  +            // Initialise the components
  +            for( Iterator iterator = components.iterator(); 
iterator.hasNext(); )
  +            {
  +                Object obj = iterator.next();
  +                if( obj instanceof Initializable )
  +                {
  +                    final Initializable initializable = (Initializable)obj;
  +                    initializable.initialize();
  +                }
  +            }
  +
               // Register some standard roles
               // Add some core roles
               final RoleManager roleManager = 
(RoleManager)getServiceManager().lookup( RoleManager.ROLE );
  @@ -144,12 +170,29 @@
       }
   
       /**
  -     * Creates an instance of a component.  Sub-classes can override this
  +     * Creates the parameters for the test.  Sub-classes can override this
  +     * method to set-up the parameters.
  +     */
  +    protected Parameters getParameters()
  +    {
  +        final Parameters parameters = new Parameters();
  +        final String homeDir = getInstallDirectory().getAbsolutePath();
  +        parameters.setParameter( "myrmidon.home", homeDir );
  +        parameters.setParameter( "myrmidon.ext.path", homeDir + 
File.separatorChar + "ext" );
  +        return parameters;
  +    }
  +
  +    /**
  +     * Creates an instance of a test component.  Sub-classes can override 
this
        * method to add a particular implementation to the set of test 
components.
        */
       protected Object createComponent( final String role, final Class 
defaultImpl )
           throws Exception
       {
  +        if( role.equals( ClassLoaderManager.ROLE ) )
  +        {
  +            return new DefaultClassLoaderManager( 
getClass().getClassLoader() );
  +        }
           return defaultImpl.newInstance();
       }
   
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/DefaultClassLoaderManagerTestCase.java
  
  Index: DefaultClassLoaderManagerTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.components.classloader.test;
  
  import java.io.File;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.util.Enumeration;
  import org.apache.myrmidon.components.AbstractComponentTest;
  import org.apache.myrmidon.components.classloader.DefaultClassLoaderManager;
  import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager;
  import org.apache.myrmidon.interfaces.classloader.ClassLoaderException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.excalibur.i18n.Resources;
  
  /**
   * Test cases for the DefaultClassLoaderManager.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/03 10:58:20 $
   */
  public class DefaultClassLoaderManagerTestCase
      extends AbstractComponentTest
  {
      private static final String UNSHARED_PKG_NAME =
          getPackageName( DefaultClassLoaderManagerTestCase.class ) + 
".libs.unshared";
      private static final String UNSHARED_RES_NAME = getResourceName( 
UNSHARED_PKG_NAME, "unshared.txt" );
      private static final String UNSHARED_CLASS_NAME = UNSHARED_PKG_NAME + 
".UnsharedClass";
  
      private static final String SHARED_PKG_NAME =
          getPackageName( DefaultClassLoaderManagerTestCase.class ) + 
".libs.shared";
      private static final String SHARED_RES_NAME = getResourceName( 
SHARED_PKG_NAME, "shared.txt" );
      private static final String SHARED_CLASS_NAME = SHARED_PKG_NAME + 
".SharedClass";
  
      private static final String EXTN_PKG_NAME =
          getPackageName( DefaultClassLoaderManagerTestCase.class ) + 
".libs.extn";
      private static final String EXTN_RES_NAME = getResourceName( 
EXTN_PKG_NAME, "extn.txt" );
      private static final String EXTN_CLASS_NAME = EXTN_PKG_NAME + 
".ExtnClass";
  
      private File m_commonJar;
      private ClassLoader m_commonClassLoader;
      private ClassLoaderManager m_loaderManager;
  
      public DefaultClassLoaderManagerTestCase( final String name )
      {
          super( name );
      }
  
      /**
       * Sets up the test.
       */
      protected void setUp() throws Exception
      {
          m_commonJar = getTestResource( "common.jar" );
          final URL commonJarUrl = m_commonJar.toURL();
          m_commonClassLoader = new URLClassLoader( new URL[]{commonJarUrl} );
  
          assertClassFound( m_commonClassLoader, SHARED_CLASS_NAME );
          assertResourcesFound( m_commonClassLoader, SHARED_RES_NAME, 
m_commonJar );
  
          // Create the classloader mgr
          m_loaderManager = (ClassLoaderManager)getServiceManager().lookup( 
ClassLoaderManager.ROLE );
      }
  
      /**
       * Creates an instance of a test component.
       */
      protected Object createComponent( final String role, final Class 
defaultImpl )
          throws Exception
      {
          if( role.equals( ClassLoaderManager.ROLE ) )
          {
              return new DefaultClassLoaderManager( m_commonClassLoader );
          }
          else
          {
              return super.createComponent( role, defaultImpl );
          }
      }
  
      /**
       * Creates the parameters for the test.  Sub-classes can override this
       * method to set-up the parameters.
       */
      protected Parameters getParameters()
      {
          final Parameters parameters = super.getParameters();
          parameters.setParameter( "myrmidon.ext.path", getTestDirectory( "ext" 
).getAbsolutePath() );
          return parameters;
      }
  
      /**
       * Returns the name of a resource in a package.
       */
      private static String getResourceName( final String pkgName,
                                             final String resname )
      {
          return pkgName.replace( '.', '/' ) + '/' + resname;
      }
  
      /**
       * Asserts that a class is not available in a classloader.
       */
      private void assertClassNotFound( final ClassLoader classLoader,
                                        final String className )
      {
          try
          {
              classLoader.loadClass( className );
              fail( "Class " + className + " should not be available." );
          }
          catch( ClassNotFoundException e )
          {
          }
      }
  
      /**
       * Asserts that a class is available in a classloader.
       */
      private void assertClassFound( final ClassLoader classLoader,
                                     final String className )
          throws Exception
      {
          assertClassFound( classLoader, className, classLoader );
      }
  
      /**
       * Asserts that a class is available in a classloader.
       */
      private void assertClassFound( final ClassLoader classLoader,
                                     final String className,
                                     final ClassLoader expectedClassLoader )
          throws Exception
      {
          try
          {
              final Class cls = classLoader.loadClass( className );
              assertSame( expectedClassLoader, cls.getClassLoader() );
              if( classLoader != expectedClassLoader )
              {
                  final Class expectedCls = expectedClassLoader.loadClass( 
className );
                  assertSame( expectedCls, cls );
              }
          }
          catch( ClassNotFoundException e )
          {
              fail( "Class " + className + " not found." );
          }
  
      }
  
      /**
       * Asserts that a resouce is not available in a classloader.
       */
      private void assertResourceNotFound( final ClassLoader classLoader,
                                           final String resName )
          throws Exception
      {
          assertNull( classLoader.getResource( resName ) );
          assertNull( classLoader.getResourceAsStream( resName ) );
          final Enumeration enum = classLoader.getResources( resName );
          assertTrue( !enum.hasMoreElements() );
      }
  
      /**
       * Asserts that a resource is available in a classloader.
       */
      private void assertResourcesFound( final ClassLoader classLoader,
                                         final String resName,
                                         final File expectedJar )
          throws Exception
      {
          assertResourcesFound( classLoader, resName, new File[]{expectedJar} );
      }
  
      /**
       * Asserts that a resource is available in a classloader.
       */
      private void assertResourcesFound( final ClassLoader classLoader,
                                         final String resName,
                                         final File[] expectedJars )
          throws Exception
      {
          final String[] expectedLocations = new String[ expectedJars.length ];
          for( int i = 0; i < expectedJars.length; i++ )
          {
              final File jar = expectedJars[ i ];
              expectedLocations[ i ] = "jar:" + jar.toURL() + "!/" + resName;
          }
  
          assertResourcesFound( classLoader, resName, expectedLocations );
      }
  
      /**
       * Asserts that a resource is available in a classloader.
       */
      private void assertResourcesFound( final ClassLoader classLoader,
                                         final String resName,
                                         final String[] expectedLocations )
          throws Exception
      {
          // Use the first in the list of expected locations as the location
          // of the resource returned by getResource()
          final URL resUrl = classLoader.getResource( resName );
          assertNotNull( resUrl );
          assertEquals( expectedLocations[ 0 ], resUrl.toString() );
  
          // Now check all of the resources returned by getResources()
          final Enumeration resources = classLoader.getResources( resName );
          for( int i = 0; i < expectedLocations.length; i++ )
          {
              final String expectedLocation = expectedLocations[ i ];
              assertTrue( resources.hasMoreElements() );
              final URL location = (URL)resources.nextElement();
              assertEquals( expectedLocation, location.toString() );
          }
          assertTrue( !resources.hasMoreElements() );
      }
  
      /**
       * Tests for a Jar with no required extensions.
       */
      public void testNoDependencies() throws Exception
      {
          // Make some assumptions about the common classloader
          assertClassNotFound( m_commonClassLoader, UNSHARED_CLASS_NAME );
          assertResourceNotFound( m_commonClassLoader, UNSHARED_RES_NAME );
  
          // Build the classloader
          final File jarFile = getTestResource( "no-dependencies.jar" );
          final ClassLoader classLoader = m_loaderManager.getClassLoader( 
jarFile );
  
          // Check shared classes/resources
          assertClassFound( classLoader, SHARED_CLASS_NAME, m_commonClassLoader 
);
          assertResourcesFound( classLoader, SHARED_RES_NAME, new 
File[]{m_commonJar, jarFile} );
  
          // Check unshared classes/resources
          assertClassFound( classLoader, UNSHARED_CLASS_NAME );
          assertResourcesFound( classLoader, UNSHARED_RES_NAME, jarFile );
      }
  
      /**
       * Tests ClassLoader caching.
       */
      public void testClassLoaderReuse() throws Exception
      {
          final File jarFile = getTestResource( "no-dependencies.jar" );
          final ClassLoader classLoader1 = m_loaderManager.getClassLoader( 
jarFile );
          final ClassLoader classLoader2 = m_loaderManager.getClassLoader( 
jarFile );
          assertSame( classLoader1, classLoader2 );
      }
  
      /**
       * Tests for a Jar with a single required extension.
       */
      public void testOneDependency() throws Exception
      {
          // Make some assumptions about the common classloader
          assertClassNotFound( m_commonClassLoader, UNSHARED_CLASS_NAME );
          assertResourceNotFound( m_commonClassLoader, UNSHARED_RES_NAME );
          assertClassNotFound( m_commonClassLoader, EXTN_CLASS_NAME );
          assertResourceNotFound( m_commonClassLoader, EXTN_RES_NAME );
  
          // Build the extension classloader
          final File extnJarFile = getTestResource( "ext/simple-extension.jar" 
);
          final ClassLoader extnClassLoader = m_loaderManager.getClassLoader( 
extnJarFile );
  
          // Build the Jar classloader
          final File jarFile = getTestResource( "one-dependency.jar" );
          final ClassLoader classLoader = m_loaderManager.getClassLoader( 
jarFile );
  
          // Check shared classes/resources
          assertClassFound( classLoader, SHARED_CLASS_NAME, m_commonClassLoader 
);
          assertResourcesFound( classLoader, SHARED_RES_NAME, new 
File[]{m_commonJar, extnJarFile, jarFile} );
  
          // Check extension classes/resources
          assertClassFound( classLoader, EXTN_CLASS_NAME, extnClassLoader );
          assertResourcesFound( classLoader, EXTN_RES_NAME, extnJarFile );
  
          // Check unshared classes/resources
          assertClassFound( classLoader, UNSHARED_CLASS_NAME );
          assertResourcesFound( classLoader, UNSHARED_RES_NAME, jarFile );
      }
  
      /**
       * Tests that classes from extensions can be shared across classloaders.
       */
      public void testShareClasses() throws Exception
      {
          // Build the extension classloader
          final File extnJarFile = getTestResource( "ext/simple-extension.jar" 
);
          final ClassLoader extnClassLoader = m_loaderManager.getClassLoader( 
extnJarFile );
  
          // Build the Jar classloaders
          final File jarFile1 = getTestResource( "one-dependency.jar" );
          final ClassLoader classLoader1 = m_loaderManager.getClassLoader( 
jarFile1 );
          final File jarFile2 = getTestResource( "one-dependency-2.jar" );
          final ClassLoader classLoader2 = m_loaderManager.getClassLoader( 
jarFile2 );
  
          // Check extension classes/resources
          assertClassFound( classLoader1, EXTN_CLASS_NAME, extnClassLoader );
          assertResourcesFound( classLoader1, EXTN_RES_NAME, extnJarFile );
          assertClassFound( classLoader2, EXTN_CLASS_NAME, extnClassLoader );
          assertResourcesFound( classLoader2, EXTN_RES_NAME, extnJarFile );
      }
  
      /**
       * Tests detection of dependency cycles in extensions.
       */
      public void testCycle() throws Exception
      {
          final File jarFile = getTestResource( "ext/cycle-extension-1.jar" );
          try
          {
              m_loaderManager.getClassLoader( jarFile );
              fail();
          }
          catch( final ClassLoaderException e )
          {
              final Resources rez = getResourcesForTested( 
DefaultClassLoaderManager.class );
              final String[] messages = {
                  rez.getString( "create-classloader-for-file.error", jarFile ),
                  rez.getString( "dependency-cycle.error", jarFile )
              };
              assertSameMessage( messages, e );
          }
      }
  
      /**
       * add some classes to common loader only.
       *
       * unknown extension
       * multiple versions of extensions
       * extn with requirement on itself
       *
       * jar with 1 and 2 extns:
       *   class/resources in parent
       *   class/resources in jar
       *   class/resources in extn
       *   class/resources in all
       *
       * jar with transitive extn
       *   class/resources in 2nd extn
       *
       * jar with transitive extn + explicit extn on same jar
       *   class/resources in 2nd extn
       *
       * Same classes:
       *     get extn explicitly and implicitly, and check classes are the same
       *     extn shared by 2 jars, using same extn and different extns
       *     classes in common classloader, shared by 2 jars
       *
       * multiple files:
       *     fetch classloader twice
       *     different path ordering
       *
       * tools.jar
       */
  }
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/cycle-extension-1.mf
  
  Index: cycle-extension-1.mf
  ===================================================================
  Extension-Name: test.cycle1
  Specification-Title: Test Extension
  Specification-Version: 1.0.0
  Specification-Vendor: Jakarta Apache
  Implementation-Vendor-Id: org.apache.myrmidon
  Implementation-Vendor: Apache Myrmidon Project
  Implementation-Version: 3.0
  Extension-List: cycle2
  cycle2-Extension-Name: test.cycle2
  cycle2-Specification-Version: 1.0
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/cycle-extension-2.mf
  
  Index: cycle-extension-2.mf
  ===================================================================
  Extension-Name: test.cycle2
  Specification-Title: Test Extension
  Specification-Version: 1.0.0
  Specification-Vendor: Jakarta Apache
  Implementation-Vendor-Id: org.apache.myrmidon
  Implementation-Vendor: Apache Myrmidon Project
  Implementation-Version: 1.709.2
  Extension-List: cycle1
  cycle1-Extension-Name: test.cycle1
  cycle1-Specification-Version: 1.0
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/one-dependency.mf
  
  Index: one-dependency.mf
  ===================================================================
  Extension-List: extension1
  extension1-Extension-Name: test.simple
  extension1-Specification-Version: 1.0
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/simple-extension.mf
  
  Index: simple-extension.mf
  ===================================================================
  Extension-Name: test.simple
  Specification-Title: Test Simple Extension
  Specification-Version: 1.0.0
  Specification-Vendor: Jakarta Apache
  Implementation-Vendor-Id: org.apache.myrmidon
  Implementation-Vendor: Apache Myrmidon Project
  Implementation-Version: 1.0.2
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/extn/ExtnClass.java
  
  Index: ExtnClass.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.components.classloader.test.libs.extn;
  
  import 
org.apache.myrmidon.components.classloader.test.libs.shared.SharedClass;
  
  /**
   * A test class loaded from an extension.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/03 10:58:20 $
   */
  public class ExtnClass
  {
      public SharedClass m_test = new SharedClass();
  }
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/extn/extn.txt
  
  Index: extn.txt
  ===================================================================
  A test resource loaded from an extension.
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/shared/SharedClass.java
  
  Index: SharedClass.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.components.classloader.test.libs.shared;
  
  /**
   * A test class.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/03 10:58:20 $
   */
  public class SharedClass
  {
  }
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/shared/shared.txt
  
  Index: shared.txt
  ===================================================================
  A shared resource.
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/unshared/UnsharedClass.java
  
  Index: UnsharedClass.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.components.classloader.test.libs.unshared;
  
  import 
org.apache.myrmidon.components.classloader.test.libs.shared.SharedClass;
  
  /**
   * A test class.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/03 10:58:20 $
   */
  public class UnsharedClass
  {
      public SharedClass m_test = new SharedClass();
  }
  
  
  
  1.1                  
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/classloader/test/libs/unshared/unshared.txt
  
  Index: unshared.txt
  ===================================================================
  An unshared resource.
  
  
  1.2       +43 -1     
jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/embeddor/test/DefaultEmbeddorTest.java
  
  Index: DefaultEmbeddorTest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/proposal/myrmidon/src/test/org/apache/myrmidon/components/embeddor/test/DefaultEmbeddorTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DefaultEmbeddorTest.java  17 Mar 2002 08:07:09 -0000      1.1
  +++ DefaultEmbeddorTest.java  3 Apr 2002 10:58:20 -0000       1.2
  @@ -9,8 +9,10 @@
   
   import java.io.File;
   import org.apache.avalon.framework.parameters.Parameters;
  +import org.apache.avalon.framework.logger.Logger;
   import org.apache.myrmidon.AbstractProjectTest;
   import org.apache.myrmidon.LogMessageTracker;
  +import org.apache.myrmidon.components.embeddor.DefaultEmbeddor;
   import org.apache.myrmidon.interfaces.embeddor.Embeddor;
   import org.apache.myrmidon.interfaces.model.Project;
   import org.apache.myrmidon.interfaces.model.Target;
  @@ -21,17 +23,56 @@
    * Test cases for the default embeddor.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
  - * @version $Revision: 1.1 $ $Date: 2002/03/17 08:07:09 $
  + * @version $Revision: 1.2 $ $Date: 2002/04/03 10:58:20 $
    */
   public class DefaultEmbeddorTest
       extends AbstractProjectTest
   {
  +    private DefaultEmbeddor m_embeddor;
  +
       public DefaultEmbeddorTest( String name )
       {
           super( name );
       }
   
       /**
  +     * Tear-down the test.
  +     */
  +    protected void tearDown() throws Exception
  +    {
  +        if( m_embeddor != null )
  +        {
  +            m_embeddor.dispose();
  +            m_embeddor = null;
  +        }
  +    }
  +
  +    /**
  +     * Returns an embeddor which can be used to build and execute projects.
  +     */
  +    protected Embeddor getEmbeddor() throws Exception
  +    {
  +        if( m_embeddor == null )
  +        {
  +            // Need to set the context classloader - The default embeddor 
uses it
  +            Thread.currentThread().setContextClassLoader( 
getClass().getClassLoader() );
  +
  +            final Logger logger = getLogger();
  +            m_embeddor = new DefaultEmbeddor();
  +            m_embeddor.enableLogging( logger );
  +
  +            final Parameters params = new Parameters();
  +            final File instDir = getInstallDirectory();
  +            params.setParameter( "myrmidon.home", instDir.getAbsolutePath() 
);
  +            m_embeddor.parameterize( params );
  +            m_embeddor.initialize();
  +            m_embeddor.start();
  +        }
  +
  +        return m_embeddor;
  +    }
  +
  +    /**
        * Tests that a project is successfully built from a file.
        */
       public void testProjectBuilder() throws Exception
  @@ -63,6 +104,7 @@
       public void testCreateListener() throws Exception
       {
           final ProjectListener listener = getEmbeddor().createListener( 
"default" );
  +        assertNotNull( listener );
       }
   
       /**
  
  
  
  1.26      +15 -11    jakarta-ant/proposal/myrmidon/src/xdocs/todo.xml
  
  Index: todo.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/xdocs/todo.xml,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- todo.xml  1 Apr 2002 00:46:26 -0000       1.25
  +++ todo.xml  3 Apr 2002 10:58:20 -0000       1.26
  @@ -524,23 +524,12 @@
                           <code>&lt;socket&gt;</code>
                       conditions to an antlib.  Need to resolve how these will 
be passed a logger.
                       </li>
  -                    <li>Make the
  -                        <code>&lt;uptodate&gt;</code> task a condition, and 
move to
  -                    an antlib.
  -                    </li>
  -                    <li>Split up
  -                        <code>&lt;is-set&gt;</code> condition into is-set 
and is-true conditions.
  -                    </li>
                       <li>Allow the
                           <code>&lt;if&gt;</code> task to take any condition 
implementation.
                       </li>
                       <li>Add an else block to the
                           <code>&lt;if&gt;</code> task.
                       </li>
  -                    <li>Split the
  -                        <code>&lt;available&gt;</code> condition into 
separate conditions
  -                    that test for the availability of a class, or a resource.
  -                    </li>
                       <li>Move
                           <code>crimson.jar</code> to
                           <code>bin/lib</code> in the distribution,
  @@ -550,6 +539,21 @@
                       <li>Add a <code>--type</code> command-line option, to 
allow
                           the project builder to be manually selected.
                       </li>
  +                    <li>Change <code>ProjectBuilder</code>
  +                        and <code>Embeddor</code> to throw something more
  +                        specialised than Exception.
  +                    </li>
  +                    <li>Change <code>DefaultClassLoaderManager</code> to 
handle
  +                        directories as part of a library classpath.
  +                    </li>
  +                    <li><code>&lt;condition&gt;</code> should set the 
property
  +                        value to <code>false</code> when the condition is 
false.</li>
  +                    <li>Split the <code>&lt;uptodate&gt;</code> condition 
into
  +                        a condition that checks against a single target file,
  +                        and one which checks using a destdir/mapper.</li>
  +                    <li>Add a task to unset a property.</li>
  +                    <li>Change the various def and import task to allow a 
classpath
  +                        to be provided.</li>
                       <li>Unit tests.</li>
                   </ul>
   
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to