ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From adammurd...@apache.org
Subject cvs commit: jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace ClassicPropertyResolverTest.java DefaultPropertyResolverTest.java
Date Wed, 13 Mar 2002 07:35:19 GMT
adammurdoch    02/03/12 23:35:19

  Modified:    proposal/myrmidon/src/java/org/apache/myrmidon/components/builder
                        DefaultProjectBuilder.java Resources.properties
               proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace
                        DefaultTaskContext.java DefaultWorkspace.java
                        ProjectEntry.java Resources.properties
               proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder
                        ProjectBuilder.java
               proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model
                        Target.java
               proposal/myrmidon/src/testcases/org/apache/aut/vfs
                        AbstractFileSystemTest.java
               proposal/myrmidon/src/testcases/org/apache/myrmidon
                        AbstractMyrmidonTest.java AbstractProjectTest.java
               proposal/myrmidon/src/testcases/org/apache/myrmidon/components
                        AbstractComponentTest.java
               proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder
                        DefaultProjectBuilderTest.java
               proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service
                        InstantiatingServiceManagerTest.java
  Added:       proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder
                        bad-version.ant bad-xml.ant defaults.ant
                        mismatched-version.ant no-version.ant
                        set-base-dir.ant set-default-target.ant
                        set-project-name.ant
               proposal/myrmidon/src/java/org/apache/myrmidon/components/property
                        Resources.properties
               proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace
                        TargetState.java
               proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model
                        Dependency.java
               proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property
                        AbstractPropertyResolverTest.java
                        ClassicPropertyResolverTest.java
                        DefaultPropertyResolverTest.java
  Removed:     proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace
                        ClassicPropertyResolverTest.java
                        DefaultPropertyResolverTest.java
  Log:
  Project Model:
  
  * Removed "if" and "unless" conditions from targets.
  
  * Moved parsing of "project->target" dependencies out of DefaultWorkspace,
    into DefaultProjectBuilder.
  
  * DefaultWorkspace now detects cycles in the target dependency graph.
  
  * DefaultWorkspace now executes the implicit target for referenced projects.
  
  * Changes to DefaultProjectBuilder error reporting.
  
  * Added a few more test cases for DefaultProjectBuilder.
  
  Unit Tests:
  
  * Moved AbstractComponentTest.getLogger() up to AbstractMyrmidonTest.
  
  * Removed AbstractComponentTest.setup().  Components are now created on demand.
  
  * Use BasicLogger in unit tests.
  
  Revision  Changes    Path
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-version.ant
  
  Index: bad-version.ant
  ===================================================================
  <!-- Project with invalid version  -->
  <project version="ant2">
  </project>
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-xml.ant
  
  Index: bad-xml.ant
  ===================================================================
  this ain't xml.
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/defaults.ant
  
  Index: defaults.ant
  ===================================================================
  <!-- Use all the defaults -->
  <project version="2.0">
  </project>
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/mismatched-version.ant
  
  Index: mismatched-version.ant
  ===================================================================
  <!-- Project with mismatched version -->
  <project version="1.0.2">
  </project>
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/no-version.ant
  
  Index: no-version.ant
  ===================================================================
  <!-- Project with no version attribute -->
  <project>
  </project>
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-base-dir.ant
  
  Index: set-base-dir.ant
  ===================================================================
  <!-- Project with a non-default base directory -->
  <project version="2.0" basedir="other-base-dir">
  </project>
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-default-target.ant
  
  Index: set-default-target.ant
  ===================================================================
  <!-- Project with a non-default default target -->
  <project version="2.0" default="some-target">
  </project>
  
  
  1.1                  jakarta-ant/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-project-name.ant
  
  Index: set-project-name.ant
  ===================================================================
  <!-- Project with non-default name -->
  <project name="some-project" version="2.0">
  </project >
  
  
  1.38      +77 -90    jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/DefaultProjectBuilder.java
  
  Index: DefaultProjectBuilder.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/DefaultProjectBuilder.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- DefaultProjectBuilder.java	11 Mar 2002 06:07:23 -0000	1.37
  +++ DefaultProjectBuilder.java	13 Mar 2002 07:35:18 -0000	1.38
  @@ -8,8 +8,6 @@
   package org.apache.myrmidon.components.builder;
   
   import java.io.File;
  -import java.net.MalformedURLException;
  -import java.net.URL;
   import java.util.ArrayList;
   import java.util.HashMap;
   import javax.xml.parsers.SAXParser;
  @@ -23,13 +21,10 @@
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
  -import org.apache.myrmidon.framework.conditions.AndCondition;
  -import org.apache.myrmidon.framework.conditions.Condition;
  -import org.apache.myrmidon.framework.conditions.IsSetCondition;
  -import org.apache.myrmidon.framework.conditions.NotCondition;
   import org.apache.myrmidon.interfaces.builder.ProjectBuilder;
   import org.apache.myrmidon.interfaces.builder.ProjectException;
   import org.apache.myrmidon.interfaces.model.DefaultNameValidator;
  +import org.apache.myrmidon.interfaces.model.Dependency;
   import org.apache.myrmidon.interfaces.model.Project;
   import org.apache.myrmidon.interfaces.model.Target;
   import org.apache.myrmidon.interfaces.model.TypeLib;
  @@ -39,7 +34,7 @@
    * Default implementation to construct project from a build file.
    *
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  - * @version $Revision: 1.37 $ $Date: 2002/03/11 06:07:23 $
  + * @version $Revision: 1.38 $ $Date: 2002/03/13 07:35:18 $
    *
    * @ant:type type="project-builder" name="xml"
    * @ant:type type="project-builder" name="ant"
  @@ -78,31 +73,39 @@
       private Project build( final File file, final HashMap projects )
           throws ProjectException
       {
  -        final URL systemID = extractURL( file );
  -        final Project result = (Project)projects.get( systemID.toString() );
  -        if( null != result )
  +        try
           {
  -            return result;
  -        }
  -
  -        // Parse the project file
  -        final Configuration configuration = parseProject( systemID );
  +            // Check for cached project
  +            final String systemID = extractURL( file );
  +            final Project result = (Project)projects.get( systemID );
  +            if( null != result )
  +            {
  +                return result;
  +            }
   
  -        // Build the project model
  -        final DefaultProject project = buildProject( file, configuration );
  +            // Parse the project file
  +            final Configuration configuration = parseProject( systemID );
   
  -        projects.put( systemID.toString(), project );
  +            // Build the project model and add to cache
  +            final DefaultProject project = buildProject( file, configuration );
  +            projects.put( systemID, project );
   
  -        //build using all top-level attributes
  -        buildTopLevelProject( project, configuration, projects );
  +            // Build using all top-level attributes
  +            buildTopLevelProject( project, configuration, projects );
   
  -        return project;
  +            return project;
  +        }
  +        catch( Exception e )
  +        {
  +            final String message = REZ.getString( "ant.project-build.error", file.getAbsolutePath() );
  +            throw new ProjectException( message, e );
  +        }
       }
   
       /**
        * Parses the project.
        */
  -    private Configuration parseProject( final URL systemID )
  +    private Configuration parseProject( final String systemID )
           throws ProjectException
       {
           try
  @@ -117,13 +120,13 @@
   
               parser.setContentHandler( handler );
               parser.setErrorHandler( handler );
  -            parser.parse( systemID.toString() );
  +            parser.parse( systemID );
   
               return handler.getConfiguration();
           }
           catch( Exception e )
           {
  -            String message = REZ.getString( "ant.project-parse.error" );
  +            final String message = REZ.getString( "ant.project-parse.error" );
               throw new ProjectException( message, e );
           }
       }
  @@ -164,7 +167,7 @@
           File baseDirectory = file.getParentFile();
           if( baseDirectoryName != null )
           {
  -            baseDirectory = new File( baseDirectory, baseDirectoryName );
  +            baseDirectory = FileUtil.resolveFile( baseDirectory, baseDirectoryName );
           }
           baseDirectory = baseDirectory.getAbsoluteFile();
   
  @@ -257,7 +260,7 @@
           {
               final String message =
                   REZ.getString( "ant.malformed.version", versionString );
  -            throw new ProjectException( message, e );
  +            throw new ProjectException( message );
           }
       }
   
  @@ -338,7 +341,7 @@
           final Configuration[] implicitTasks =
               (Configuration[])implicitTaskList.toArray( new Configuration[ 0 ] );
   
  -        final Target implicitTarget = new Target( null, implicitTasks, null );
  +        final Target implicitTarget = new Target( implicitTasks, null );
           project.setImplicitTarget( implicitTarget );
       }
   
  @@ -378,26 +381,30 @@
           // Build the URL of the referenced projects
           final File baseDirectory = project.getBaseDirectory();
           final File file = FileUtil.resolveFile( baseDirectory, location );
  -        final String systemID = extractURL( file ).toString();
   
           // Locate the referenced project, building it if necessary
  -        Project other = (Project)projects.get( systemID );
  -        if( null == other )
  -        {
  -            other = build( file, projects );
  -        }
  +        final Project other = build( file, projects );
   
           // Add the reference
           project.addProject( name, other );
       }
   
  -    private URL extractURL( final File file ) throws ProjectException
  +    /**
  +     * Validates a project file name, and builds the canonical URL for it.
  +     */
  +    private String extractURL( final File file ) throws ProjectException
       {
  +        if( ! file.isFile() )
  +        {
  +            final String message = REZ.getString( "ant.no-project-file.error" );
  +            throw new ProjectException( message );
  +        }
  +
           try
           {
  -            return file.toURL();
  +            return file.getCanonicalFile().toURL().toString();
           }
  -        catch( MalformedURLException e )
  +        catch( Exception e )
           {
               final String message = REZ.getString( "ant.project-unexpected.error" );
               throw new ProjectException( message, e );
  @@ -443,8 +450,6 @@
       {
           final String name = target.getAttribute( "name", null );
           final String depends = target.getAttribute( "depends", null );
  -        final String ifCondition = target.getAttribute( "if", null );
  -        final String unlessCondition = target.getAttribute( "unless", null );
   
           verifyTargetName( name, target );
   
  @@ -454,10 +459,8 @@
               getLogger().debug( message );
           }
   
  -        final String[] dependencies = buildDependsList( depends, target );
  -        final Condition condition = buildCondition( ifCondition, unlessCondition );
  -        final Target defaultTarget =
  -            new Target( condition, target.getChildren(), dependencies );
  +        final Dependency[] dependencies = buildDependsList( depends, target );
  +        final Target defaultTarget = new Target( target.getChildren(), dependencies );
   
           //add target to project
           project.addTarget( name, defaultTarget );
  @@ -485,70 +488,54 @@
           }
       }
   
  -    private String[] buildDependsList( final String depends, final Configuration target )
  +    private Dependency[] buildDependsList( final String depends, final Configuration target )
           throws ProjectException
       {
  -        String[] dependencies = null;
  -
           //apply depends attribute
  -        if( null != depends )
  +        if( null == depends )
           {
  -            final String[] elements = StringUtil.split( depends, "," );
  -            final ArrayList dependsList = new ArrayList();
  -
  -            for( int i = 0; i < elements.length; i++ )
  -            {
  -                final String dependency = elements[ i ].trim();
  -
  -                if( 0 == dependency.length() )
  -                {
  -                    final String message = REZ.getString( "ant.target-bad-dependency.error",
  -                                                          target.getName(),
  -                                                          target.getLocation() );
  -                    throw new ProjectException( message );
  -                }
  -
  -                if( getLogger().isDebugEnabled() )
  -                {
  -                    final String message = REZ.getString( "ant.target-dependency.notice", dependency );
  -                    getLogger().debug( message );
  -                }
  -
  -                dependsList.add( dependency );
  -            }
  -
  -            dependencies = (String[])dependsList.toArray( new String[ 0 ] );
  +            return null;
           }
  -        return dependencies;
  -    }
   
  -    private Condition buildCondition( final String ifCondition,
  -                                      final String unlessCondition )
  -    {
  -        final AndCondition condition = new AndCondition();
  +        final String[] elements = StringUtil.split( depends, "," );
  +        final ArrayList dependsList = new ArrayList();
   
  -        // Add the 'if' condition
  -        if( null != ifCondition )
  +        for( int i = 0; i < elements.length; i++ )
           {
  +            final String dependency = elements[ i ].trim();
  +
               if( getLogger().isDebugEnabled() )
               {
  -                final String message = REZ.getString( "ant.target-if.notice", ifCondition );
  +                final String message = REZ.getString( "ant.target-dependency.notice", dependency );
                   getLogger().debug( message );
               }
  -            condition.add( new IsSetCondition( ifCondition ) );
  -        }
   
  -        // Add the 'unless' condition
  -        if( null != unlessCondition )
  -        {
  -            if( getLogger().isDebugEnabled() )
  +            // Split project->target dependencies
  +            final int sep = dependency.indexOf( "->" );
  +            final String projectName;
  +            final String targetName;
  +            if( sep != -1 )
               {
  -                final String message = REZ.getString( "ant.target-unless.notice", unlessCondition );
  -                getLogger().debug( message );
  +                projectName = dependency.substring( 0, sep );
  +                targetName = dependency.substring( sep + 2 );
  +            }
  +            else
  +            {
  +                projectName = null;
  +                targetName = dependency;
  +            }
  +
  +            if( targetName.length() == 0 || ( projectName != null && projectName.length() == 0 ) )
  +            {
  +                final String message = REZ.getString( "ant.target-bad-dependency.error",
  +                                                      target.getName(),
  +                                                      target.getLocation() );
  +                throw new ProjectException( message );
               }
  -            condition.add( new NotCondition( new IsSetCondition( unlessCondition ) ) );
  +
  +            dependsList.add( new Dependency( projectName, targetName ) );
           }
   
  -        return condition;
  +        return (Dependency[])dependsList.toArray( new Dependency[dependsList.size() ] );
       }
   }
  
  
  
  1.7       +6 -6      jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/Resources.properties,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Resources.properties	11 Mar 2002 06:07:23 -0000	1.6
  +++ Resources.properties	13 Mar 2002 07:35:18 -0000	1.7
  @@ -9,11 +9,10 @@
   
   ant.project-banner.notice=Project {0} base directory: {1}.
   ant.target-parse.notice=Parsing target: {0}.
  -ant.target-if.notice=Target if condition: {0}
  -ant.target-unless.notice=Target unless condition: {0}
   ant.target-dependency.notice=Target dependency: {0}
   ant.project-unexpected.error=Unexpected error building project.
  -ant.project-parse.error=Error parsing project.
  +ant.project-parse.error=Could not parse project file.
  +ant.project-build.error=Could not load project from "{0}".
   ant.no-project-element.error=Project file must be enclosed in project element.
   ant.unknown-toplevel-element.error=Unknown top-level element {0} at {1}.
   ant.project-bad-name.error=Invalid project name.
  @@ -26,9 +25,10 @@
   ant.target-noname.error=Discovered un-named target at {0}.
   ant.target-bad-name.error=Target with an invalid name at {0}.
   ant.target-bad-dependency.error=Discovered empty dependency in target {0} at {1}.
  -ant.malformed.version=Malformed version string "{0}" specified in version attribute of project.
  -ant.version-missing.error=Missing version attribute from project.
  -ant.bad-version.error=Incompatible build file version detected. Expected {0} but found {1}.
  +ant.malformed.version=Project has an invalid version "{0}".
  +ant.version-missing.error=Project has no version attribute.
  +ant.bad-version.error=Incompatible build file version detected. Expected version {0} but found version {1}.
  +ant.no-project-file.error=Project file does not exist, or is not a file.
   
   duplicate-project.error=Can not have two projects referenced in a file with the name {0}.
   duplicate-target.error=Can not have two targets in a file with the name {0}.
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/property/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  #AbstractPropertyResolver
  prop.mismatched-braces.error=Malformed property with mismatched }'s.
  prop.missing-value.error=Unable to find "{0}" to expand during property resolution.
  
  
  
  1.27      +2 -3      jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java
  
  Index: DefaultTaskContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- DefaultTaskContext.java	12 Mar 2002 11:10:52 -0000	1.26
  +++ DefaultTaskContext.java	13 Mar 2002 07:35:18 -0000	1.27
  @@ -15,9 +15,9 @@
   import org.apache.avalon.excalibur.io.FileUtil;
   import org.apache.avalon.framework.context.Context;
   import org.apache.avalon.framework.context.ContextException;
  +import org.apache.avalon.framework.logger.Logger;
   import org.apache.avalon.framework.service.ServiceException;
   import org.apache.avalon.framework.service.ServiceManager;
  -import org.apache.avalon.framework.logger.Logger;
   import org.apache.myrmidon.api.TaskContext;
   import org.apache.myrmidon.api.TaskException;
   import org.apache.myrmidon.interfaces.model.DefaultNameValidator;
  @@ -27,7 +27,7 @@
    * Default implementation of TaskContext.
    *
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  - * @version $Revision: 1.26 $ $Date: 2002/03/12 11:10:52 $
  + * @version $Revision: 1.27 $ $Date: 2002/03/13 07:35:18 $
    */
   public class DefaultTaskContext
       implements TaskContext, Context
  @@ -60,7 +60,6 @@
           m_parent = parent;
           m_serviceManager = serviceManager;
           m_logger = logger;
  -        //m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class );
       }
   
       /**
  
  
  
  1.32      +93 -67    jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java
  
  Index: DefaultWorkspace.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- DefaultWorkspace.java	12 Mar 2002 09:45:10 -0000	1.31
  +++ DefaultWorkspace.java	13 Mar 2002 07:35:18 -0000	1.32
  @@ -26,12 +26,12 @@
   import org.apache.avalon.framework.service.Serviceable;
   import org.apache.myrmidon.api.TaskContext;
   import org.apache.myrmidon.api.TaskException;
  -import org.apache.myrmidon.framework.conditions.Condition;
   import org.apache.myrmidon.interfaces.deployer.Deployer;
   import org.apache.myrmidon.interfaces.deployer.DeploymentException;
   import org.apache.myrmidon.interfaces.deployer.TypeDeployer;
   import org.apache.myrmidon.interfaces.executor.ExecutionFrame;
   import org.apache.myrmidon.interfaces.executor.Executor;
  +import org.apache.myrmidon.interfaces.model.Dependency;
   import org.apache.myrmidon.interfaces.model.Project;
   import org.apache.myrmidon.interfaces.model.Target;
   import org.apache.myrmidon.interfaces.model.TypeLib;
  @@ -43,7 +43,7 @@
    * This is the default implementation of Workspace.
    *
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  - * @version $Revision: 1.31 $ $Date: 2002/03/12 09:45:10 $
  + * @version $Revision: 1.32 $ $Date: 2002/03/13 07:35:18 $
    */
   public class DefaultWorkspace
       extends AbstractLogEnabled
  @@ -123,9 +123,7 @@
   
           m_listenerSupport.projectStarted( project.getProjectName() );
   
  -        executeTarget( project, "<init>", project.getImplicitTarget(), entry.getFrame() );
  -
  -        execute( project, target, entry );
  +        executeTarget( entry, target );
   
           m_listenerSupport.projectFinished( project.getProjectName() );
       }
  @@ -307,105 +305,130 @@
       /**
        * Helper method to execute a target.
        *
  -     * @param project the Project
  -     * @param targetName the name of the target
  -     * @param entry the context
  +     * @param entry the project to execute
  +     * @param targetName the name of the target to execute
        * @exception TaskException if an error occurs
        */
  -    private void execute( final Project project,
  -                          final String targetName,
  -                          final ProjectEntry entry )
  +    private void executeTarget( final ProjectEntry entry,
  +                          final String targetName )
           throws TaskException
       {
  -        final int index = targetName.indexOf( "->" );
  -        if( -1 != index )
  +        // Locate the target
  +        final Target target = entry.getProject().getTarget( targetName );
  +        if( null == target )
           {
  -            final String name = targetName.substring( 0, index );
  -            final String otherTargetName = targetName.substring( index + 2 );
  +            final String message = REZ.getString( "no-target.error", targetName );
  +            throw new TaskException( message );
  +        }
   
  -            final Project otherProject = getProject( name, project );
  -            final ProjectEntry otherEntry = getProjectEntry( otherProject );
  +        executeTarget( entry, targetName, target );
  +    }
  +
  +    /**
  +     * Executes a target.  Does not execute the target if it has already been
  +     * executed.  Executes the dependencies of the target, before executing
  +     * the target itself.
  +     *
  +     * @param name the name of target
  +     * @param target the target
  +     * @param entry the project in which to execute
  +     * @exception TaskException if an error occurs
  +     */
  +    private void executeTarget( final ProjectEntry entry,
  +                                final String name,
  +                                final Target target )
  +        throws TaskException
  +    {
  +        final Project project = entry.getProject();
   
  -            //Execute target in referenced project
  -            execute( otherProject, otherTargetName, otherEntry );
  +        // Check target state, to see if it has already been executed, and
  +        // to check for dependency cycles
  +        final TargetState state = entry.getTargetState( target );
  +        if( state == TargetState.FINISHED )
  +        {
  +            // Target has been executed
               return;
           }
  -
  -        final Target target = project.getTarget( targetName );
  -        if( null == target )
  +        if( state == TargetState.TRAVERSING )
           {
  -            final String message = REZ.getString( "no-target.error", targetName );
  +            // Cycle in target dependencies
  +            final String message = REZ.getString( "target-dependency-cycle.error", name );
               throw new TaskException( message );
           }
   
  -        //add target to list of targets executed
  -        entry.completeTarget( targetName );
  +        // Set state to indicate this target has been started
  +        entry.setTargetState( target, TargetState.TRAVERSING );
  +
  +        // Execute the target's dependencies
   
  -        //execute all dependencies
  -        final String[] dependencies = target.getDependencies();
  +        // Implicit target first
  +        if( target != project.getImplicitTarget() )
  +        {
  +            executeTarget( entry, "<init>", project.getImplicitTarget() );
  +        }
  +
  +        // Named dependencies
  +        final Dependency[] dependencies = target.getDependencies();
           for( int i = 0; i < dependencies.length; i++ )
           {
  -            if( !entry.isTargetCompleted( dependencies[ i ] ) )
  +            final Dependency dependency = dependencies[ i ];
  +            final String otherProjectName = dependency.getProjectName();
  +            if( otherProjectName != null )
  +            {
  +                // Dependency in a referenced project
  +                final Project otherProject = getProject( otherProjectName, project );
  +                final ProjectEntry otherEntry = getProjectEntry( otherProject );
  +                executeTarget( otherEntry, dependency.getTargetName() );
  +            }
  +            else
               {
  -                execute( project, dependencies[ i ], entry );
  +                // Dependency in this project
  +                executeTarget( entry, dependency.getTargetName() );
               }
           }
   
  -        executeTarget( project, targetName, target, entry.getFrame() );
  +        // Now execute the target itself
  +        executeTargetNoDeps( entry, name, target );
  +
  +        // Mark target as complete
  +        entry.setTargetState( target, TargetState.FINISHED );
       }
   
       /**
  -     * Method to execute a particular target instance.
  +     * Executes a target.  Does not check whether the target has been
  +     * executed already, and does not check that its dependencies have been
  +     * executed.
        *
  -     * @param name the name of target
  -     * @param target the target
  -     * @param frame the frame in which to execute
  -     * @exception TaskException if an error occurs
  +     * @param entry the project to execute the target in.
  +     * @param name the name of the target.
  +     * @param target the target itself
        */
  -    private void executeTarget( final Project project,
  -                                final String name,
  -                                final Target target,
  -                                final ExecutionFrame frame )
  +    private void executeTargetNoDeps( final ProjectEntry entry,
  +                                      final String name,
  +                                      final Target target )
           throws TaskException
       {
  -        //notify listeners
  +        final Project project = entry.getProject();
  +
  +        // Notify listeners
           m_listenerSupport.targetStarted( project.getProjectName(), name );
   
  -        //check the condition associated with target.
  -        //if it is not satisfied then skip target
  -        final Condition condition = target.getCondition();
  -        if( null != condition )
  +        if( getLogger().isDebugEnabled() )
           {
  -            try
  -            {
  -                final boolean result = condition.evaluate( frame.getContext() );
  -                if( !result )
  -                {
  -                    final String message = REZ.getString( "skip-target.notice", name );
  -                    getLogger().debug( message );
  -                    return;
  -                }
  -            }
  -            catch( final TaskException te )
  -            {
  -                final String message = REZ.getString( "condition-eval.error", name );
  -                throw new TaskException( message, te );
  -            }
  +            final String message = REZ.getString( "exec-target.notice", project.getProjectName(), name );
  +            getLogger().debug( message );
           }
   
  -        final String message = REZ.getString( "exec-target.notice", name );
  -        getLogger().debug( message );
  -
           //frame.getContext().setProperty( Project.TARGET, target );
   
  -        //execute all tasks assciated with target
  +        // Execute all tasks assciated with target
           final Configuration[] tasks = target.getTasks();
           for( int i = 0; i < tasks.length; i++ )
           {
  -            executeTask( tasks[ i ], frame );
  +            executeTask( tasks[ i ], entry.getFrame() );
           }
   
  -        //notify listeners
  +        // Notify listeners
           m_listenerSupport.targetFinished();
       }
   
  @@ -421,8 +444,11 @@
       {
           final String name = task.getName();
   
  -        final String message = REZ.getString( "exec-task.notice", name );
  -        getLogger().debug( message );
  +        if( getLogger().isDebugEnabled() )
  +        {
  +            final String message = REZ.getString( "exec-task.notice", name );
  +            getLogger().debug( message );
  +        }
   
           //is setting name even necessary ???
           frame.getContext().setProperty( TaskContext.NAME, name );
  
  
  
  1.8       +18 -8     jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ProjectEntry.java
  
  Index: ProjectEntry.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ProjectEntry.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ProjectEntry.java	12 Mar 2002 10:17:28 -0000	1.7
  +++ ProjectEntry.java	13 Mar 2002 07:35:18 -0000	1.8
  @@ -7,21 +7,26 @@
    */
   package org.apache.myrmidon.components.workspace;
   
  -import java.util.ArrayList;
  +import java.util.HashMap;
  +import java.util.Map;
   import org.apache.myrmidon.interfaces.executor.ExecutionFrame;
   import org.apache.myrmidon.interfaces.model.Project;
  +import org.apache.myrmidon.interfaces.model.Target;
   
   /**
  - * This contains detaisl for each project that is managed by ProjectManager.
  + * This contains details for each project that is being executed by a
  + * DefaultWorkspace.
    *
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  - * @version $Revision: 1.7 $ $Date: 2002/03/12 10:17:28 $
  + * @version $Revision: 1.8 $ $Date: 2002/03/13 07:35:18 $
    */
   final class ProjectEntry
   {
       private final Project m_project;
       private final ExecutionFrame m_frame;
  -    private final ArrayList m_targetsCompleted = new ArrayList();
  +
  +    /** Map from Target -> TargetState for that target. */
  +    private final Map m_targetState = new HashMap();
   
       public ProjectEntry( final Project project,
                            final ExecutionFrame frame )
  @@ -40,13 +45,18 @@
           return m_frame;
       }
   
  -    public boolean isTargetCompleted( final String target )
  +    public TargetState getTargetState( final Target target )
       {
  -        return m_targetsCompleted.contains( target );
  +        TargetState state = (TargetState)m_targetState.get( target );
  +        if( state == null )
  +        {
  +            state = TargetState.NOT_STARTED;
  +        }
  +        return state;
       }
   
  -    public void completeTarget( final String target )
  +    public void setTargetState( final Target target, final TargetState state )
       {
  -        m_targetsCompleted.add( target );
  +        m_targetState.put( target, state );
       }
   }
  
  
  
  1.10      +2 -7      jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- Resources.properties	11 Mar 2002 06:07:24 -0000	1.9
  +++ Resources.properties	13 Mar 2002 07:35:18 -0000	1.10
  @@ -5,10 +5,9 @@
   bad-frame.error=Error setting up ExecutionFrame.
   no-project.error=Project {0} not found.
   no-target.error=Target {0} not found.
  -skip-target.notice=Skipping target {0} as it does not satisfy condition.
  -condition-eval.error=Error evaluating Condition for target {0}.
  -exec-target.notice=Executing target {0}.
  +exec-target.notice=Executing project {0}, target {1}.
   exec-task.notice=Executing task {0}.
  +target-dependency-cycle.error=Cycle in dependencies for target {0}.
   
   #DefaultTaskContext
   unknown-prop.error=Unknown property {0}.
  @@ -18,7 +17,3 @@
   bad-resolve.error=Unable to resolve value "{0}".
   bad-find-service.error=Could not find service "{0}".
   bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}.
  -
  -#AbstractPropertyResolver
  -prop.mismatched-braces.error=Malformed property with mismatched }'s.
  -prop.missing-value.error=Unable to find "{0}" to expand during property resolution.
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/TargetState.java
  
  Index: TargetState.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.workspace;
  
  /**
   * An enumerated type that represents the dependency traversal state of a
   * target.
   *
   * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/03/13 07:35:18 $
   */
  final class TargetState
  {
      private TargetState()
      {
      }
  
      /** Target has not been started. */
      public final static TargetState NOT_STARTED = new TargetState();
  
      /**
       * Target has been started, and the dependencies of the target are being
       * traversed.
       */
      public final static TargetState TRAVERSING = new TargetState();
  
      /** Target has been completed. */
      public final static TargetState FINISHED = new TargetState();
  }
  
  
  
  1.10      +2 -2      jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder/ProjectBuilder.java
  
  Index: ProjectBuilder.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder/ProjectBuilder.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ProjectBuilder.java	11 Mar 2002 06:07:24 -0000	1.9
  +++ ProjectBuilder.java	13 Mar 2002 07:35:19 -0000	1.10
  @@ -13,7 +13,7 @@
    * Interface implemented by components that build projects from sources.
    *
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  - * @version $Revision: 1.9 $ $Date: 2002/03/11 06:07:24 $
  + * @version $Revision: 1.10 $ $Date: 2002/03/13 07:35:19 $
    * @ant:role shorthand="project-builder"
    */
   public interface ProjectBuilder
  @@ -23,7 +23,7 @@
       /**
        * build a project from source.
        *
  -     * @param source the source
  +     * @param source the project file path.
        * @return the constructed Project
        * @exception ProjectException if an error occurs
        */
  
  
  
  1.7       +6 -23     jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Target.java
  
  Index: Target.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Target.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Target.java	4 Mar 2002 04:23:38 -0000	1.6
  +++ Target.java	13 Mar 2002 07:35:19 -0000	1.7
  @@ -9,31 +9,24 @@
   
   import java.util.ArrayList;
   import org.apache.avalon.framework.configuration.Configuration;
  -import org.apache.myrmidon.framework.conditions.Condition;
   
   /**
    * Targets in build file.
    *
    * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  - * @version $Revision: 1.6 $ $Date: 2002/03/04 04:23:38 $
  + * @version $Revision: 1.7 $ $Date: 2002/03/13 07:35:19 $
    */
   public class Target
   {
       private final ArrayList m_dependencies = new ArrayList();
       private final ArrayList m_tasks = new ArrayList();
  -    private final Condition m_condition;
   
       /**
  -     * Constructor taking condition for target.
  -     *
  -     * @param condition the condition
  +     * Constructs a target.
        */
  -    public Target( final Condition condition,
  -                   final Configuration[] tasks,
  -                   final String[] dependencies )
  +    public Target( final Configuration[] tasks,
  +                   final Dependency[] dependencies )
       {
  -        m_condition = condition;
  -
           for( int i = 0; i < tasks.length; i++ )
           {
               m_tasks.add( tasks[ i ] );
  @@ -49,23 +42,13 @@
       }
   
       /**
  -     * Get condition under which target is executed.
  -     *
  -     * @return the condition for target or null
  -     */
  -    public final Condition getCondition()
  -    {
  -        return m_condition;
  -    }
  -
  -    /**
        * Get dependencies of target
        *
        * @return the dependency list
        */
  -    public final String[] getDependencies()
  +    public final Dependency[] getDependencies()
       {
  -        return (String[])m_dependencies.toArray( new String[ 0 ] );
  +        return (Dependency[])m_dependencies.toArray( new Dependency[ 0 ] );
       }
   
       /**
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Dependency.java
  
  Index: Dependency.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.interfaces.model;
  
  /**
   * A dependency for a target.
   *
   * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/03/13 07:35:19 $
   */
  public class Dependency
  {
      private final String m_projectName;
      private final String m_targetName;
  
      public Dependency( final String projectName, final String targetName )
      {
          m_projectName = projectName;
          m_targetName = targetName;
      }
  
      public String getProjectName()
      {
          return m_projectName;
      }
  
      public String getTargetName()
      {
          return m_targetName;
      }
  }
  
  
  
  1.6       +8 -0      jakarta-ant/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java
  
  Index: AbstractFileSystemTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- AbstractFileSystemTest.java	9 Mar 2002 10:31:31 -0000	1.5
  +++ AbstractFileSystemTest.java	13 Mar 2002 07:35:19 -0000	1.6
  @@ -90,6 +90,14 @@
       }
   
       /**
  +     * Cleans-up test.
  +     */
  +    protected void tearDown() throws Exception
  +    {
  +        m_manager.close();
  +    }
  +
  +    /**
        * Tests resolution of absolute URI.
        */
       public void testAbsoluteURI() throws Exception
  
  
  
  1.8       +45 -21    jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java
  
  Index: AbstractMyrmidonTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- AbstractMyrmidonTest.java	2 Mar 2002 03:56:23 -0000	1.7
  +++ AbstractMyrmidonTest.java	13 Mar 2002 07:35:19 -0000	1.8
  @@ -11,13 +11,8 @@
   import java.io.IOException;
   import junit.framework.TestCase;
   import org.apache.avalon.framework.ExceptionUtil;
  -import org.apache.avalon.framework.logger.LogKitLogger;
   import org.apache.avalon.framework.logger.Logger;
  -import org.apache.log.Hierarchy;
  -import org.apache.log.LogTarget;
  -import org.apache.log.Priority;
  -import org.apache.log.format.PatternFormatter;
  -import org.apache.log.output.io.StreamTarget;
  +import org.apache.myrmidon.frontends.BasicLogger;
   
   /**
    * A base class for Myrmidon tests.  Provides utility methods for locating
  @@ -30,8 +25,7 @@
   {
       private final File m_testBaseDir;
       private final File m_baseDir;
  -
  -    private final static String PATTERN = "[%8.8{category}] %{message}\\n%{throwable}";
  +    private Logger m_logger;
   
       public AbstractMyrmidonTest( String name )
       {
  @@ -50,9 +44,38 @@
        */
       protected File getTestResource( final String name )
       {
  +        return getTestResource( name, true );
  +    }
  +
  +    /**
  +     * Locates a test resource.
  +     */
  +    protected File getTestResource( final String name, final boolean mustExist )
  +    {
  +        File file = new File( m_testBaseDir, name );
  +        file = getCanonicalFile( file );
  +        if( mustExist )
  +        {
  +            assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() );
  +        }
  +        else
  +        {
  +            assertTrue( "Test file \"" + file + "\" should not exist.", !file.exists() );
  +        }
  +
  +        return file;
  +    }
  +
  +    /**
  +     * Locates a test directory, creating it if it does not exist.
  +     */
  +    protected File getTestDirectory( final String name )
  +    {
           File file = new File( m_testBaseDir, name );
           file = getCanonicalFile( file );
  -        assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() );
  +
  +        assertTrue( "Test directory \"" + file + "\" does not exist or is not a directory.",
  +                    file.isDirectory() || file.mkdirs() );
           return file;
       }
   
  @@ -83,18 +106,13 @@
       /**
        * Creates a logger.
        */
  -    protected Logger createLogger()
  +    protected Logger getLogger()
       {
  -        // Setup a logger
  -        final Priority priority = Priority.WARN;
  -        final org.apache.log.Logger targetLogger = Hierarchy.getDefaultHierarchy().getLoggerFor( "myrmidon" );
  -
  -        final PatternFormatter formatter = new PatternFormatter( PATTERN );
  -        final StreamTarget target = new StreamTarget( System.out, formatter );
  -        targetLogger.setLogTargets( new LogTarget[]{target} );
  -        targetLogger.setPriority( priority );
  -
  -        return new LogKitLogger( targetLogger );
  +        if( m_logger == null )
  +        {
  +            m_logger = new BasicLogger( "[test]", BasicLogger.LEVEL_WARN );
  +        }
  +        return m_logger;
       }
   
       /**
  @@ -105,6 +123,12 @@
        */
       protected void assertSameMessage( final String[] messages, final Throwable throwable )
       {
  +        //System.out.println( "exception:" );
  +        //for( Throwable t = throwable; t != null; t = ExceptionUtil.getCause( t, true ) )
  +        //{
  +        //    System.out.println( "  " + t.getMessage() );
  +        //}
  +
           Throwable current = throwable;
           for( int i = 0; i < messages.length; i++ )
           {
  @@ -125,7 +149,7 @@
        */
       protected void assertSameMessage( final String message, final Throwable throwable )
       {
  -        assertEquals( message, throwable.getMessage() );
  +        assertSameMessage( new String[] { message }, throwable );
       }
   
       /**
  
  
  
  1.5       +2 -2      jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractProjectTest.java
  
  Index: AbstractProjectTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractProjectTest.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- AbstractProjectTest.java	1 Mar 2002 08:54:34 -0000	1.4
  +++ AbstractProjectTest.java	13 Mar 2002 07:35:19 -0000	1.5
  @@ -20,7 +20,7 @@
    * A base class for test cases which need to execute projects.
    *
    * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
  - * @version $Revision: 1.4 $ $Date: 2002/03/01 08:54:34 $
  + * @version $Revision: 1.5 $ $Date: 2002/03/13 07:35:19 $
    */
   public class AbstractProjectTest
       extends AbstractMyrmidonTest
  @@ -54,7 +54,7 @@
               // Need to set the context classloader - The default embeddor uses it
               Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
   
  -            final Logger logger = createLogger();
  +            final Logger logger = getLogger();
               m_embeddor = new DefaultEmbeddor();
               m_embeddor.enableLogging( logger );
   
  
  
  
  1.15      +72 -85    jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java
  
  Index: AbstractComponentTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- AbstractComponentTest.java	12 Mar 2002 10:20:22 -0000	1.14
  +++ AbstractComponentTest.java	13 Mar 2002 07:35:19 -0000	1.15
  @@ -14,7 +14,6 @@
   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.ServiceException;
   import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.avalon.framework.service.Serviceable;
   import org.apache.myrmidon.AbstractMyrmidonTest;
  @@ -24,20 +23,19 @@
   import org.apache.myrmidon.components.converter.DefaultMasterConverter;
   import org.apache.myrmidon.components.deployer.DefaultDeployer;
   import org.apache.myrmidon.components.extensions.DefaultExtensionManager;
  +import org.apache.myrmidon.components.property.DefaultPropertyResolver;
   import org.apache.myrmidon.components.role.DefaultRoleManager;
   import org.apache.myrmidon.components.type.DefaultTypeManager;
  -import org.apache.myrmidon.components.property.DefaultPropertyResolver;
   import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager;
   import org.apache.myrmidon.interfaces.configurer.Configurer;
   import org.apache.myrmidon.interfaces.converter.ConverterRegistry;
   import org.apache.myrmidon.interfaces.deployer.Deployer;
   import org.apache.myrmidon.interfaces.extensions.ExtensionManager;
  +import org.apache.myrmidon.interfaces.property.PropertyResolver;
   import org.apache.myrmidon.interfaces.role.RoleInfo;
   import org.apache.myrmidon.interfaces.role.RoleManager;
   import org.apache.myrmidon.interfaces.type.DefaultTypeFactory;
  -import org.apache.myrmidon.interfaces.type.TypeException;
   import org.apache.myrmidon.interfaces.type.TypeManager;
  -import org.apache.myrmidon.interfaces.property.PropertyResolver;
   
   /**
    * A base class for tests for the default components.
  @@ -48,7 +46,6 @@
       extends AbstractMyrmidonTest
   {
       private DefaultServiceManager m_serviceManager;
  -    private Logger m_logger;
   
       public AbstractComponentTest( final String name )
       {
  @@ -58,95 +55,85 @@
       /**
        * Returns the component manager containing the components to test.
        */
  -    protected final ServiceManager getServiceManager()
  +    protected final ServiceManager getServiceManager() throws Exception
       {
  -        return m_serviceManager;
  -    }
  +        if( m_serviceManager == null )
  +        {
  +            Logger logger = getLogger();
   
  -    protected final Logger getLogger()
  -    {
  -        return m_logger;
  +            // Create the components
  +            m_serviceManager = new DefaultServiceManager();
  +            List components = new ArrayList();
  +
  +            Object component = new DefaultMasterConverter();
  +            m_serviceManager.put( Converter.ROLE, component );
  +            components.add( component );
  +
  +            component = new DefaultConverterRegistry();
  +            m_serviceManager.put( ConverterRegistry.ROLE, component );
  +            components.add( component );
  +
  +            component = new DefaultTypeManager();
  +            m_serviceManager.put( TypeManager.ROLE, component );
  +            components.add( component );
  +
  +            component = new DefaultConfigurer();
  +            m_serviceManager.put( Configurer.ROLE, component );
  +            components.add( component );
  +
  +            component = new DefaultDeployer();
  +            m_serviceManager.put( Deployer.ROLE, component );
  +            components.add( component );
  +
  +            final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager();
  +            classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() );
  +            m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr );
  +            components.add( classLoaderMgr );
  +
  +            component = new DefaultExtensionManager();
  +            m_serviceManager.put( ExtensionManager.ROLE, component );
  +            components.add( component );
  +
  +            component = new DefaultRoleManager();
  +            m_serviceManager.put( RoleManager.ROLE, component );
  +            components.add( component );
  +
  +            component = new DefaultPropertyResolver();
  +            m_serviceManager.put( PropertyResolver.ROLE, component );
  +            components.add( component );
  +
  +            // Log enable the components
  +            for( Iterator iterator = components.iterator(); iterator.hasNext(); )
  +            {
  +                Object obj = iterator.next();
  +                if( obj instanceof LogEnabled )
  +                {
  +                    final LogEnabled logEnabled = (LogEnabled)obj;
  +                    logEnabled.enableLogging( logger );
  +                }
  +            }
  +
  +            // Compose the components
  +            for( Iterator iterator = components.iterator(); iterator.hasNext(); )
  +            {
  +                Object obj = iterator.next();
  +                if( obj instanceof Serviceable )
  +                {
  +                    final Serviceable serviceable = (Serviceable)obj;
  +                    serviceable.service( m_serviceManager );
  +                }
  +            }
  +        }
  +        return m_serviceManager;
       }
   
       /**
        * Returns the type manager.
        */
       protected TypeManager getTypeManager()
  -        throws ServiceException
  -    {
  -        return (TypeManager)getServiceManager().lookup( TypeManager.ROLE );
  -    }
  -
  -    /**
  -     * Setup the test case - prepares the set of components.
  -     */
  -    protected void setUp()
           throws Exception
       {
  -        m_logger = createLogger();
  -
  -        // Create the components
  -        m_serviceManager = new DefaultServiceManager();
  -        List components = new ArrayList();
  -
  -        Object component = new DefaultMasterConverter();
  -        m_serviceManager.put( Converter.ROLE, component );
  -        components.add( component );
  -
  -        component = new DefaultConverterRegistry();
  -        m_serviceManager.put( ConverterRegistry.ROLE, component );
  -        components.add( component );
  -
  -        component = new DefaultTypeManager();
  -        m_serviceManager.put( TypeManager.ROLE, component );
  -        components.add( component );
  -
  -        component = new DefaultConfigurer();
  -        m_serviceManager.put( Configurer.ROLE, component );
  -        components.add( component );
  -
  -        component = new DefaultDeployer();
  -        m_serviceManager.put( Deployer.ROLE, component );
  -        components.add( component );
  -
  -        final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager();
  -        classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() );
  -        m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr );
  -        components.add( classLoaderMgr );
  -
  -        component = new DefaultExtensionManager();
  -        m_serviceManager.put( ExtensionManager.ROLE, component );
  -        components.add( component );
  -
  -        component = new DefaultRoleManager();
  -        m_serviceManager.put( RoleManager.ROLE, component );
  -        components.add( component );
  -
  -        component = new DefaultPropertyResolver();
  -        m_serviceManager.put( PropertyResolver.ROLE, component );
  -        components.add( component );
  -
  -        // Log enable the components
  -        for( Iterator iterator = components.iterator(); iterator.hasNext(); )
  -        {
  -            Object obj = iterator.next();
  -            if( obj instanceof LogEnabled )
  -            {
  -                final LogEnabled logEnabled = (LogEnabled)obj;
  -                logEnabled.enableLogging( m_logger );
  -            }
  -        }
  -
  -        // Compose the components
  -        for( Iterator iterator = components.iterator(); iterator.hasNext(); )
  -        {
  -            Object obj = iterator.next();
  -            if( obj instanceof Serviceable )
  -            {
  -                final Serviceable serviceable = (Serviceable)obj;
  -                serviceable.service( m_serviceManager );
  -            }
  -        }
  +        return (TypeManager)getServiceManager().lookup( TypeManager.ROLE );
       }
   
       /**
  @@ -179,7 +166,7 @@
       protected void registerConverter( final Class converterClass,
                                         final Class sourceClass,
                                         final Class destClass )
  -        throws ServiceException, TypeException
  +        throws Exception
       {
           ConverterRegistry converterRegistry = (ConverterRegistry)getServiceManager().lookup( ConverterRegistry.ROLE );
           converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() );
  
  
  
  1.2       +237 -6    jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java
  
  Index: DefaultProjectBuilderTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DefaultProjectBuilderTest.java	11 Mar 2002 06:07:24 -0000	1.1
  +++ DefaultProjectBuilderTest.java	13 Mar 2002 07:35:19 -0000	1.2
  @@ -8,21 +8,25 @@
   package org.apache.myrmidon.components.builder;
   
   import java.io.File;
  +import java.util.Arrays;
   import org.apache.avalon.excalibur.i18n.ResourceManager;
   import org.apache.avalon.excalibur.i18n.Resources;
  +import org.apache.avalon.excalibur.io.FileUtil;
   import org.apache.myrmidon.AbstractMyrmidonTest;
  +import org.apache.myrmidon.interfaces.builder.ProjectException;
  +import org.apache.myrmidon.interfaces.model.Project;
   
   /**
    * Test cases for {@link DefaultProjectBuilder}.
    *
    * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a>
  - * @version $Revision: 1.1 $ $Date: 2002/03/11 06:07:24 $
  + * @version $Revision: 1.2 $ $Date: 2002/03/13 07:35:19 $
    */
   public class DefaultProjectBuilderTest
       extends AbstractMyrmidonTest
   {
       private final static Resources REZ
  -        = ResourceManager.getPackageResources( DefaultProjectBuilder.class );
  +        = ResourceManager.getPackageResources( DefaultProjectBuilderTest.class );
   
       private DefaultProjectBuilder m_builder;
   
  @@ -35,11 +39,227 @@
       {
           super.setUp();
           m_builder = new DefaultProjectBuilder();
  -        m_builder.enableLogging( createLogger() );
  +        m_builder.enableLogging( getLogger() );
       }
   
       /**
  -     * Test validation of project and target names.
  +     * Creates a project, with default values set.
  +     */
  +    private DefaultProject createProject( final File projFile )
  +    {
  +        final DefaultProject project = new DefaultProject();
  +        project.setProjectName( FileUtil.removeExtension( projFile.getName() ) );
  +        project.setBaseDirectory( getTestDirectory( "." ) );
  +        project.setDefaultTargetName( "main" );
  +        return project;
  +    }
  +
  +    /**
  +     * Tests bad project file name.
  +     */
  +    public void testProjectFileName() throws Exception
  +    {
  +        // Test with a file that does not exist
  +        File projFile = getTestResource( "unknown.ant", false );
  +
  +        try
  +        {
  +            m_builder.build( projFile.getAbsolutePath() );
  +            fail();
  +        }
  +        catch( ProjectException e )
  +        {
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ),
  +                REZ.getString( "ant.no-project-file.error" )
  +            };
  +            assertSameMessage( messages, e );
  +        }
  +
  +        // Test with a directory
  +        projFile = getTestDirectory( "some-dir" );
  +
  +        try
  +        {
  +            m_builder.build( projFile.getAbsolutePath() );
  +            fail();
  +        }
  +        catch( ProjectException e )
  +        {
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ),
  +                REZ.getString( "ant.no-project-file.error" )
  +            };
  +            assertSameMessage( messages, e );
  +        }
  +    }
  +
  +    /**
  +     * Tests error reporting when the project file contains badly formed XML.
  +     */
  +    public void testBadlyFormedFile() throws Exception
  +    {
  +        final File projFile = getTestResource( "bad-xml.ant" );
  +        try
  +        {
  +            m_builder.build( projFile.getAbsolutePath() );
  +            fail();
  +        }
  +        catch( ProjectException e )
  +        {
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ),
  +                REZ.getString( "ant.project-parse.error" )
  +            };
  +            assertSameMessage( messages, e );
  +        }
  +    }
  +
  +    /**
  +     * Tests building a project with default values for project name, base dir
  +     * and default target.
  +     */
  +    public void testDefaults() throws Exception
  +    {
  +        // Build project
  +        final File projFile = getTestResource( "defaults.ant" );
  +        Project project = m_builder.build( projFile.getAbsolutePath() );
  +
  +        // Compare against expected project
  +        DefaultProject expected = createProject( projFile );
  +        assertSameProject( expected, project );
  +    }
  +
  +    /**
  +     * Tests setting the project name.
  +     */
  +    public void testProjectName() throws Exception
  +    {
  +        // Build project
  +        final File projFile = getTestResource( "set-project-name.ant" );
  +        Project project = m_builder.build( projFile.getAbsolutePath() );
  +
  +        // Compare against expected project
  +        DefaultProject expected = createProject( projFile );
  +        expected.setProjectName( "some-project" );
  +        assertSameProject( expected, project );
  +    }
  +
  +    /**
  +     * Tests setting the base directory.
  +     */
  +    public void testBaseDirectory() throws Exception
  +    {
  +        // Build project
  +        final File projFile = getTestResource( "set-base-dir.ant" );
  +        Project project = m_builder.build( projFile.getAbsolutePath() );
  +
  +        // Compare against expected project
  +        DefaultProject expected = createProject( projFile );
  +        final File baseDir = getTestDirectory( "other-base-dir" );
  +        expected.setBaseDirectory( baseDir );
  +        assertSameProject( expected, project );
  +    }
  +
  +    /**
  +     * Tests setting the default target name.
  +     */
  +    public void testDefaultTarget() throws Exception
  +    {
  +        // Build project
  +        final File projFile = getTestResource( "set-default-target.ant" );
  +        Project project = m_builder.build( projFile.getAbsolutePath() );
  +
  +        // Compare against expected project
  +        DefaultProject expected = createProject( projFile );
  +        expected.setDefaultTargetName( "some-target" );
  +        assertSameProject( expected, project );
  +    }
  +
  +    /**
  +     * Tests missing, invalid and incompatible project version.
  +     */
  +    public void testProjectVersion() throws Exception
  +    {
  +        // No version
  +        File projFile = getTestResource( "no-version.ant" );
  +        try
  +        {
  +            m_builder.build( projFile.getAbsolutePath() );
  +            fail();
  +        }
  +        catch( ProjectException e )
  +        {
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ),
  +                REZ.getString( "ant.version-missing.error" )
  +            };
  +            assertSameMessage( messages, e );
  +        }
  +
  +        // Badly formed version
  +        projFile = getTestResource( "bad-version.ant" );
  +        try
  +        {
  +            m_builder.build( projFile.getAbsolutePath() );
  +            fail();
  +        }
  +        catch( ProjectException e )
  +        {
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ),
  +                REZ.getString( "ant.malformed.version", "ant2" )
  +            };
  +            assertSameMessage( messages, e );
  +        }
  +
  +        // Incompatible version
  +        projFile = getTestResource( "mismatched-version.ant" );
  +        try
  +        {
  +            m_builder.build( projFile.getAbsolutePath() );
  +            fail();
  +        }
  +        catch( ProjectException e )
  +        {
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ),
  +                REZ.getString( "ant.bad-version.error", "2.0.0", "1.0.2" )
  +            };
  +            assertSameMessage( messages, e );
  +        }
  +    }
  +
  +    /**
  +     * Asserts that 2 projects are identical.
  +     */
  +    protected void assertSameProject( final Project expected,
  +                                      final Project project )
  +    {
  +        assertEquals( expected.getProjectName(), project.getProjectName() );
  +        assertEquals( expected.getBaseDirectory(), project.getBaseDirectory() );
  +        assertEquals( expected.getDefaultTargetName(), project.getDefaultTargetName() );
  +
  +        // TODO - make sure each of the projects are the same
  +        assertTrue( Arrays.equals( expected.getProjectNames(), project.getProjectNames() ) );
  +
  +        // TODO - make sure the implicit targets are the same
  +
  +        // TODO - make sure each of the targets are the same
  +        assertTrue( Arrays.equals( expected.getTargetNames(), project.getTargetNames() ) );
  +
  +        // TODO - implement TypeLib.equals(), or use a comparator
  +        assertTrue( Arrays.equals( expected.getTypeLibs(), project.getTypeLibs() ) );
  +    }
  +
  +    /**
  +     * Tests validation of project and target names.
        */
       public void testNameValidation() throws Exception
       {
  @@ -52,7 +272,12 @@
           }
           catch( Exception e )
           {
  -            assertSameMessage( REZ.getString( "ant.project-bad-name.error" ), e );
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", badProjectFile.getAbsolutePath() ),
  +                REZ.getString( "ant.project-bad-name.error" )
  +            };
  +            assertSameMessage( messages, e );
           }
   
           // Check bad target name
  @@ -64,7 +289,13 @@
           }
           catch( Exception e )
           {
  -            // TODO - check error message
  +            final String[] messages =
  +            {
  +                REZ.getString( "ant.project-build.error", badTargetFile.getAbsolutePath() ),
  +                // TODO - check error message
  +                null
  +            };
  +            assertSameMessage( messages, e );
           }
       }
   }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java
  
  Index: AbstractPropertyResolverTest.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.property;
  
  import java.io.File;
  import java.util.Date;
  import org.apache.avalon.excalibur.i18n.ResourceManager;
  import org.apache.avalon.excalibur.i18n.Resources;
  import org.apache.avalon.framework.context.Context;
  import org.apache.myrmidon.AbstractMyrmidonTest;
  import org.apache.myrmidon.api.TaskException;
  import org.apache.myrmidon.components.workspace.DefaultTaskContext;
  import org.apache.myrmidon.interfaces.property.PropertyResolver;
  
  /**
   * General-purpose property resolver test cases.
   *
   * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
   * @version $Revision: 1.1 $ $Date: 2002/03/13 07:35:19 $
   */
  public abstract class AbstractPropertyResolverTest
      extends AbstractMyrmidonTest
  {
      protected final static Resources REZ
          = ResourceManager.getPackageResources( AbstractPropertyResolverTest.class );
  
      protected PropertyResolver m_resolver;
      protected DefaultTaskContext m_context;
  
      public AbstractPropertyResolverTest( String name )
      {
          super( name );
      }
  
      protected void setUp() throws Exception
      {
          m_resolver = createResolver();
  
          m_context = new DefaultTaskContext( null, null, getLogger() );
          m_context.setProperty( "intProp", new Integer( 333 ) );
          m_context.setProperty( "stringProp", "String property" );
      }
  
      /**
       * Creates the resolver to test.
       */
      protected abstract PropertyResolver createResolver();
  
      /**
       * Test property resolution with various different typed properties.
       */
      public void testPropertyTypes() throws Exception
      {
          testPropertyValue( new String( "String value" ) );
          testPropertyValue( new Date() );
          testPropertyValue( new Integer( Integer.MIN_VALUE ) );
          testPropertyValue( new Double( 24234.98453 ) );
          testPropertyValue( this.getClass() );
          testPropertyValue( File.createTempFile( "PropertyResolverTest", null ) );
      }
  
      /**
       * Simple tests with property on it's own, and accompanied by text.
       */
      private void testPropertyValue( Object propObject )
          throws Exception
      {
          m_context.setProperty( "typedProp", propObject );
          final String propString = propObject.toString();
  
          doTestResolution( "${typedProp}", propObject, m_context );
          doTestResolution( "${typedProp} with following text",
                            propString + " with following text", m_context );
          doTestResolution( "Preceding text with ${typedProp}",
                            "Preceding text with " + propString, m_context );
      }
  
      /**
       * Tests multiple property declarations in a single value.
       */
      public void testMultipleProperties() throws Exception
      {
          m_context.setProperty( "prop1", "value1" );
          m_context.setProperty( "prop2", "value2" );
          m_context.setProperty( "int1", new Integer( 123 ) );
  
          doTestResolution( "${prop1}${prop2}", "value1value2", m_context );
          doTestResolution( "${prop1}${prop1}${prop1}", "value1value1value1", m_context );
          doTestResolution( "before ${prop2} between ${prop1} after",
                            "before value2 between value1 after", m_context );
          doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context );
      }
  
      /**
       * Tests illegal property syntax.
       */
      public void testInvalidTypeDeclarations() throws Exception
      {
  
          doTestFailure( "${unclosed",
                         REZ.getString( "prop.mismatched-braces.error" ),
                         m_context );
          doTestFailure( "${",
                         REZ.getString( "prop.mismatched-braces.error" ),
                         m_context );
  
          /* TODO - need to handle these cases. */
          //        testFailure( "${bad${}", "", m_context );
          //        testFailure( "${ }", "", m_context );
      }
  
      /**
       * Resolves the property using the supplied context, and checks the result.
       */
      protected void doTestResolution( final String value,
                                       final Object expected,
                                       final Context context )
          throws Exception
      {
          final Object resolved = m_resolver.resolveProperties( value, context );
  
          assertEquals( expected, resolved );
      }
  
      /**
       * Attempts to resolve the value using the supplied context, expecting to
       * fail with the supplied error message.
       */
      protected void doTestFailure( final String value,
                                    final String expectedErrorMessage,
                                    final Context context )
      {
          try
          {
              m_resolver.resolveProperties( value, context );
              fail( "Unexpected sucess - test should have failed." );
          }
          catch( TaskException e )
          {
              assertSameMessage( expectedErrorMessage, e );
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java
  
  Index: ClassicPropertyResolverTest.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.property;
  
  import org.apache.myrmidon.interfaces.property.PropertyResolver;
  
  /**
   * A test for {@link ClassicPropertyResolver}.
   *
   * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a>
   * @version $Revision: 1.1 $ $Date: 2002/03/13 07:35:19 $
   */
  public class ClassicPropertyResolverTest
      extends AbstractPropertyResolverTest
  {
      public ClassicPropertyResolverTest( String name )
      {
          super( name );
      }
  
      protected PropertyResolver createResolver()
      {
          return new ClassicPropertyResolver();
      }
  
      /**
       * Tests handing undefined property.
       */
      public void testUndefinedProp() throws Exception
      {
          final String undefinedProp = "undefinedProperty";
          final String propRef = "${" + undefinedProp + "}";
          doTestResolution( propRef, propRef, m_context );
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java
  
  Index: DefaultPropertyResolverTest.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.property;
  
  import org.apache.myrmidon.interfaces.property.PropertyResolver;
  
  /**
   * Functional tests for {@link DefaultPropertyResolver}.
   *
   * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a>
   * @version $Revision: 1.1 $ $Date: 2002/03/13 07:35:19 $
   */
  public class DefaultPropertyResolverTest
      extends AbstractPropertyResolverTest
  {
      public DefaultPropertyResolverTest( String name )
      {
          super( name );
      }
  
      protected PropertyResolver createResolver()
      {
          return new DefaultPropertyResolver();
      }
  
      /**
       * Tests handing undefined property.
       */
      public void testUndefinedProp() throws Exception
      {
          final String undefinedProp = "undefinedProperty";
          doTestFailure( "${" + undefinedProp + "}",
                         REZ.getString( "prop.missing-value.error", undefinedProp ),
                         m_context );
  
          //TODO - "" should be disallowed as a property name
          doTestFailure( "${}",
                         REZ.getString( "prop.missing-value.error", "" ),
                         m_context );
      }
  }
  
  
  
  1.3       +2 -4      jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java
  
  Index: InstantiatingServiceManagerTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- InstantiatingServiceManagerTest.java	1 Mar 2002 08:54:34 -0000	1.2
  +++ InstantiatingServiceManagerTest.java	13 Mar 2002 07:35:19 -0000	1.3
  @@ -22,7 +22,7 @@
    * Test cases for the default service manager.
    *
    * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
  - * @version $Revision: 1.2 $ $Date: 2002/03/01 08:54:34 $
  + * @version $Revision: 1.3 $ $Date: 2002/03/13 07:35:19 $
    */
   public class InstantiatingServiceManagerTest
       extends AbstractComponentTest
  @@ -44,11 +44,9 @@
       protected void setUp()
           throws Exception
       {
  -        super.setUp();
  -
           // Set-up the service manager
           m_serviceManager = new InstantiatingServiceManager();
  -        m_serviceManager.enableLogging( createLogger() );
  +        m_serviceManager.enableLogging( getLogger() );
           m_serviceManager.service( getServiceManager() );
           m_serviceManager.parameterize( m_parameters );
       }
  
  
  

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message