Browse Source

Updated to the version on harddisk + added the start of documentation.

Major changes include
* making convertion API context-sensitive
* the simplification of all the interfaces. The simplification is achived by applying IOC. Now AntEngine is responsible for creating and instantiating shared components via a ComponentManager.
* Moved most of startup code to AntEngine so that alternate front ends can be added in simply.


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268409 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Donald 24 years ago
parent
commit
8c97911720
66 changed files with 1899 additions and 1122 deletions
  1. +6
    -3
      proposal/myrmidon/build.bat
  2. +3
    -1
      proposal/myrmidon/build.xml
  3. BIN
      proposal/myrmidon/lib/ant.jar
  4. BIN
      proposal/myrmidon/lib/avalonapi.jar
  5. +48
    -0
      proposal/myrmidon/src/java/org/apache/ant/AntEngine.java
  6. +410
    -0
      proposal/myrmidon/src/java/org/apache/ant/DefaultAntEngine.java
  7. +18
    -0
      proposal/myrmidon/src/java/org/apache/ant/FrontEnd.java
  8. +97
    -521
      proposal/myrmidon/src/java/org/apache/ant/Main.java
  9. +0
    -6
      proposal/myrmidon/src/java/org/apache/ant/configuration/ConfigurationBuilder.java
  10. +14
    -15
      proposal/myrmidon/src/java/org/apache/ant/configuration/DefaultConfigurer.java
  11. +7
    -3
      proposal/myrmidon/src/java/org/apache/ant/convert/AbstractConverter.java
  12. +4
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/Converter.java
  13. +17
    -3
      proposal/myrmidon/src/java/org/apache/ant/convert/ConverterEngine.java
  14. +49
    -35
      proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterEngine.java
  15. +14
    -7
      proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterRegistry.java
  16. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToByteConverter.java
  17. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToClassConverter.java
  18. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToDoubleConverter.java
  19. +35
    -0
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFileConverter.java
  20. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFloatConverter.java
  21. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToIntegerConverter.java
  22. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToLongConverter.java
  23. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToShortConverter.java
  24. +2
    -1
      proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToURLConverter.java
  25. +21
    -1
      proposal/myrmidon/src/java/org/apache/ant/datatypes/DataTypeEngine.java
  26. +39
    -42
      proposal/myrmidon/src/java/org/apache/ant/datatypes/DefaultDataTypeEngine.java
  27. +35
    -0
      proposal/myrmidon/src/java/org/apache/ant/datatypes/Pattern.java
  28. +56
    -0
      proposal/myrmidon/src/java/org/apache/ant/launcher/AntClassLoader.java
  29. +48
    -32
      proposal/myrmidon/src/java/org/apache/ant/launcher/AntLoader.java
  30. +54
    -4
      proposal/myrmidon/src/java/org/apache/ant/project/DefaultProject.java
  31. +117
    -78
      proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectBuilder.java
  32. +107
    -64
      proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectEngine.java
  33. +51
    -5
      proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectListener.java
  34. +40
    -3
      proposal/myrmidon/src/java/org/apache/ant/project/DefaultTarget.java
  35. +10
    -1
      proposal/myrmidon/src/java/org/apache/ant/project/LogTargetToListenerAdapter.java
  36. +37
    -0
      proposal/myrmidon/src/java/org/apache/ant/project/Project.java
  37. +16
    -4
      proposal/myrmidon/src/java/org/apache/ant/project/ProjectBuilder.java
  38. +34
    -5
      proposal/myrmidon/src/java/org/apache/ant/project/ProjectEngine.java
  39. +45
    -0
      proposal/myrmidon/src/java/org/apache/ant/project/ProjectListener.java
  40. +50
    -0
      proposal/myrmidon/src/java/org/apache/ant/project/ProjectListenerSupport.java
  41. +23
    -1
      proposal/myrmidon/src/java/org/apache/ant/project/Target.java
  42. +2
    -22
      proposal/myrmidon/src/java/org/apache/ant/tasklet/AbstractTasklet.java
  43. +11
    -3
      proposal/myrmidon/src/java/org/apache/ant/tasklet/DefaultTaskletContext.java
  44. +1
    -1
      proposal/myrmidon/src/java/org/apache/ant/tasklet/Tasklet.java
  45. +2
    -2
      proposal/myrmidon/src/java/org/apache/ant/tasklet/TaskletContext.java
  46. +58
    -132
      proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletEngine.java
  47. +21
    -21
      proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTskDeployer.java
  48. +0
    -29
      proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletConverterEngine.java
  49. +0
    -29
      proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletDataTypeEngine.java
  50. +2
    -4
      proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEngine.java
  51. +3
    -4
      proposal/myrmidon/src/java/org/apache/ant/tasks/core/AbstractResourceRegisterer.java
  52. +2
    -3
      proposal/myrmidon/src/java/org/apache/ant/tasks/core/AntCall.java
  53. +13
    -10
      proposal/myrmidon/src/java/org/apache/ant/tasks/core/Property.java
  54. +4
    -5
      proposal/myrmidon/src/java/org/apache/ant/tasks/core/RegisterConverter.java
  55. +3
    -4
      proposal/myrmidon/src/java/org/apache/ant/tasks/core/RegisterTasklib.java
  56. +1
    -1
      proposal/myrmidon/src/java/org/apache/ant/util/Condition.java
  57. +2
    -2
      proposal/myrmidon/src/script/ant
  58. +25
    -4
      proposal/myrmidon/src/script/ant.bat
  59. +224
    -0
      proposal/myrmidon/src/xdocs/design.html
  60. +1
    -1
      proposal/myrmidon/tools/bin/ant
  61. +1
    -1
      proposal/myrmidon/tools/bin/ant.bat
  62. +0
    -0
      proposal/myrmidon/tools/bin/antRun
  63. +1
    -1
      proposal/myrmidon/tools/bin/antRun.bat
  64. +0
    -0
      proposal/myrmidon/tools/bin/fixPath.awk
  65. +1
    -0
      proposal/myrmidon/tools/bin/lcp.bat
  66. BIN
      proposal/myrmidon/tools/lib/ant.jar

+ 6
- 3
proposal/myrmidon/build.bat View File

@@ -4,11 +4,14 @@ echo.
echo Ant Build System
echo ----------------

set ANT_HOME=.
set ANT_HOME=tools

set CLASSPATH=
set LOCALCLASSPATH=
for %%i in (lib\*.jar) do call tools\bin\lcp.bat %%i
set CLASSPATH=%LOCALCLASSPATH%
set LOCALCLASSPATH=

%ANT_HOME%\bin\ant.bat -emacs %1 %2 %3 %4 %5 %6 %7 %8
%ANT_HOME%\bin\ant.bat -logger org.apache.tools.ant.NoBannerLogger -emacs %1 %2 %3 %4 %5 %6 %7 %8
goto cleanup

:cleanup


+ 3
- 1
proposal/myrmidon/build.xml View File

@@ -154,7 +154,9 @@ Legal:
destdir="${build.classes}"
debug="${debug}"
optimize="${optimize}"
deprecation="${deprecation}" />
deprecation="${deprecation}">
<exclude name="org/apache/ant/gui/**"/>
</javac>

<!--
<copy todir="${build.classes}">


BIN
proposal/myrmidon/lib/ant.jar View File


BIN
proposal/myrmidon/lib/avalonapi.jar View File


+ 48
- 0
proposal/myrmidon/src/java/org/apache/ant/AntEngine.java View File

@@ -0,0 +1,48 @@
/*
* 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 file.
*/
package org.apache.ant;

import java.util.Properties;
import org.apache.ant.project.ProjectBuilder;
import org.apache.ant.project.ProjectEngine;
import org.apache.avalon.Component;
import org.apache.avalon.Disposable;
import org.apache.avalon.Initializable;

/**
* Interface to the Ant runtime.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface AntEngine
extends Component, Initializable, Disposable
{
/**
* Setup basic properties of engine.
* Called before init() and can be used to specify alternate components in system.
*
* @param properties the properties
*/
void setProperties( Properties properties );

/**
* Retrieve builder for runtime.
* Valid after init() call
*
* @return the ProjectBuilder
*/
ProjectBuilder getProjectBuilder();
/**
* Retrieve project engine for runtime.
* Valid after init() call
*
* @return the ProjectBuilder
*/
ProjectEngine getProjectEngine();
}

+ 410
- 0
proposal/myrmidon/src/java/org/apache/ant/DefaultAntEngine.java View File

@@ -0,0 +1,410 @@
/*
* 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 file.
*/
package org.apache.ant;

import java.io.File;
import java.util.Properties;
import org.apache.ant.configuration.Configurer;
import org.apache.ant.convert.ConverterEngine;
import org.apache.ant.datatypes.DataTypeEngine;
import org.apache.ant.project.ProjectBuilder;
import org.apache.ant.project.ProjectEngine;
import org.apache.ant.tasklet.JavaVersion;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.ant.tasklet.engine.TskDeployer;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.Component;
import org.apache.avalon.Composer;
import org.apache.avalon.DefaultComponentManager;
import org.apache.avalon.Initializable;
import org.apache.avalon.camelot.CamelotUtil;
import org.apache.avalon.camelot.DefaultFactory;
import org.apache.avalon.camelot.Deployer;
import org.apache.avalon.camelot.Factory;
import org.apache.avalon.util.ObjectUtil;
import org.apache.avalon.util.io.FileUtil;

/**
* Default implementation of Ant runtime.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultAntEngine
extends AbstractLoggable
implements AntEngine, Initializable
{
protected ConverterEngine m_converterEngine;
protected DataTypeEngine m_dataTypeEngine;
protected TaskletEngine m_taskletEngine;
protected ProjectEngine m_projectEngine;

protected ProjectBuilder m_builder;
protected TskDeployer m_deployer;
protected Configurer m_configurer;

protected Factory m_factory;

protected DefaultComponentManager m_componentManager;
protected Properties m_properties;
protected Properties m_defaults;

protected File m_homeDir;
protected File m_binDir;
protected File m_libDir;
protected File m_taskLibDir;
/**
* Setup basic properties of engine.
* Called before init() and can be used to specify alternate components in system.
*
* @param properties the properties
*/
public void setProperties( final Properties properties )
{
m_properties = properties;
}

/**
* Retrieve builder for runtime.
* Valid after init() call
*
* @return the ProjectBuilder
*/
public ProjectBuilder getProjectBuilder()
{
return m_builder;
}

/**
* Retrieve project engine for runtime.
* Valid after init() call
*
* @return the ProjectBuilder
*/
public ProjectEngine getProjectEngine()
{
return m_projectEngine;
}

/**
* Initialize the system.
*
* @exception Exception if an error occurs
*/
public void init()
throws Exception
{
//setup default properties
m_defaults = createDefaultProperties();

//create all the components
m_factory = new DefaultFactory();
createComponents();

//setup the component manager
m_componentManager = createComponentManager();

setupComponents();

setupFiles();

CamelotUtil.deployFromDirectory( m_deployer, m_taskLibDir, ".tsk" );
}

/**
* Dispose engine.
*
* @exception Exception if an error occurs
*/
public void dispose()
throws Exception
{
m_converterEngine = null;
m_dataTypeEngine = null;
m_taskletEngine = null;
m_projectEngine = null;
m_builder = null;
m_deployer = null;
m_configurer = null;
m_factory = null;
m_componentManager = null;
m_properties = null;
m_defaults = null;
m_homeDir = null;
m_binDir = null;
m_libDir = null;
m_taskLibDir = null;
}
/**
* Create default properties which includes default names of all components.
* Overide this in sub-classes to change values.
*
* @return the Properties
*/
protected Properties createDefaultProperties()
{
final Properties defaults = new Properties();

//create all the default properties for files/directories
defaults.setProperty( "ant.path.bin", "bin" );
defaults.setProperty( "ant.path.lib", "lib" );
defaults.setProperty( "ant.path.task-lib", "lib" );

//create all the default properties for components
defaults.setProperty( "ant.comp.converter",
"org.apache.ant.convert.DefaultConverterEngine" );
defaults.setProperty( "ant.comp.datatype",
"org.apache.ant.datatypes.DefaultDataTypeEngine" );
defaults.setProperty( "ant.comp.tasklet",
"org.apache.ant.tasklet.engine.DefaultTaskletEngine" );
defaults.setProperty( "ant.comp.project",
"org.apache.ant.project.DefaultProjectEngine" );
defaults.setProperty( "ant.comp.builder",
"org.apache.ant.project.DefaultProjectBuilder" );
defaults.setProperty( "ant.comp.deployer",
"org.apache.ant.tasklet.engine.DefaultTskDeployer" );
defaults.setProperty( "ant.comp.configurer",
"org.apache.ant.configuration.DefaultConfigurer" );

return defaults;
}

/**
* Create a ComponentManager containing all components in engine.
*
* @return the ComponentManager
*/
protected DefaultComponentManager createComponentManager()
{
final DefaultComponentManager componentManager = new DefaultComponentManager();

componentManager.put( "org.apache.ant.tasklet.engine.TaskletEngine", m_taskletEngine );
componentManager.put( "org.apache.ant.project.ProjectEngine", m_projectEngine );
componentManager.put( "org.apache.ant.convert.ConverterEngine", m_converterEngine );
componentManager.put( "org.apache.ant.convert.Converter", m_converterEngine );
componentManager.put( "org.apache.ant.datatypes.DataTypeEngine", m_dataTypeEngine );
componentManager.put( "org.apache.ant.project.ProjectBuilder", m_builder );
componentManager.put( "org.apache.ant.tasklet.engine.TskDeployer", m_deployer );
componentManager.put( "org.apache.avalon.camelot.Factory", m_factory );
componentManager.put( "org.apache.ant.configuration.Configurer", m_configurer );

return componentManager;
}

/**
* Create all required components.
*
* @exception Exception if an error occurs
*/
protected void createComponents()
throws Exception
{
String component = null;

component = getProperty( "ant.comp.converter" );
m_converterEngine = (ConverterEngine)createComponent( component, ConverterEngine.class );

component = getProperty( "ant.comp.datatype" );
m_dataTypeEngine = (DataTypeEngine)createComponent( component, DataTypeEngine.class );
component = getProperty( "ant.comp.tasklet" );
m_taskletEngine = (TaskletEngine)createComponent( component, TaskletEngine.class );
component = getProperty( "ant.comp.project" );
m_projectEngine = (ProjectEngine)createComponent( component, ProjectEngine.class );

component = getProperty( "ant.comp.builder" );
m_builder =(ProjectBuilder)createComponent( component, ProjectBuilder.class );

component = getProperty( "ant.comp.deployer" );
m_deployer = (TskDeployer)createComponent( component, TskDeployer.class );

component = getProperty( "ant.comp.configurer" );
m_configurer = (Configurer)createComponent( component, Configurer.class );
}

/**
* Setup all the components. (ir run all required lifecycle methods).
*
* @exception Exception if an error occurs
*/
protected void setupComponents()
throws Exception
{
setupComponent( m_factory );
setupComponent( m_converterEngine );
setupComponent( m_dataTypeEngine );
setupComponent( m_taskletEngine );
setupComponent( m_projectEngine );
setupComponent( m_builder );
setupComponent( m_deployer );
setupComponent( m_configurer );
}

/**
* Setup an individual component.
*
* @param component the component
* @exception Exception if an error occurs
*/
protected void setupComponent( final Component component )
throws Exception
{
setupLogger( component );

if( component instanceof Composer )
{
((Composer)component).compose( m_componentManager );
}

if( component instanceof Initializable )
{
((Initializable)component).init();
}
}

/**
* Setup all the files attributes.
*/
protected void setupFiles()
{
String filepath = null;

filepath = getProperty( "ant.home" );
m_homeDir = (new File( filepath )).getAbsoluteFile();
checkDirectory( m_homeDir, "ant-home" );

filepath = getProperty( "ant.path.bin" );
m_binDir = resolveDirectory( filepath, "bin-dir" );
filepath = getProperty( "ant.path.lib" );
m_libDir = resolveDirectory( filepath, "lib-dir" );

filepath = getProperty( "ant.path.task-lib" );
m_taskLibDir = resolveDirectory( filepath, "task-lib-dir" );
}

/**
* 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
*/
protected String getProperty( final String name )
{
String value = m_properties.getProperty( name );

if( null == value )
{
value = m_defaults.getProperty( name );
}

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 AntException if an error occurs
*/
protected File resolveDirectory( final String dir, final String name )
throws AntException
{
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)
*/
protected void checkDirectory( final File file, final String name )
throws AntException
{
if( !file.exists() )
{
throw new AntException( name + " (" + file + ") does not exist" );
}
else if( !file.isDirectory() )
{
throw new AntException( name + " (" + file + ") is not a directory" );
}
}

/**
* Helper method to retrieve current JVM version.
* Basically stolen from original Ant sources.
*
* @return the current JVM version
*/
protected JavaVersion getJavaVersion()
{
JavaVersion version = JavaVersion.JAVA1_0;
try
{
Class.forName( "java.lang.Void" );
version = JavaVersion.JAVA1_1;
Class.forName( "java.lang.ThreadLocal" );
version = JavaVersion.JAVA1_2;
Class.forName( "java.lang.StrictMath" );
version = JavaVersion.JAVA1_3;
}
catch( final ClassNotFoundException cnfe ) {}
return version;
}

/**
* Create a component that implements an interface.
*
* @param component the name of the component
* @param clazz the name of interface/type
* @return the created object
* @exception AntException if an error occurs
*/
protected Object createComponent( final String component, final Class clazz )
throws AntException
{
try
{
final Object object = ObjectUtil.createObject( component );

if( !clazz.isInstance( object ) )
{
throw new AntException( "Object " + component + " is not an instance of " +
clazz );
}

return object;
}
catch( final IllegalAccessException iae )
{
throw new AntException( "Non-public constructor for " + clazz + " " + component,
iae );
}
catch( final InstantiationException ie )
{
throw new AntException( "Error instantiating class for " + clazz + " " + component,
ie );
}
catch( final ClassNotFoundException cnfe )
{
throw new AntException( "Could not find the class for " + clazz +
" (" + component + ")", cnfe );
}
}
}

+ 18
- 0
proposal/myrmidon/src/java/org/apache/ant/FrontEnd.java View File

@@ -0,0 +1,18 @@
/*
* 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 file.
*/
package org.apache.ant;

/**
* Interface for front end.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
* @author James Duncan Davidson (duncan@apache.org)
*/
public interface FrontEnd
{
}

+ 97
- 521
proposal/myrmidon/src/java/org/apache/ant/Main.java View File

@@ -15,25 +15,26 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.ant.launcher.AntClassLoader;
import org.apache.ant.launcher.AntLoader;
import org.apache.ant.project.DefaultProjectEngine;
import org.apache.ant.project.LogTargetToListenerAdapter;
import org.apache.ant.project.Project;
import org.apache.ant.project.ProjectBuilder;
import org.apache.ant.project.ProjectEngine;
import org.apache.ant.project.ProjectListener;
import org.apache.ant.project.LogTargetToListenerAdapter;
import org.apache.ant.tasklet.JavaVersion;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.ant.tasklet.engine.TskDeployer;
import org.apache.avalon.Disposable;
import org.apache.avalon.Initializable;
import org.apache.avalon.camelot.CamelotUtil;
import org.apache.avalon.camelot.Deployer;
import org.apache.avalon.camelot.DeploymentException;
import org.apache.avalon.util.ObjectUtil;
import org.apache.avalon.util.StringUtil;
@@ -41,7 +42,6 @@ import org.apache.avalon.util.cli.AbstractMain;
import org.apache.avalon.util.cli.CLOption;
import org.apache.avalon.util.cli.CLOptionDescriptor;
import org.apache.avalon.util.io.ExtensionFileFilter;
import org.apache.avalon.util.io.FileUtil;
import org.apache.log.Category;
import org.apache.log.LogKit;
import org.apache.log.Logger;
@@ -67,21 +67,11 @@ public class Main
protected final static String DEFAULT_LOGLEVEL = "WARN";

//Some defaults for file locations/names
protected final static String DEFAULT_LIB_DIRECTORY = "lib";
protected final static String DEFAULT_TASKLIB_DIRECTORY = DEFAULT_LIB_DIRECTORY;
protected final static String DEFAULT_FILENAME = "build.xmk";

//some constants that define the classes to be loaded to perform
//particular services
protected final static String DEFAULT_ENGINE =
"org.apache.ant.project.DefaultProjectEngine";

protected final static String DEFAULT_LISTENER =
"org.apache.ant.project.DefaultProjectListener";

protected final static String DEFAULT_BUILDER =
"org.apache.ant.project.DefaultProjectBuilder";

//defines for the Command Line options
private static final int HELP_OPT = 'h';
private static final int QUIET_OPT = 'q';
@@ -91,8 +81,6 @@ public class Main
private static final int DEFINE_OPT = 'D';
private static final int VERSION_OPT = 1;
private static final int LISTENER_OPT = 2;
private static final int BIN_DIR_OPT = 3;
private static final int LIB_DIR_OPT = 4;
private static final int TASKLIB_DIR_OPT = 5;
private static final int INCREMENTAL_OPT = 6;
private static final int HOME_DIR_OPT = 7;
@@ -102,8 +90,7 @@ public class Main
{
HELP_OPT, QUIET_OPT, VERBOSE_OPT, FILE_OPT,
LOG_LEVEL_OPT, VERSION_OPT, LISTENER_OPT,
DEFINE_OPT
//BIN_DIR_OPT, LIB_DIR_OPT, TASKLIB_DIR_OPT, HOME_DIR_OPT
DEFINE_OPT //TASKLIB_DIR_OPT, HOME_DIR_OPT
};
//incompatable options for other logging options
@@ -112,15 +99,8 @@ public class Main
QUIET_OPT, VERBOSE_OPT, LOG_LEVEL_OPT
};


protected Logger m_logger;
protected ProjectListener m_listener;
protected File m_binDir;
protected File m_homeDir;
protected File m_libDir;
protected File m_taskLibDir;
protected File m_buildFile;
protected File m_userDir;

/**
* Main entry point called to run standard Ant.
@@ -134,13 +114,13 @@ public class Main
try { main.execute( args ); }
catch( final AntException ae )
{
main.m_logger.error( "Error: " + ae.getMessage() );
main.m_logger.debug( "Exception..." + StringUtil.printStackTrace( ae ) );
main.getLogger().error( "Error: " + ae.getMessage() );
main.getLogger().debug( "Exception..." + StringUtil.printStackTrace( ae ) );
}
catch( final Throwable throwable )
{
main.m_logger.error( "Error: " + throwable );
main.m_logger.debug( "Exception..." + StringUtil.printStackTrace( throwable ) );
main.getLogger().error( "Error: " + throwable );
main.getLogger().debug( "Exception..." + StringUtil.printStackTrace( throwable ) );
}
}

@@ -151,7 +131,7 @@ public class Main
protected CLOptionDescriptor[] createCLOptions()
{
//TODO: localise
final CLOptionDescriptor[] options = new CLOptionDescriptor[ 13 ];
final CLOptionDescriptor[] options = new CLOptionDescriptor[ 11 ];

options[0] =
new CLOptionDescriptor( "help",
@@ -202,33 +182,21 @@ public class Main
INFO_OPT_INCOMPAT );

options[7] =
new CLOptionDescriptor( "bin-dir",
CLOptionDescriptor.ARGUMENT_REQUIRED,
BIN_DIR_OPT,
"the listener for log events." );

options[8] =
new CLOptionDescriptor( "lib-dir",
CLOptionDescriptor.ARGUMENT_REQUIRED,
LIB_DIR_OPT,
"the lib directory to scan for jars/zip files." );

options[9] =
new CLOptionDescriptor( "task-lib-dir",
CLOptionDescriptor.ARGUMENT_REQUIRED,
TASKLIB_DIR_OPT,
"the task lib directory to scan for .tsk files." );
options[10] =
options[8] =
new CLOptionDescriptor( "incremental",
CLOptionDescriptor.ARGUMENT_DISALLOWED,
INCREMENTAL_OPT,
"Run in incremental mode" );
options[11] =
options[9] =
new CLOptionDescriptor( "ant-home",
CLOptionDescriptor.ARGUMENT_REQUIRED,
HOME_DIR_OPT,
"Specify ant home directory" );
options[12] =
options[10] =
new CLOptionDescriptor( "define",
CLOptionDescriptor.ARGUMENTS_REQUIRED_2,
DEFINE_OPT,
@@ -249,11 +217,8 @@ public class Main
final ArrayList targets = new ArrayList();
String filename = null;
String listenerName = null;
String builderName = null;
String logLevel = null;
String binDir = null;
String homeDir = null;
String libDir = null;
String taskLibDir = null;
boolean incremental = false;
HashMap defines = new HashMap();
@@ -268,8 +233,6 @@ public class Main
case HELP_OPT: usage(); return;
case VERSION_OPT: System.out.println( VERSION ); return;
case FILE_OPT: filename = option.getArgument(); break;
case BIN_DIR_OPT: binDir = option.getArgument(); break;
case LIB_DIR_OPT: libDir = option.getArgument(); break;
case HOME_DIR_OPT: homeDir = option.getArgument(); break;
case TASKLIB_DIR_OPT: taskLibDir = option.getArgument(); break;
case VERBOSE_OPT: logLevel = "INFO"; break;
@@ -284,64 +247,63 @@ public class Main
}
}

if( null == logLevel ) logLevel = getDefaultLogLevel();
if( null == listenerName ) listenerName = getDefaultListener();
if( null == filename ) filename = getDefaultFilename();
if( null == libDir ) libDir = getDefaultLibDir();
if( null == taskLibDir ) taskLibDir = getDefaultTaskLibDir();
if( null == builderName ) builderName = getBuilderNameFor( filename );

setupLogger( logLevel ); //handle logging...
setupListener( listenerName ); //handle listener..
setupDefaultAntDirs();

//try to auto-discover the location of ant so that
//can populate classpath with libs/tasks and gain access
//to antRun
if( null == binDir && null == homeDir )
{
m_homeDir = getDefaultHomeDir();
m_binDir = m_homeDir.getParentFile();
}
else if( null == binDir ) // && null != homeDir
{
m_homeDir = getHomeDir( homeDir );
m_binDir = new File( m_homeDir, "bin" );
}
else
if( null == logLevel ) logLevel = DEFAULT_LOGLEVEL;
if( null == listenerName ) listenerName = DEFAULT_LISTENER;
if( null == filename ) filename = DEFAULT_FILENAME;

//handle logging...
setLogger( createLogger( logLevel ) );

//if ant home not set then use system property ant.home
//that was set up by launcher.
if( null == homeDir ) homeDir = System.getProperty( "ant.home" );

final Properties properties = new Properties();
properties.setProperty( "ant.home", homeDir );

if( null != taskLibDir ) properties.setProperty( "ant.path.task-lib", taskLibDir );

m_homeDir = (new File( homeDir )).getAbsoluteFile();
if( !m_homeDir.isDirectory() )
{
m_binDir = getBinDir( binDir );
m_homeDir = m_binDir.getParentFile();
throw new AntException( "ant-home (" + m_homeDir + ") is not a directory" );
}

m_libDir = getLibDir( m_homeDir, libDir );
m_taskLibDir = getTaskLibDir( m_homeDir, taskLibDir );
m_buildFile = getFile( filename );

m_logger.warn( "Ant Build File: " + m_buildFile );
m_logger.info( "Ant Home Directory: " + m_homeDir );
m_logger.info( "Ant Bin Directory: " + m_binDir );
m_logger.debug( "Ant Lib Directory: " + m_libDir );
m_logger.debug( "Ant Task Lib Directory: " + m_taskLibDir );
final File libDir = new File( m_homeDir, "lib" );

final File buildFile = (new File( filename )).getCanonicalFile();
if( !buildFile.isFile() )
{
throw new AntException( "File " + buildFile + " is not a file or doesn't exist" );
}
//setup classloader so that it will correctly load
//the Project/ProjectBuilder/ProjectEngine and all dependencies
setupContextClassLoader( m_libDir );
final ClassLoader classLoader = createClassLoader( libDir );
Thread.currentThread().setContextClassLoader( classLoader );

final Project project = getProject( builderName, m_buildFile );
setupProjectContext( project, defines );
//handle listener..
final ProjectListener listener = createListener( listenerName );

final ProjectEngine engine = getProjectEngine();
getLogger().warn( "Ant Build File: " + buildFile );
getLogger().info( "Ant Home Directory: " + m_homeDir );
//getLogger().info( "Ant Bin Directory: " + m_binDir );
//getLogger().debug( "Ant Lib Directory: " + m_libDir );
//getLogger().debug( "Ant Task Lib Directory: " + m_taskLibDir );

//make sure Engine is sweet...
if( engine instanceof Initializable )
{
((Initializable)engine).init();
}
final AntEngine antEngine = new DefaultAntEngine();
setupLogger( antEngine );
antEngine.setProperties( properties );
antEngine.init();

engine.addProjectListener( m_listener );
final ProjectBuilder builder = antEngine.getProjectBuilder();

//create the project
final Project project = builder.build( buildFile );
setupProjectContext( project, defines );

deployDefaultTaskLibs( engine, m_taskLibDir );
final ProjectEngine engine = antEngine.getProjectEngine();
engine.addProjectListener( listener );

BufferedReader reader = null;

@@ -366,44 +328,7 @@ public class Main
}

//shutdown engine gracefully if needed
if( engine instanceof Disposable )
{
((Disposable)engine).dispose();
}
}

/**
* Deploy all tasklibs in tasklib directory into ProjectEngine.
*
* @param engine the ProjectEngine
* @param taskLibDirectory the directory to look for .tsk files
*/
protected void deployDefaultTaskLibs( final ProjectEngine engine,
final File taskLibDirectory )
{
final ExtensionFileFilter filter = new ExtensionFileFilter( ".tsk" );

final File[] files = taskLibDirectory.listFiles( filter );
final TskDeployer deployer = engine.getTaskletEngine().getTskDeployer();

for( int i = 0; i < files.length; i++ )
{
final String name = files[ i ].getName();

try
{
deployer.deploy( name.substring( 0, name.length() - 4 ),
files[ i ].toURL() );
}
catch( final MalformedURLException mue ) {}
catch( final DeploymentException de )
{
throw new AntException( "Failed to deploy task library " + files[ i ],
de );
}
}
antEngine.dispose();
}

/**
@@ -436,22 +361,11 @@ public class Main
}
catch( final AntException ae )
{
m_logger.error( "BUILD FAILED" );
m_logger.error( "Reason:\n" + StringUtil.printStackTrace( ae, 5, true ) );
getLogger().error( "BUILD FAILED" );
getLogger().error( "Reason:\n" + StringUtil.printStackTrace( ae, 5, true ) );
}
}
/**
* Setup Logger for a particular log-level.
* This is in seperate method so it can be overidden if sub-classed.
*
* @param logLevel the log-level
*/
protected void setupLogger( final String logLevel )
{
m_logger = createLogger( logLevel );
}

/**
* Create Logger of appropriate log-level.
*
@@ -479,39 +393,47 @@ public class Main
*
* @param listenerName the name of project listener
*/
protected void setupListener( final String listenerName )
protected ProjectListener createListener( final String listenerName )
throws AntException
{
m_listener = createListener( listenerName );
m_logger.addLogTarget( new LogTargetToListenerAdapter( m_listener ) );
}
ProjectListener result = null;

/**
* Make sure classloader is setup correctly so can do Class.forName safely
*
* @param libDir the directory to grab all the lib files from
*/
protected void setupContextClassLoader( final File libDir )
{
setupClassLoader( libDir );
Thread.currentThread().setContextClassLoader( AntLoader.getLoader() );
try { result = (ProjectListener)ObjectUtil.createObject( listenerName ); }
catch( final Throwable t )
{
throw new AntException( "Error creating the listener " + listenerName +
" due to " + StringUtil.printStackTrace( t, 5, true ),
t );
}

getLogger().addLogTarget( new LogTargetToListenerAdapter( result ) );

return result;
}

/**
* Setup classloader so that the *current* classloader has access to parsers etc.
* This is a bit of a hack as it assumes that AntLoader was used to load this file
* but it is the only way to add to current classloader safely.
* Try to load all extra zipz/jars from lib directory into CURRENT classloader.
*
* @param libDir the directory of lib files to add
*/
protected void setupClassLoader( final File libDir )
protected ClassLoader createClassLoader( final File libDir )
{
final ClassLoader candidate = getClass().getClassLoader();
if( !(candidate instanceof AntClassLoader) )
{
getLogger().warn( "Warning: Unable to add entries from " +
"lib-path to classloader" );
return candidate;
}
final AntClassLoader classLoader = (AntClassLoader)candidate;

final ExtensionFileFilter filter =
new ExtensionFileFilter( new String[] { ".jar", ".zip" } );

final File[] files = libDir.listFiles( filter );

final AntLoader classLoader = AntLoader.getLoader();

for( int i = 0; i < files.length; i++ )
{
//except for a few *special* files add all the
@@ -524,28 +446,8 @@ public class Main
catch( final MalformedURLException mue ) {}
}
}
}

/**
* Using a specified builder create a project from a particular file.
*
* @param builderName the name of the builder class
* @param file the file
* @return the newly created Project
* @exception AntException if an error occurs
* @exception IOException if an error occurs
*/
protected Project getProject( final String builderName, final File file )
throws AntException, IOException
{
m_logger.debug( "Ant Project Builder: " + builderName );
final ProjectBuilder builder = createBuilder( builderName );
builder.setLogger( m_logger );

//create the project
final Project project = builder.build( file );

return project;
return classLoader;
}

/**
@@ -562,12 +464,11 @@ public class Main
{
//put these values into defines so that they overide
//user-defined proeprties
defines.put( AntContextResources.HOME_DIR, m_homeDir );
defines.put( AntContextResources.BIN_DIR, m_binDir );
defines.put( AntContextResources.LIB_DIR, m_libDir );
defines.put( AntContextResources.TASKLIB_DIR, m_taskLibDir );
//defines.put( AntContextResources.USER_DIR, m_userDir );
defines.put( TaskletContext.JAVA_VERSION, getJavaVersion() );
//defines.put( AntContextResources.HOME_DIR, m_homeDir );
//defines.put( AntContextResources.BIN_DIR, m_binDir );
//defines.put( AntContextResources.LIB_DIR, m_libDir );
//defines.put( AntContextResources.TASKLIB_DIR, m_taskLibDir );
//defines.put( TaskletContext.JAVA_VERSION, getJavaVersion() );

final TaskletContext context = project.getContext();
addToContext( context, defines );
@@ -593,330 +494,5 @@ public class Main
context.setProperty( key, value );
}
}

/**
* Helper method to retrieve current JVM version.
* Basically stolen from original Ant sources.
*
* @return the current JVM version
*/
protected JavaVersion getJavaVersion()
{
JavaVersion version = JavaVersion.JAVA1_0;

try
{
Class.forName( "java.lang.Void" );
version = JavaVersion.JAVA1_1;
Class.forName( "java.lang.ThreadLocal" );
version = JavaVersion.JAVA1_2;
Class.forName( "java.lang.StrictMath" );
version = JavaVersion.JAVA1_3;
}
catch( final ClassNotFoundException cnfe ) {}

return version;
}

/**
* Create and configure project engine
*
* @return the ProjectEngine
*/
protected ProjectEngine getProjectEngine()
{
final ProjectEngine engine = createProjectEngine();
engine.setLogger( m_logger );
return engine;
}

/**
* Create the project engine.
* This is seperate method so that it can be overidden in a sub-class.
*
* @return the new ProjectEngine
*/
protected ProjectEngine createProjectEngine()
{
return (ProjectEngine)createObject( DEFAULT_ENGINE, "project-engine" );
}

protected File getHomeDir( final String homeDir )
throws AntException
{
final File file = (new File( homeDir )).getAbsoluteFile();
checkDirectory( file, "ant-home" );
return file;
}

protected File getBinDir( final String binDir )
throws AntException
{
File file = (new File( binDir )).getAbsoluteFile();
if( !file.isDirectory() ) file = file.getParentFile();
checkDirectory( file, "bin-dir" );
return file;
}

protected File getLibDir( final File antHome, String libDir )
throws AntException
{
return resolveDirectory( antHome, libDir, "lib-dir" );
}

protected File getTaskLibDir( final File antHome, final String taskLibDir )
throws AntException
{
return resolveDirectory( antHome, taskLibDir, "task-lib-dir" );
}

protected File resolveDirectory( final File antHome, final String dir, final String name )
throws AntException
{
final File file = FileUtil.resolveFile( antHome, dir );
checkDirectory( file, name );
return file;
}

protected void checkDirectory( final File file, final String name )
{
if( !file.exists() )
{
throw new AntException( name + " (" + file + ") does not exist" );
}
else if( !file.isDirectory() )
{
throw new AntException( name + " (" + file + ") is not a directory" );
}
}

protected ProjectListener createListener( final String listenerName )
throws AntException
{
try { return (ProjectListener)createObject( listenerName, "listener" ); }
catch( final ClassCastException cce )
{
throw new AntException( "Aparently the listener named " + listenerName +
" does not implement the ProjectListener interface",
cce );
}
}

protected void setupDefaultAntDirs()
{
final String os = System.getProperty( "os.name" );
final String userDir = System.getProperty( "user.home" );
m_userDir =
(new File( getUserLocationFor( os, userDir ) )).getAbsoluteFile();
}

/**
* Retrieve default bin-dir value if possible (Otherwise throw an exception).
*
* Lookup OS specific places for ant to be.
* /opt/ant on *BSD ?
* /usr/local/ant on linux ?
* /Program Files/Ant on Win32 ?
*
* @return bin directory
*/
protected File getDefaultHomeDir()
throws AntException
{
if( null != m_userDir )
{
try
{
checkDirectory( m_userDir, null );
return m_userDir;
}
catch( final AntException ae ) {}
}

final String os = System.getProperty( "os.name" );
final File candidate =
(new File( getSystemLocationFor( os ) )).getAbsoluteFile();
checkDirectory( candidate, "ant-home" );
return candidate;
}

/**
* This determins a mapping from an OS specific place to ants home directory.
* In later versions the mapping should be read from configuration file.
*
* @param os the name of OS
* @return the location of directory
*/
protected String getUserLocationFor( final String os, final String userDir )
{
if( os.startsWith( "Windows" ) )
{
return userDir + "\\Ant";
}
else if( '/' == File.separatorChar )
{
if( os.startsWith( "Linux" ) ) return userDir + "/ant";
else return userDir + "/opt/ant";
}
else
{
return userDir + File.separator + "ant";
}
}

/**
* This determins a mapping from an OS specific place to ants home directory.
* In later versions the mapping should be read from configuration file.
*
* @param os the name of OS
* @return the location of directory
*/
protected String getSystemLocationFor( final String os )
{
if( os.startsWith( "Windows" ) )
{
return "\\Program Files\\Ant";
}
else if( '/' == File.separatorChar )
{
if( os.startsWith( "Linux" ) ) return "/usr/local/ant";
else return "/opt/ant";
}
else
{
return File.separator + "ant";
}
}

protected String getDefaultLibDir()
{
return DEFAULT_LIB_DIRECTORY;
}

protected String getDefaultTaskLibDir()
{
return DEFAULT_TASKLIB_DIRECTORY;
}

/**
* Retrieve default filename. Overide this in base classes to change default.
*
* @return the default filename
*/
protected String getDefaultFilename()
{
return DEFAULT_FILENAME;
}
/**
* Retrieve default logelevel. Overide this in base classes to change default.
*
* @return the default loglevel
*/
protected String getDefaultLogLevel()
{
return DEFAULT_LOGLEVEL;
}
/**
* Retrieve default listener. Overide this in base classes to change default.
*
* @return the default listener
*/
protected String getDefaultListener()
{
return DEFAULT_LISTENER;
}

/**
* Get File object for filename.
* Check that file exists and is not a directory.
*
* @param filename the filename
* @return the file object
* @exception AntException if an error occurs
*/
protected File getFile( final String filename )
throws AntException, IOException
{
final File file = (new File( filename )).getCanonicalFile();
if( !file.exists() )
{
throw new AntException( "File " + file + " does not exist." );
}
if( file.isDirectory() )
{
throw new AntException( "File " + file + " is a directory." );
}

return file;
}

/**
* Create instance of Builder based on classname.
*
* @param builderName builder class name
* @return the ProjectBuilder
* @exception AntException if an error occurs
*/
protected ProjectBuilder createBuilder( final String builderName )
throws AntException
{
try { return (ProjectBuilder)createObject( builderName, "builder" ); }
catch( final ClassCastException cce )
{
throw new AntException( "Aparently the builder named " + builderName +
" does not implement the ProjectBuilder interface",
cce );
}
}

/**
* Helper method to create object and throw an apporpriate AntException if creation failed.
*
* @param objectName the classname of object
* @param type the type of object being created (ie builder|listener)
* @return the created object
* @exception AntException if an error occurs
*/
protected Object createObject( final String objectName, final String type )
throws AntException
{
try
{
return ObjectUtil.createObject( objectName );
}
catch( final IllegalAccessException iae )
{
throw new AntException( "Non-public constructor for " + type + " " + objectName,
iae );
}
catch( final InstantiationException ie )
{
throw new AntException( "Error instantiating class for " + type + " " + objectName,
ie );
}
catch( final ClassNotFoundException cnfe )
{
throw new AntException( "Could not find the class for " + type + " " + objectName,
cnfe );
}
}

/**
* Retrieve class name of builder for file.
* Eventually this will look in a registry of file extentions to BuilderNames.
*
* @param filename the filename
* @return the name of Class for Builder
* @exception AntException if an error occurs
*/
protected String getBuilderNameFor( final String filename )
throws AntException
{
return DEFAULT_BUILDER;
}
}


+ 0
- 6
proposal/myrmidon/src/java/org/apache/ant/configuration/ConfigurationBuilder.java View File

@@ -18,12 +18,6 @@ import org.xml.sax.SAXException;
public class ConfigurationBuilder
extends org.apache.avalon.DefaultConfigurationBuilder
{
public ConfigurationBuilder()
throws SAXException
{
super();
}

protected org.apache.avalon.SAXConfigurationHandler getHandler()
{
return new SAXConfigurationHandler();


+ 14
- 15
proposal/myrmidon/src/java/org/apache/ant/configuration/DefaultConfigurer.java View File

@@ -13,9 +13,9 @@ import java.util.ArrayList;
import java.util.Iterator;
import org.apache.ant.convert.Converter;
import org.apache.ant.convert.ConverterException;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.ConfigurationException;
import org.apache.avalon.Context;
@@ -30,6 +30,7 @@ import org.apache.log.Logger;
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultConfigurer
extends AbstractLoggable
implements Configurer, Composer, Loggable
{
protected final static String RESERVED_ATTRIBUTES[] =
@@ -44,15 +45,9 @@ public class DefaultConfigurer

protected final static boolean DEBUG = false;
protected Converter m_converter;
protected Logger m_logger;

public void setLogger( final Logger logger )
{
m_logger = logger;
}

public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
m_converter = (Converter)componentManager.lookup( "org.apache.ant.convert.Converter" );
}
@@ -206,7 +201,7 @@ public class DefaultConfigurer
final Object objectValue =
PropertyUtil.resolveProperty( value, context, false );

setValue( object, objectValue, methods );
setValue( object, objectValue, methods, context );
}
catch( final PropertyException pe )
{
@@ -215,7 +210,10 @@ public class DefaultConfigurer
}
}

protected void setValue( final Object object, Object value, final Method methods[] )
protected void setValue( final Object object,
Object value,
final Method methods[],
final Context context )
throws ConfigurationException
{
final Class sourceClass = value.getClass();
@@ -223,7 +221,7 @@ public class DefaultConfigurer

for( int i = 0; i < methods.length; i++ )
{
if( setValue( object, value, methods[ i ], sourceClass, source ) )
if( setValue( object, value, methods[ i ], sourceClass, source, context ) )
{
return;
}
@@ -238,7 +236,8 @@ public class DefaultConfigurer
Object value,
final Method method,
final Class sourceClass,
final String source )
final String source,
final Context context )
throws ConfigurationException
{
Class parameterType = method.getParameterTypes()[ 0 ];
@@ -249,7 +248,7 @@ public class DefaultConfigurer
try
{
value = m_converter.convert( parameterType, value );
value = m_converter.convert( parameterType, value, context );
}
catch( final ConverterException ce )
{
@@ -359,7 +358,7 @@ public class DefaultConfigurer

protected String getMethodNameFor( final String attribute )
{
return "set" + getJavaNameFor( attribute );
return "set" + getJavaNameFor( attribute.toLowerCase() );
}

protected String getJavaNameFor( final String name )


+ 7
- 3
proposal/myrmidon/src/java/org/apache/ant/convert/AbstractConverter.java View File

@@ -7,6 +7,8 @@
*/
package org.apache.ant.convert;

import org.apache.avalon.Context;

/**
* Instances of this interface are used to convert between different types.
*
@@ -35,10 +37,11 @@ public abstract class AbstractConverter
*
* @param destination the destination type
* @param original the original Object
* @param context the context in which to convert
* @return the converted object
* @exception Exception if an error occurs
*/
public Object convert( final Class destination, final Object original )
public Object convert( final Class destination, final Object original, Context context )
throws Exception
{
if( m_destination != destination )
@@ -53,17 +56,18 @@ public abstract class AbstractConverter
"instance of " + m_source.getName() );
}
return convert( original );
return convert( original, context );
}

/**
* Overide this in a particular converter to do the conversion.
*
* @param original the original Object
* @param context the context in which to convert
* @return the converted object
* @exception Exception if an error occurs
*/
protected abstract Object convert( Object original )
protected abstract Object convert( Object original, Context context )
throws Exception;
}


+ 4
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/Converter.java View File

@@ -7,6 +7,8 @@
*/
package org.apache.ant.convert;

import org.apache.avalon.Context;

/**
* Instances of this interface are used to convert between different types.
*
@@ -21,9 +23,10 @@ public interface Converter
*
* @param destination the destinaiton type
* @param original the original type
* @param context the context in which to convert
* @return the converted object
* @exception Exception if an error occurs
*/
Object convert( Class destination, Object original )
Object convert( Class destination, Object original, Context context )
throws ConverterException, Exception;
}

+ 17
- 3
proposal/myrmidon/src/java/org/apache/ant/convert/ConverterEngine.java View File

@@ -8,13 +8,27 @@
package org.apache.ant.convert;

import org.apache.avalon.Component;
import org.apache.avalon.Loggable;
import org.apache.avalon.camelot.LocatorRegistry;
import org.apache.log.Logger;

/**
* Converter engine to handle converting between types.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface ConverterEngine
extends Component, Converter, Loggable
extends Component, Converter
{
/**
* Get registry used to locate converters.
*
* @return the LocatorRegistry
*/
LocatorRegistry getRegistry();

/**
* Get registry for converterInfo objects.
*
* @return the ConverterRegistry
*/
ConverterRegistry getInfoRegistry();
}

+ 49
- 35
proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterEngine.java View File

@@ -8,62 +8,74 @@
package org.apache.ant.convert;

import org.apache.ant.AntException;
import org.apache.avalon.Component;
import org.apache.avalon.Initializable;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.Context;
import org.apache.avalon.camelot.DefaultFactory;
import org.apache.avalon.camelot.DefaultLocatorRegistry;
import org.apache.avalon.camelot.Factory;
import org.apache.avalon.camelot.Locator;
import org.apache.avalon.camelot.LocatorRegistry;
import org.apache.log.Logger;

/**
* Converter engine to handle converting between types.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultConverterEngine
implements ConverterEngine, Initializable
extends AbstractLoggable
implements ConverterEngine, Composer
{
protected final static boolean DEBUG = false;
protected DefaultFactory m_factory;
protected LocatorRegistry m_registry;
protected ConverterRegistry m_infoRegistry;
protected Logger m_logger;

public void setLogger( final Logger logger )
{
m_logger = logger;
}
protected Factory m_factory;
protected LocatorRegistry m_registry = new DefaultLocatorRegistry();
protected ConverterRegistry m_infoRegistry = new DefaultConverterRegistry();

/**
* Get registry used to locate converters.
*
* @return the LocatorRegistry
*/
public LocatorRegistry getRegistry()
{
return m_registry;
}

/**
* Get registry for converterInfo objects.
*
* @return the ConverterRegistry
*/
public ConverterRegistry getInfoRegistry()
{
return m_infoRegistry;
}

public void init()
throws Exception
{
m_infoRegistry = createInfoRegistry();
m_registry = createRegistry();
m_factory = createFactory();
}
protected ConverterRegistry createInfoRegistry()
{
return new DefaultConverterRegistry();
}

protected LocatorRegistry createRegistry()
{
return new DefaultLocatorRegistry();
}

protected DefaultFactory createFactory()
/**
* Retrieve relevent services needed to deploy.
*
* @param componentManager the ComponentManager
* @exception ComponentManagerException if an error occurs
*/
public void compose( final ComponentManager componentManager )
throws ComponentManagerException
{
return new DefaultFactory();
m_factory = (Factory)componentManager.lookup( "org.apache.avalon.camelot.Factory" );
}

public Object convert( Class destination, final Object original )
/**
* Convert object to destination type.
*
* @param destination the destination type
* @param original the original object
* @param context the context in which to convert
* @return the converted object
* @exception Exception if an error occurs
*/
public Object convert( Class destination, final Object original, final Context context )
throws Exception
{
final Class originalClass = original.getClass();
@@ -79,6 +91,7 @@ public class DefaultConverterEngine
" to " + destination.getName() );
}

//TODO: Start searching inheritance hierarchy for converter
final String name =
m_infoRegistry.getConverterInfoName( originalClass.getName(),
destination.getName() );
@@ -90,8 +103,9 @@ public class DefaultConverterEngine
destination.getName() + " conversion" );
}

//TODO: Start caching converters instead of repeatedly instantiating em.
final Locator locator = m_registry.getLocator( name );
final Converter converter = (Converter)m_factory.create( locator, Converter.class );
return converter.convert( destination, original );
return converter.convert( destination, original, context );
}
}

+ 14
- 7
proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterRegistry.java View File

@@ -8,7 +8,7 @@
package org.apache.ant.convert;

import java.util.HashMap;
import org.apache.avalon.camelot.AbstractRegistry;
import org.apache.avalon.camelot.DefaultRegistry;
import org.apache.avalon.camelot.Info;
import org.apache.avalon.camelot.RegistryException;

@@ -18,11 +18,16 @@ import org.apache.avalon.camelot.RegistryException;
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultConverterRegistry
extends AbstractRegistry
extends DefaultRegistry
implements ConverterRegistry
{
protected final HashMap m_mapping = new HashMap();

public DefaultConverterRegistry()
{
super( ConverterInfo.class );
}

/**
* Retrieve ConverterInfo that describes converter that converts from source to destination.
*
@@ -37,6 +42,13 @@ public class DefaultConverterRegistry
return (String)map.get( destination );
}

/**
* Overidden method so can add info into mapping.
*
* @param name the name of info
* @param info the Info
* @exception RegistryException if an error occurs
*/
protected void checkInfo( final String name, final Info info )
throws RegistryException
{
@@ -55,9 +67,4 @@ public class DefaultConverterRegistry
map.put( destination, name );
}

protected Class getInfoClass()
{
return ConverterInfo.class;
}
}

+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToByteConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to byte converter
@@ -22,7 +23,7 @@ public class StringToByteConverter
super( String.class, Byte.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new Byte( (String)original );


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToClassConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to class converter
@@ -22,7 +23,7 @@ public class StringToClassConverter
super( String.class, Class.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return Class.forName( (String)original );


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToDoubleConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to double converter
@@ -22,7 +23,7 @@ public class StringToDoubleConverter
super( String.class, Double.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new Double( (String)original );


+ 35
- 0
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFileConverter.java View File

@@ -0,0 +1,35 @@
/*
* 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 file.
*/
package org.apache.ant.convert.core;

import java.io.File;
import org.apache.ant.convert.AbstractConverter;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.avalon.Context;

/**
* String to file converter
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class StringToFileConverter
extends AbstractConverter
{
public StringToFileConverter()
{
super( String.class, File.class );
}

public Object convert( final Object original, final Context context )
throws Exception
{
final TaskletContext taskletContext = (TaskletContext)context;
return taskletContext.resolveFile( (String)original );
}
}


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFloatConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to float converter
@@ -22,7 +23,7 @@ public class StringToFloatConverter
super( String.class, Float.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new Float( (String)original );


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToIntegerConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to integer converter.
@@ -22,7 +23,7 @@ public class StringToIntegerConverter
super( String.class, Integer.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new Integer( (String)original );


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToLongConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to long converter
@@ -22,7 +23,7 @@ public class StringToLongConverter
super( String.class, Long.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new Long( (String)original );


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToShortConverter.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.convert.core;

import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to short converter
@@ -22,7 +23,7 @@ public class StringToShortConverter
super( String.class, Short.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new Short( (String)original );


+ 2
- 1
proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToURLConverter.java View File

@@ -9,6 +9,7 @@ package org.apache.ant.convert.core;

import java.net.URL;
import org.apache.ant.convert.AbstractConverter;
import org.apache.avalon.Context;

/**
* String to url converter
@@ -23,7 +24,7 @@ public class StringToURLConverter
super( String.class, URL.class );
}

public Object convert( final Object original )
public Object convert( final Object original, final Context context )
throws Exception
{
return new URL( (String)original );


+ 21
- 1
proposal/myrmidon/src/java/org/apache/ant/datatypes/DataTypeEngine.java View File

@@ -13,11 +13,31 @@ import org.apache.avalon.camelot.FactoryException;
import org.apache.avalon.camelot.LocatorRegistry;
import org.apache.avalon.camelot.RegistryException;

/**
* This is basically a engine that can be used to access data-types.
* The engine acts as a repository and factory for these types.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface DataTypeEngine
extends Component, Loggable
extends Component
{
/**
* Retrieve registry of data-types.
* This is used by deployer to add types into engine.
*
* @return the registry
*/
LocatorRegistry getRegistry();

/**
* Create a data-type of type registered under name.
*
* @param name the name of data type
* @return the DataType
* @exception RegistryException if an error occurs
* @exception FactoryException if an error occurs
*/
DataType createDataType( String name )
throws RegistryException, FactoryException;
}

+ 39
- 42
proposal/myrmidon/src/java/org/apache/ant/datatypes/DefaultDataTypeEngine.java View File

@@ -7,65 +7,62 @@
*/
package org.apache.ant.datatypes;

import org.apache.ant.AntException;
import org.apache.avalon.Initializable;
import org.apache.avalon.Loggable;
import org.apache.avalon.camelot.DefaultFactory;
import org.apache.avalon.Composer;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.camelot.DefaultLocatorRegistry;
import org.apache.avalon.camelot.Factory;
import org.apache.avalon.camelot.FactoryException;
import org.apache.avalon.camelot.Locator;
import org.apache.avalon.camelot.LocatorRegistry;
import org.apache.avalon.camelot.RegistryException;
import org.apache.avalon.camelot.FactoryException;
import org.apache.log.Logger;

/**
* This is basically a engine that can be used to access data-types.
* The engine acts as a repository and factory for these types.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultDataTypeEngine
implements DataTypeEngine, Initializable
implements DataTypeEngine, Composer
{
protected DefaultFactory m_factory;
protected LocatorRegistry m_registry;
protected Logger m_logger;
public void setLogger( final Logger logger )
{
m_logger = logger;
}
protected Factory m_factory;
protected LocatorRegistry m_registry = new DefaultLocatorRegistry();
/**
* Retrieve registry of data-types.
* This is used by deployer to add types into engine.
*
* @return the registry
*/
public LocatorRegistry getRegistry()
{
return m_registry;
}
public void init()
throws Exception
{
m_registry = createRegistry();
setupComponent( m_registry );

m_factory = createFactory();
setupComponent( m_factory );
}

protected void setupComponent( final Object object )
throws Exception
{
if( object instanceof Loggable )
{
((Loggable)object).setLogger( m_logger );
}
}
protected LocatorRegistry createRegistry()
{
return new DefaultLocatorRegistry();
}
protected DefaultFactory createFactory()
/**
* Retrieve relevent services needed to deploy.
*
* @param componentManager the ComponentManager
* @exception ComponentManagerException if an error occurs
*/
public void compose( final ComponentManager componentManager )
throws ComponentManagerException
{
return new DefaultFactory();
m_factory = (Factory)componentManager.lookup( "org.apache.avalon.camelot.Factory" );
}
/**
* Create a data-type of type registered under name.
*
* @param name the name of data type
* @return the DataType
* @exception RegistryException if an error occurs
* @exception FactoryException if an error occurs
*/
public DataType createDataType( final String name )
throws RegistryException, FactoryException
throws RegistryException, FactoryException
{
final Locator locator = m_registry.getLocator( name );
return (DataType)m_factory.create( locator, DataType.class );


+ 35
- 0
proposal/myrmidon/src/java/org/apache/ant/datatypes/Pattern.java View File

@@ -8,6 +8,7 @@
package org.apache.ant.datatypes;

import org.apache.ant.AntException;
import org.apache.ant.util.Condition;

/**
* Basic data type for holding patterns.
@@ -20,21 +21,43 @@ public class Pattern
protected String m_name;
protected Condition m_condition;

/**
* Retrieve name (aka value) of pattern.
*
* @return the name/value of pattern
*/
public String getName()
{
return m_name;
}
/**
* Get condition associated with pattern if any.
*
* @return the Condition
*/
public Condition getCondition()
{
return m_condition;
}
/**
* Setter method for name/value of pattern.
* Conforms to ant setter patterns
*
* @param name the value
*/
public void setName( final String name )
{
m_name = name;
}

/**
* Set if clause on pattern.
*
* @param condition the condition
* @exception AntException if an error occurs
*/
public void setIf( final String condition )
throws AntException
{
@@ -42,6 +65,12 @@ public class Pattern
m_condition = new Condition( true, condition );
}

/**
* Set unless clause of pattern.
*
* @param condition the unless clause
* @exception AntException if an error occurs
*/
public void setUnless( final String condition )
throws AntException
{
@@ -49,6 +78,12 @@ public class Pattern
m_condition = new Condition( false, condition );
}

/**
* Utility method to make sure condition unset.
* Made so that it is not possible for both if and unless to be set.
*
* @exception AntException if an error occurs
*/
protected void verifyConditionNull()
throws AntException
{


+ 56
- 0
proposal/myrmidon/src/java/org/apache/ant/launcher/AntClassLoader.java View File

@@ -0,0 +1,56 @@
/*
* 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 file.
*/
package org.apache.ant.launcher;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.StringTokenizer;

/**
* Basic classloader that allows modification at runtime.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public final class AntClassLoader
extends URLClassLoader
{
/**
* Basic constructor.
*
* @param urls the Starting URLS
*/
public AntClassLoader( final URL[] urls )
{
super( urls );
}

/**
* Add a URL to classloader
*
* @param url the url
*/
public void addURL( final URL url )
{
super.addURL( url );
}
/**
* Add an array of URLs to classloader
*
* @param url the url
*/
public void addURLs( final URL[] urls )
{
for( int i = 0; i < urls.length; i++ )
{
addURL( urls[ i ] );
}
}
}

+ 48
- 32
proposal/myrmidon/src/java/org/apache/ant/launcher/AntLoader.java View File

@@ -7,31 +7,22 @@
*/
package org.apache.ant.launcher;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.StringTokenizer;

/**
* Basic Loader that is responsible for all the hackery to get classloader to work.
* Other classes can call AntLoader.getLoader() and add to their own classloader.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
* @author <a href="mailto:mpfoemme@thoughtworks.com">Matthew Foemmel</a>
*/
public final class AntLoader
extends URLClassLoader
{
protected static AntLoader c_classLoader;

public static AntLoader getLoader()
{
if( null == c_classLoader )
{
c_classLoader = new AntLoader( new URL[ 0 ] );
}

return c_classLoader;
}

/**
* Magic entry point.
*
@@ -40,42 +31,67 @@ public final class AntLoader
*/
public final static void main( final String[] args )
throws Exception
{
final URL archive = new URL( "file:lib/myrmidon.jar" );
c_classLoader = new AntLoader( new URL[] { archive } );
{
try
{
//actually try to discover the install directory based on where
// the ant.jar is
final File installDirectory = findInstallDir();
System.setProperty( "ant.home", installDirectory.toString() );

//setup classloader appropriately for myrmidon jar
final File archive =
new File( installDirectory, "lib" + File.separator + "myrmidon.jar" );
final AntClassLoader classLoader =
new AntClassLoader( new URL[] { archive.toURL() } );

//load class and retrieve appropriate main method.
final Class clazz = c_classLoader.loadClass( "org.apache.ant.Main" );
final Class clazz = classLoader.loadClass( "org.apache.ant.Main" );
final Method method = clazz.getMethod( "main", new Class[] { args.getClass() } );
//kick the tires and light the fires....
method.invoke( null, new Object[] { args } );
}
catch( final InvocationTargetException ite )
{
System.err.println( "Error: " + ite.getTargetException().getMessage() );
ite.getTargetException().printStackTrace();
}
catch( final Throwable throwable )
{
System.err.println( "Error: " + throwable.getMessage() );
throwable.printStackTrace();
}
}

/**
* Basic constructor.
*
* @param urls the Starting URLS
* Finds the ant.jar file in the classpath.
*/
public AntLoader( final URL[] urls )
protected final static File findInstallDir()
throws Exception
{
super( urls );
}
final String classpath = System.getProperty( "java.class.path" );
final String pathSeparator = System.getProperty( "path.separator" );
final StringTokenizer tokenizer = new StringTokenizer( classpath, pathSeparator );
while( tokenizer.hasMoreTokens() )
{
final String element = tokenizer.nextToken();

/**
* Add a URL to classloader
*
* @param url the url
*/
public void addURL( final URL url )
{
super.addURL( url );
if( element.endsWith( "ant.jar" ) )
{
File file = (new File( element )).getAbsoluteFile();
file = file.getParentFile();
if( null != file )
{
file = file.getParentFile();
}

return file;
}
}
throw new Exception( "Unable to locate ant.jar in classpath" );
}
}

+ 54
- 4
proposal/myrmidon/src/java/org/apache/ant/project/DefaultProject.java View File

@@ -16,6 +16,11 @@ import org.apache.ant.AntException;
import org.apache.ant.tasklet.DefaultTaskletContext;
import org.apache.ant.tasklet.TaskletContext;

/**
* Default project implementation.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultProject
implements Project
{
@@ -23,42 +28,87 @@ public class DefaultProject
protected final HashMap m_targets = new HashMap();
protected Target m_implicitTarget;
protected String m_defaultTarget;

/**
* Retrieve implicit target.
* The implicit target is top level tasks.
* Currently restricted to property tasks.
*
* @return the Target
*/
public Target getImplicitTarget()
{
return m_implicitTarget;
}

/**
* Set ImplicitTarget.
*
* @param target the implicit target
*/
public void setImplicitTarget( final Target target )
{
m_implicitTarget = target;
}

/**
* Retrieve a target by name.
*
* @param name the name of target
* @return the Target or null if no target exists with name
*/
public Target getTarget( final String targetName )
{
return (Target)m_targets.get( targetName );
}

/**
* Get name of default target.
*
* @return the default target name
*/
public String getDefaultTargetName()
{
return m_defaultTarget;
}

/**
* Retrieve names of all targets in project.
*
* @return the iterator of project names
*/
public Iterator getTargetNames()
{
return m_targets.keySet().iterator();
}
/**
* Get project (top-level) context.
*
* @return the context
*/
public TaskletContext getContext()
{
return m_baseContext;
}

/**
* Set DefaultTargetName.
*
* @param defaultTarget the default target name
*/
public void setDefaultTargetName( final String defaultTarget )
{
m_defaultTarget = defaultTarget;
}

/**
* Add a target to project.
*
* @param name the name of target
* @param target the Target
* @exception AntException if an error occurs
*/
public void addTarget( final String name, final Target target )
throws AntException
{


+ 117
- 78
proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectBuilder.java View File

@@ -13,54 +13,87 @@ import java.util.Iterator;
import org.apache.ant.AntException;
import org.apache.ant.configuration.Configuration;
import org.apache.ant.configuration.ConfigurationBuilder;
import org.apache.ant.datatypes.Condition;
import org.apache.ant.util.Condition;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.ConfigurationException;
import org.apache.avalon.util.StringUtil;
import org.apache.log.Logger;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* Default implementation to construct project from a build file.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultProjectBuilder
extends AbstractLoggable
implements ProjectBuilder
{
protected final ConfigurationBuilder m_configurationBuilder;
protected Logger m_logger;
protected ConfigurationBuilder m_builder;

public DefaultProjectBuilder()
{
ConfigurationBuilder builder = null;
try { builder = new ConfigurationBuilder(); }
catch( final SAXException se ) {}

m_configurationBuilder = builder;
}

public void setLogger( final Logger logger )
{
m_logger = logger;
m_builder = new ConfigurationBuilder();
}

/**
* build a project from file.
*
* @param source the source
* @return the constructed Project
* @exception IOException if an error occurs
* @exception AntException if an error occurs
*/
public Project build( final File projectFile )
throws IOException, AntException
{
try
{
final String location = projectFile.getCanonicalFile().toURL().toString();
final InputSource inputSource = new InputSource( location );
final Configuration configuration =
(Configuration)m_configurationBuilder.build( inputSource );
final String location = projectFile.getCanonicalFile().toString();
final Configuration configuration = buildConfiguration( location );
return build( projectFile, configuration );
}
catch( final SAXException se )
{
throw new AntException( "SAXEception: " + se.getMessage(), se );
}
catch( final ConfigurationException ce )
{
throw new AntException( "ConfigurationException: " + ce.getMessage(), ce );
}
}

/**
* Utility method to build a Configuration tree from a source.
* Overide this in sub-classes if you want to provide extra
* functionality (ie xslt/css).
*
* @param location the location
* @return the created Configuration
* @exception AntException if an error occurs
* @exception IOException if an error occurs
*/
protected Configuration buildConfiguration( final String location )
throws AntException, IOException, ConfigurationException
{
try
{
return (Configuration)m_builder.build( location );
}
catch( final SAXException se )
{
throw new AntException( "SAXEception: " + se.getMessage(), se );
}
}

/**
* build project from configuration.
*
* @param file the file from which configuration was loaded
* @param configuration the configuration loaded
* @return the created Project
* @exception IOException if an error occurs
* @exception AntException if an error occurs
* @exception ConfigurationException if an error occurs
*/
protected Project build( final File file, final Configuration configuration )
throws IOException, AntException, ConfigurationException
{
@@ -68,29 +101,41 @@ public class DefaultProjectBuilder
{
throw new AntException( "Project file must be enclosed in project element" );
}

//get project-level attributes
final String baseDirectoryName = configuration.getAttribute( "basedir" );
final String defaultTarget = configuration.getAttribute( "default" );
final String projectName = configuration.getAttribute( "name" );

final DefaultProject project = new DefaultProject();
project.setDefaultTargetName( defaultTarget );

//determine base directory for project
final File baseDirectory =
(new File( file.getParentFile(), baseDirectoryName )).getAbsoluteFile();

m_logger.debug( "Project " + projectName + " base directory: " + baseDirectory );
getLogger().debug( "Project " + projectName + " base directory: " + baseDirectory );

//create project and ...
final DefaultProject project = new DefaultProject();
project.setDefaultTargetName( defaultTarget );
//setup basic context of project
final TaskletContext context = project.getContext();
context.setProperty( TaskletContext.BASE_DIRECTORY, baseDirectory );
context.setProperty( Project.PROJECT_FILE, file );
context.setProperty( Project.PROJECT, projectName );

//build using all top-level attributes
buildTopLevelProject( project, configuration );

return project;
}

/**
* Handle all top level elements in configuration.
*
* @param project the project
* @param configuration the Configuration
* @exception AntException if an error occurs
*/
protected void buildTopLevelProject( final DefaultProject project,
final Configuration configuration )
throws AntException
@@ -102,8 +147,9 @@ public class DefaultProjectBuilder
final Configuration element = (Configuration)elements.next();
final String name = element.getName();

//handle individual elements
if( name.equals( "target" ) ) buildTarget( project, element );
else if( name.equals( "property" ) ) buildProperty( project, element );
else if( name.equals( "property" ) ) buildImplicitTask( project, element );
else
{
throw new AntException( "Unknown top-level element " + name +
@@ -112,95 +158,88 @@ public class DefaultProjectBuilder
}
}

protected void buildTarget( final DefaultProject project,
final Configuration configuration )
/**
* Build a target from configuration.
*
* @param project the project
* @param task the Configuration
*/
protected void buildTarget( final DefaultProject project, final Configuration target )
{
final String name = configuration.getAttribute( "name", null );
final String depends = configuration.getAttribute( "depends", null );
final String ifCondition = configuration.getAttribute( "if", null );
final String unlessCondition = configuration.getAttribute( "unless", null );
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 );

if( null == name )
{
throw new AntException( "Discovered un-named target at " +
configuration.getLocation() );
target.getLocation() );
}

m_logger.debug( "Parsing target: " + name );
getLogger().debug( "Parsing target: " + name );

if( null != ifCondition && null != unlessCondition )
{
throw new AntException( "Discovered invalid target that has both a if and " +
"unless condition at " + configuration.getLocation() );
"unless condition at " + target.getLocation() );
}

Condition condition = null;

if( null != ifCondition )
{
m_logger.debug( "Target if condition: " + ifCondition );
getLogger().debug( "Target if condition: " + ifCondition );
condition = new Condition( true, ifCondition );
}
else if( null != unlessCondition )
{
m_logger.debug( "Target unless condition: " + unlessCondition );
getLogger().debug( "Target unless condition: " + unlessCondition );
condition = new Condition( false, unlessCondition );
}

final DefaultTarget target = new DefaultTarget( condition );
final DefaultTarget defaultTarget = new DefaultTarget( condition );

//apply depends attribute
if( null != depends )
{
int start = 0;
int end = depends.indexOf( ',' );
final String[] elements = StringUtil.splitString( depends, "," );

while( -1 != end )
for( int i = 0; i < elements.length; i++ )
{
final String dependency =
parseDependency( configuration, depends.substring( start, end ) );

target.addDependency( dependency );
start = end++;
end = depends.indexOf( ',', start );
}
final String dependency = elements[ i ].trim();

final String dependency =
parseDependency( configuration, depends.substring( start ) );
if( 0 == dependency.length() )
{
throw new AntException( "Discovered empty dependency in target " +
target.getName() + " at " + target.getLocation() );
}

target.addDependency( dependency );
getLogger().debug( "Target dependency: " + dependency );
defaultTarget.addDependency( dependency );
}
}

final Iterator tasks = configuration.getChildren();
//add all the targets from element
final Iterator tasks = target.getChildren();
while( tasks.hasNext() )
{
final Configuration task = (Configuration)tasks.next();
m_logger.debug( "Parsed task: " + task.getName() );
target.addTask( task );
}

project.addTarget( name, target );
}

protected String parseDependency( final Configuration configuration,
String dependency )
throws AntException
{
dependency = dependency.trim();
if( 0 == dependency.length() )
{
throw new AntException( "Discovered empty dependency in target " +
configuration.getName() + " at " +
configuration.getLocation() );
getLogger().debug( "Parsed task: " + task.getName() );
defaultTarget.addTask( task );
}
m_logger.debug( "Target dependency: " + dependency );

return dependency;
//add target to project
project.addTarget( name, defaultTarget );
}

protected void buildProperty( final DefaultProject project,
final Configuration configuration )
/**
* Create an implict task from configuration
*
* @param project the project
* @param task the configuration
*/
protected void buildImplicitTask( final DefaultProject project, final Configuration task )
{
DefaultTarget target = (DefaultTarget)project.getImplicitTarget();
@@ -210,7 +249,7 @@ public class DefaultProjectBuilder
project.setImplicitTarget( target );
}

m_logger.debug( "Parsed implicit task: " + configuration.getName() );
target.addTask( configuration );
getLogger().debug( "Parsed implicit task: " + task.getName() );
target.addTask( task );
}
}

+ 107
- 64
proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectEngine.java View File

@@ -11,88 +11,80 @@ import java.util.ArrayList;
import java.util.Iterator;
import org.apache.ant.AntException;
import org.apache.ant.configuration.Configuration;
import org.apache.ant.datatypes.Condition;
import org.apache.ant.tasklet.DefaultTaskletContext;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.ant.tasklet.engine.DefaultTaskletEngine;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.ant.util.Condition;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.Composer;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.DefaultComponentManager;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.DefaultComponentManager;
import org.apache.avalon.Disposable;
import org.apache.avalon.Initializable;
import org.apache.log.Logger;

/**
* This is the default implementation of ProjectEngine.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultProjectEngine
implements ProjectEngine, Initializable, Disposable
extends AbstractLoggable
implements ProjectEngine, Composer
{
protected TaskletEngine m_taskletEngine;
protected Logger m_logger;
protected ProjectListenerSupport m_listenerSupport;
protected ProjectListenerSupport m_listenerSupport = new ProjectListenerSupport();
protected DefaultComponentManager m_componentManager;
public void setLogger( final Logger logger )
{
m_logger = logger;
}
/**
* Add a listener to project events.
*
* @param listener the listener
*/
public void addProjectListener( final ProjectListener listener )
{
m_listenerSupport.addProjectListener( listener );
}

/**
* Remove a listener from project events.
*
* @param listener the listener
*/
public void removeProjectListener( final ProjectListener listener )
{
m_listenerSupport.removeProjectListener( listener );
}

public void init()
throws Exception
{
m_listenerSupport = new ProjectListenerSupport();

setupTaskletEngine();

m_componentManager = new DefaultComponentManager();
m_componentManager.put( "org.apache.ant.project.ProjectEngine", this );
m_componentManager.put( "org.apache.ant.tasklet.engine.TaskletEngine", m_taskletEngine );
m_componentManager.put( "org.apache.ant.convert.ConverterEngine",
m_taskletEngine.getConverterEngine() );
}

public void dispose()
throws Exception
{
if( m_taskletEngine instanceof Disposable )
{
((Disposable)m_taskletEngine).dispose();
}
}

public TaskletEngine getTaskletEngine()
/**
* Retrieve relevent services needed for engine.
*
* @param componentManager the ComponentManager
* @exception ComponentManagerException if an error occurs
*/
public void compose( final ComponentManager componentManager )
throws ComponentManagerException
{
return m_taskletEngine;
m_componentManager = (DefaultComponentManager)componentManager;
m_taskletEngine = (TaskletEngine)componentManager.
lookup( "org.apache.ant.tasklet.engine.TaskletEngine" );
}

protected void setupTaskletEngine()
throws Exception
{
m_taskletEngine = createTaskletEngine();
m_taskletEngine.setLogger( m_logger );
if( m_taskletEngine instanceof Initializable )
{
((Initializable)m_taskletEngine).init();
}
}
protected TaskletEngine createTaskletEngine()
{
return new DefaultTaskletEngine();
}
/**
* Execute a target in a particular project.
* Execute in the project context.
*
* @param project the Project
* @param target the name of the target
* @exception AntException if an error occurs
*/
public void execute( final Project project, final String target )
throws AntException
{
//HACK: should do this a better way !!!!!!
m_componentManager.put( "org.apache.ant.project.Project", project );

final TaskletContext context = project.getContext();
@@ -110,12 +102,29 @@ public class DefaultProjectEngine
m_listenerSupport.projectFinished();
}

/**
* Execute a target in a particular project, in a particular context.
*
* @param project the Project
* @param target the name of the target
* @param context the context
* @exception AntException if an error occurs
*/
public void execute( Project project, String target, TaskletContext context )
throws AntException
{
execute( project, target, context, new ArrayList() );
}

/**
* Helper method to execute a target.
*
* @param project the Project
* @param target the name of the target
* @param context the context
* @param done the list of targets already executed in current run
* @exception AntException if an error occurs
*/
protected void execute( final Project project,
final String targetName,
final TaskletContext context,
@@ -128,9 +137,11 @@ public class DefaultProjectEngine
{
throw new AntException( "Unable to find target " + targetName );
}

//add target to list of targets executed
done.add( targetName );

//execute all dependencies
final Iterator dependencies = target.getDependencies();
while( dependencies.hasNext() )
{
@@ -144,41 +155,65 @@ public class DefaultProjectEngine
executeTarget( targetName, target, context );
}

/**
* Method to execute a particular target instance.
*
* @param targetName the name of target
* @param target the target
* @param context the context in which to execute
* @exception AntException if an error occurs
*/
protected void executeTarget( final String targetName,
final Target target,
final TaskletContext context )
throws AntException
{
m_componentManager.put( "org.apache.ant.project.Target", target );
//is this necessary ? I think not but ....
// NO it isn't because you set target name and project has already been provided
//m_componentManager.put( "org.apache.ant.project.Target", target );

//create project context and set target name
final TaskletContext targetContext = new DefaultTaskletContext( context );
targetContext.setProperty( Project.TARGET, targetName );
//notify listeners
m_listenerSupport.targetStarted( targetName );

//actually do the execution work
executeTargetWork( targetName, target, targetContext );
//notify listeners
m_listenerSupport.targetFinished();
}

/**
* Do the work associated with target.
* ie execute all tasks
*
* @param name the name of target
* @param target the target
* @param context the context
*/
protected void executeTargetWork( final String name,
final Target target,
final TaskletContext context )
{
//check the condition associated with target.
//if it is not satisfied then skip target
final Condition condition = target.getCondition();

if( null != condition )
{
if( false == condition.evaluate( context ) )
{
m_logger.debug( "Skipping target " + name +
" as it does not satisfy condition" );
getLogger().debug( "Skipping target " + name +
" as it does not satisfy condition" );
return;
}
}

m_logger.debug( "Executing target " + name );
getLogger().debug( "Executing target " + name );

//execute all tasks assciated with target
final Iterator tasks = target.getTasks();
while( tasks.hasNext() )
{
@@ -187,24 +222,32 @@ public class DefaultProjectEngine
}
}

protected void executeTask( final Configuration configuration,
final TaskletContext context )
/**
* Execute a task.
*
* @param task the task definition
* @param context the context
* @exception AntException if an error occurs
*/
protected void executeTask( final Configuration task, final TaskletContext context )
throws AntException
{
final String name = configuration.getName();
m_logger.debug( "Executing task " + name );
final String name = task.getName();
getLogger().debug( "Executing task " + name );

//Set up context for task...

//is Only necessary if we are multi-threaded
//final TaskletContext targetContext = new DefaultTaskletContext( context );

//is setting name even necessary ???
context.setProperty( TaskletContext.NAME, name );

//notify listeners
m_listenerSupport.taskletStarted( name );

//run task
m_taskletEngine.execute( configuration, context, m_componentManager );
m_taskletEngine.execute( task, context );

//notify listeners task has ended
m_listenerSupport.taskletFinished();


+ 51
- 5
proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectListener.java View File

@@ -9,49 +9,95 @@ package org.apache.ant.project;

import org.apache.avalon.util.StringUtil;

/**
* Default listener that emulates the old ant listener notifications.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultProjectListener
implements ProjectListener
{
protected String m_prefix;

/**
* Notify listener of projectStarted event.
*
* @param projectName the projectName
*/
public void projectStarted( final String projectName )
{
output( "Starting project " + projectName + "\n" );
}

/**
* Notify listener of projectFinished event.
*/
public void projectFinished()
{
}
/**
* Notify listener of targetStarted event.
*
* @param targetName the name of target
*/
public void targetStarted( final String targetName )
{
output( targetName + ":\n" );
}

/**
* Notify listener of targetFinished event.
*/
public void targetFinished()
{
}
/**
* Notify listener of taskletStarted event.
*
* @param taskletName the name of tasklet
*/
public void taskletStarted( final String taskletName )
{
m_prefix = taskletName;
}

/**
* Notify listener of taskletFinished event.
*/
public void taskletFinished()
{
m_prefix = null;
}

/**
* Notify listener of log message event.
*
* @param message the message
*/
public void log( String message )
{
output( message );
}

/**
* Notify listener of log message event.
*
* @param message the message
* @param throwable the throwable
*/
public void log( String message, Throwable throwable )
{
output( message + "\n" + StringUtil.printStackTrace( throwable, 5, true ) );
}

/**
* Utility class to output data.
* Overide in sub-classes to direct to a different destination.
*
* @param data the data
*/
protected void output( final String data )
{
if( null != m_prefix ) System.out.println( "\t[" + m_prefix + "] " + data );


+ 40
- 3
proposal/myrmidon/src/java/org/apache/ant/project/DefaultTarget.java View File

@@ -10,8 +10,13 @@ package org.apache.ant.project;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.ant.configuration.Configuration;
import org.apache.ant.datatypes.Condition;
import org.apache.ant.util.Condition;

/**
* Default implementation of target.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultTarget
implements Target
{
@@ -19,36 +24,68 @@ public class DefaultTarget
protected final ArrayList m_tasks = new ArrayList();
protected final Condition m_condition;

/**
* Constructor taking condition for target.
*
* @param condition the condition
*/
public DefaultTarget( final Condition condition )
{
m_condition = condition;
}

/**
* Constructor for target with no condition.
*/
public DefaultTarget()
{
this( null );
}

/**
* Get condition under which target is executed.
*
* @return the condition for target or null
*/
public Condition getCondition()
{
return m_condition;
}
/**
* Get dependencies of target
*
* @return the dependency list
*/
public Iterator getDependencies()
{
return m_dependencies.iterator();
}

/**
* Get tasks in target
*
* @return the target list
*/
public Iterator getTasks()
{
return m_tasks.iterator();
}

/**
* Add a dependency to target.
*
* @param dependency the dependency
*/
public void addDependency( final String dependency )
{
m_dependencies.add( dependency );
}

/**
* Add task to target.
*
* @param taskConfiguration the task representation
*/
public void addTask( final Configuration taskConfiguration )
{
m_tasks.add( taskConfiguration );


+ 10
- 1
proposal/myrmidon/src/java/org/apache/ant/project/LogTargetToListenerAdapter.java View File

@@ -10,12 +10,21 @@ package org.apache.ant.project;
import org.apache.log.LogEntry;
import org.apache.log.LogTarget;

/**
* Adapter between Avalon LogKit and Project listener interfaces.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class LogTargetToListenerAdapter
implements LogTarget
{

protected final ProjectListener m_listener;

/**
* Constructor taking listener to convert to.
*
* @param listener the ProjectListener
*/
public LogTargetToListenerAdapter( final ProjectListener listener )
{
m_listener = listener;


+ 37
- 0
proposal/myrmidon/src/java/org/apache/ant/project/Project.java View File

@@ -12,6 +12,11 @@ import org.apache.ant.AntException;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.avalon.Component;

/**
* Interface through which to interact with projects.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface Project
extends Component
{
@@ -24,9 +29,41 @@ public interface Project
// the name of currently executing target
String TARGET = "ant.target.name";

/**
* Get name of default target.
*
* @return the default target name
*/
String getDefaultTargetName();

/**
* Retrieve implicit target.
* The implicit target is top level tasks.
* Currently restricted to property tasks.
*
* @return the Target
*/
Target getImplicitTarget();

/**
* Retrieve a target by name.
*
* @param name the name of target
* @return the Target or null if no target exists with name
*/
Target getTarget( String name );

/**
* Retrieve names of all targets in project.
*
* @return the iterator of project names
*/
Iterator getTargetNames();

/**
* Get project (top-level) context.
*
* @return the context
*/
TaskletContext getContext();
}

+ 16
- 4
proposal/myrmidon/src/java/org/apache/ant/project/ProjectBuilder.java View File

@@ -10,13 +10,25 @@ package org.apache.ant.project;
import java.io.File;
import java.io.IOException;
import org.apache.ant.AntException;
import org.apache.log.Logger;
import org.apache.avalon.Component;

/**
* Interface implemented by components that build projects from sources.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface ProjectBuilder
extends Component
{
void setLogger( Logger logger );

Project build( File projectFile )
/**
* build a project from source.
*
* @param source the source
* @return the constructed Project
* @exception IOException if an error occurs
* @exception AntException if an error occurs
*/
Project build( File source )
throws IOException, AntException;
}



+ 34
- 5
proposal/myrmidon/src/java/org/apache/ant/project/ProjectEngine.java View File

@@ -11,21 +11,50 @@ import org.apache.ant.AntException;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.avalon.Component;
import org.apache.log.Logger;

/**
* This is the interface between ProjectEngine and rest of the system.
* This is the interface that tasks/frontends must use to interact with
* project execution.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface ProjectEngine
extends Component
{
void setLogger( Logger logger );

TaskletEngine getTaskletEngine();

/**
* Add a listener to project events.
*
* @param listener the listener
*/
void addProjectListener( ProjectListener listener );

/**
* Remove a listener from project events.
*
* @param listener the listener
*/
void removeProjectListener( ProjectListener listener );

/**
* Execute a target in a particular project.
* Execute in the project context.
*
* @param project the Project
* @param target the name of the target
* @exception AntException if an error occurs
*/
void execute( Project project, String target )
throws AntException;

/**
* Execute a target in a particular project, in a particular context.
*
* @param project the Project
* @param target the name of the target
* @param context the context
* @exception AntException if an error occurs
*/
void execute( Project project, String target, TaskletContext context )
throws AntException;
}

+ 45
- 0
proposal/myrmidon/src/java/org/apache/ant/project/ProjectListener.java View File

@@ -7,17 +7,62 @@
*/
package org.apache.ant.project;

/**
* The interface to implement if you want to receive
* notification of project status.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface ProjectListener
{
/**
* Notify listener of projectStarted event.
*
* @param projectName the projectName
*/
void projectStarted( String projectName );

/**
* Notify listener of projectFinished event.
*/
void projectFinished();

/**
* Notify listener of targetStarted event.
*
* @param targetName the name of target
*/
void targetStarted( String targetName );

/**
* Notify listener of targetFinished event.
*/
void targetFinished();

/**
* Notify listener of taskletStarted event.
*
* @param taskletName the name of tasklet
*/
void taskletStarted( String taskletName );

/**
* Notify listener of taskletFinished event.
*/
void taskletFinished();

/**
* Notify listener of log message event.
*
* @param message the message
*/
void log( String message );

/**
* Notify listener of log message event.
*
* @param message the message
* @param throwable the throwable
*/
void log( String message, Throwable throwable );
}

+ 50
- 0
proposal/myrmidon/src/java/org/apache/ant/project/ProjectListenerSupport.java View File

@@ -7,11 +7,21 @@
*/
package org.apache.ant.project;

/**
* Support for the project listener event dispatching.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class ProjectListenerSupport
implements ProjectListener
{
protected ProjectListener[] m_listeners = new ProjectListener[ 0 ];

/**
* Add an extra project listener that wants to receive notification of listener events.
*
* @param listener the listener
*/
public void addProjectListener( final ProjectListener listener )
{
final ProjectListener[] listeners = new ProjectListener[ m_listeners.length + 1 ];
@@ -20,6 +30,11 @@ public class ProjectListenerSupport
m_listeners = listeners;
}

/**
* Remove a project listener that wants to receive notification of listener events.
*
* @param listener the listener
*/
public void removeProjectListener( final ProjectListener listener )
{
int found = -1;
@@ -44,6 +59,11 @@ public class ProjectListenerSupport
m_listeners = listeners;
}

/**
* Fire a projectStarted event.
*
* @param projectName the projectName
*/
public void projectStarted( final String projectName )
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -52,6 +72,9 @@ public class ProjectListenerSupport
}
}

/**
* Fire a projectFinished event.
*/
public void projectFinished()
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -60,6 +83,11 @@ public class ProjectListenerSupport
}
}

/**
* Fire a targetStarted event.
*
* @param targetName the name of target
*/
public void targetStarted( String targetName )
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -68,6 +96,9 @@ public class ProjectListenerSupport
}
}

/**
* Fire a targetFinished event.
*/
public void targetFinished()
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -76,6 +107,11 @@ public class ProjectListenerSupport
}
}

/**
* Fire a targetStarted event.
*
* @param targetName the name of target
*/
public void taskletStarted( String taskletName )
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -84,6 +120,9 @@ public class ProjectListenerSupport
}
}

/**
* Fire a taskletFinished event.
*/
public void taskletFinished()
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -92,6 +131,11 @@ public class ProjectListenerSupport
}
}

/**
* Fire a log event.
*
* @param message the log message
*/
public void log( String message )
{
for( int i = 0; i < m_listeners.length; i++ )
@@ -100,6 +144,12 @@ public class ProjectListenerSupport
}
}

/**
* Fire a log event.
*
* @param message the log message
* @param throwable the throwable to be logged
*/
public void log( String message, Throwable throwable )
{
for( int i = 0; i < m_listeners.length; i++ )


+ 23
- 1
proposal/myrmidon/src/java/org/apache/ant/project/Target.java View File

@@ -8,14 +8,36 @@
package org.apache.ant.project;

import java.util.Iterator;
import org.apache.ant.util.Condition;
import org.apache.avalon.Component;
import org.apache.ant.datatypes.Condition;

/**
* Interface to represent targets in build file.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface Target
extends Component
{
/**
* Get dependencies of target
*
* @return the dependency list
*/
Iterator getDependencies();

/**
* Get tasks in target
*
* @return the target list
*/
Iterator getTasks();

/**
* Get condition under which target is executed.
*
* @return the condition for target or null
*/
Condition getCondition();
}



+ 2
- 22
proposal/myrmidon/src/java/org/apache/ant/tasklet/AbstractTasklet.java View File

@@ -8,9 +8,9 @@
package org.apache.ant.tasklet;

import org.apache.ant.AntException;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.Context;
import org.apache.avalon.Initializable;
import org.apache.log.Logger;

/**
* This is abstract base class for tasklets.
@@ -18,23 +18,13 @@ import org.apache.log.Logger;
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public abstract class AbstractTasklet
extends AbstractLoggable
implements Tasklet, Initializable
{
//the user should set this in constructors of sub-classes
protected JavaVersion m_requiredJavaVersion;

private TaskletContext m_context;
private Logger m_logger;

/**
* Receive logger from container.
*
* @param logger the logger
*/
public void setLogger( final Logger logger )
{
m_logger = logger;
}

/**
* Retrieve context from container.
@@ -79,14 +69,4 @@ public abstract class AbstractTasklet
{
return m_context;
}

/**
* Convenience method for subclass to get logger.
*
* @return the Logger
*/
protected Logger getLogger()
{
return m_logger;
}
}

+ 11
- 3
proposal/myrmidon/src/java/org/apache/ant/tasklet/DefaultTaskletContext.java View File

@@ -87,10 +87,10 @@ public class DefaultTaskletContext
* @param filename the filename to resolve
* @return the resolved filename
*/
public String resolveFilename( final String filename )
public File resolveFile( final String filename )
{
final File result = FileUtil.resolveFile( m_baseDirectory, filename );
if( null != result ) return result.toString();
if( null != result ) return result;
else return null;
}

@@ -106,7 +106,7 @@ public class DefaultTaskletContext
try { return PropertyUtil.resolveProperty( property, this, false ); }
catch( final PropertyException pe )
{
throw new AntException( "Error resolving " + property + " due to " +pe.getMessage(),
throw new AntException( "Error resolving " + property + " due to " + pe.getMessage(),
pe );
}
}
@@ -173,6 +173,14 @@ public class DefaultTaskletContext
}
}

/**
* put a value in context.
* This put method is overidden so new baseDirectory can be saved
* in member variable.
*
* @param key the key
* @param value the value
*/
public void put( final Object key, final Object value )
{
if( key.equals( BASE_DIRECTORY ) )


+ 1
- 1
proposal/myrmidon/src/java/org/apache/ant/tasklet/Tasklet.java View File

@@ -24,6 +24,6 @@ import org.apache.avalon.Loggable;
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface Tasklet
extends Component, Contextualizable, Runnable, Loggable
extends Component, Loggable, Contextualizable, Runnable
{
}

+ 2
- 2
proposal/myrmidon/src/java/org/apache/ant/tasklet/TaskletContext.java View File

@@ -60,9 +60,9 @@ public interface TaskletContext
* different volumes, file conventions etc)
*
* @param filename the filename to resolve
* @return the resolved filename
* @return the resolved file
*/
String resolveFilename( String filename );
File resolveFile( String filename );

/**
* Resolve property.


+ 58
- 132
proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletEngine.java View File

@@ -17,8 +17,11 @@ import org.apache.ant.convert.ConverterEngine;
import org.apache.ant.datatypes.DataTypeEngine;
import org.apache.ant.tasklet.Tasklet;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.avalon.AbstractLoggable;
import org.apache.avalon.Component;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.DefaultComponentManager;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.Context;
import org.apache.avalon.Contextualizable;
@@ -28,6 +31,7 @@ import org.apache.avalon.Initializable;
import org.apache.avalon.Loggable;
import org.apache.avalon.camelot.DefaultFactory;
import org.apache.avalon.camelot.DefaultLocatorRegistry;
import org.apache.avalon.camelot.Factory;
import org.apache.avalon.camelot.FactoryException;
import org.apache.avalon.camelot.Locator;
import org.apache.avalon.camelot.LocatorRegistry;
@@ -35,20 +39,17 @@ import org.apache.avalon.camelot.RegistryException;
import org.apache.log.Logger;

public class DefaultTaskletEngine
implements TaskletEngine, Initializable
extends AbstractLoggable
implements TaskletEngine, Composer
{
protected TskDeployer m_tskDeployer;
protected DefaultFactory m_factory;
protected LocatorRegistry m_locatorRegistry;
protected Factory m_factory;
protected LocatorRegistry m_locatorRegistry = new DefaultLocatorRegistry();
protected Configurer m_configurer;
protected Logger m_logger;
protected DataTypeEngine m_dataTypeEngine;
protected ConverterEngine m_converterEngine;

public void setLogger( final Logger logger )
{
m_logger = logger;
}
protected ComponentManager m_componentManager;

public TskDeployer getTskDeployer()
{
@@ -74,120 +75,74 @@ public class DefaultTaskletEngine
{
return m_dataTypeEngine;
}

public void init()
throws Exception
{
//converter must be created before configurerer
//so that it gets placed in configurers componentManager
m_converterEngine = createConverterEngine();
setupSubComponent( m_converterEngine );

m_configurer = createConfigurer();
setupSubComponent( m_configurer );

m_locatorRegistry = createLocatorRegistry();
m_factory = createFactory();
setupSubComponent( m_factory );

m_dataTypeEngine = createDataTypeEngine();
setupSubComponent( m_dataTypeEngine );


m_tskDeployer = createTskDeployer();
setupSubComponent( m_tskDeployer );
}
protected void setupSubComponent( final Component component )
throws Exception
{
if( component instanceof Loggable )
{
((Loggable)component).setLogger( m_logger );
}

if( component instanceof Composer )
{
final DefaultComponentManager componentManager = new DefaultComponentManager();
componentManager.put( "org.apache.ant.convert.Converter",
getConverterEngine() );
componentManager.put( "org.apache.ant.configuration.Configurer",
m_configurer );
componentManager.put( "org.apache.ant.tasklet.engine.TaskletEngine",
this );

((Composer)component).compose( componentManager );
}

if( component instanceof Initializable )
{
((Initializable)component).init();
}
}

protected DataTypeEngine createDataTypeEngine()
{
final TaskletDataTypeEngine engine = new TaskletDataTypeEngine();
engine.setFactory( m_factory );
return engine;
}
protected TskDeployer createTskDeployer()
/**
* Retrieve relevent services needed to deploy.
*
* @param componentManager the ComponentManager
* @exception ComponentManagerException if an error occurs
*/
public void compose( final ComponentManager componentManager )
throws ComponentManagerException
{
return new DefaultTskDeployer();
}
//cache CM so it can be used while executing tasks
m_componentManager = componentManager;

protected Configurer createConfigurer()
{
return new DefaultConfigurer();
}
protected LocatorRegistry createLocatorRegistry()
{
return new DefaultLocatorRegistry();
}
protected DefaultFactory createFactory()
{
return new DefaultFactory();
}
protected ConverterEngine createConverterEngine()
{
//this is done so that the loaders are shared
//which results in much less overhead
final TaskletConverterEngine engine = new TaskletConverterEngine();
engine.setFactory( m_factory );
return engine;
m_factory = (Factory)componentManager.lookup( "org.apache.avalon.camelot.Factory" );
m_tskDeployer =
(TskDeployer)componentManager.lookup( "org.apache.ant.tasklet.engine.TskDeployer" );
m_configurer =
(Configurer)componentManager.lookup( "org.apache.ant.configuration.Configurer" );
m_dataTypeEngine =
(DataTypeEngine)componentManager.lookup( "org.apache.ant.datatypes.DataTypeEngine" );
m_converterEngine =
(ConverterEngine)componentManager.lookup( "org.apache.ant.convert.ConverterEngine" );
}

public void execute( final Configuration task,
final TaskletContext context,
final ComponentManager componentManager )
final TaskletContext context )
throws AntException
{
m_logger.debug( "Creating" );
getLogger().debug( "Creating" );
final Tasklet tasklet = createTasklet( task.getName() );
tasklet.setLogger( m_logger );
setupLogger( tasklet );

m_logger.debug( "Contextualizing" );
getLogger().debug( "Contextualizing" );
doContextualize( tasklet, task, context );

m_logger.debug( "Composing" );
doCompose( tasklet, task, componentManager );
getLogger().debug( "Composing" );
doCompose( tasklet, task );

m_logger.debug( "Configuring" );
getLogger().debug( "Configuring" );
doConfigure( tasklet, task, context );

m_logger.debug( "Initializing" );
getLogger().debug( "Initializing" );
doInitialize( tasklet, task );

m_logger.debug( "Running" );
getLogger().debug( "Running" );
tasklet.run();

m_logger.debug( "Disposing" );
getLogger().debug( "Disposing" );
doDispose( tasklet, task );
}
protected Tasklet createTasklet( final String name )
throws AntException
{
try
{
final Locator locator = m_locatorRegistry.getLocator( name );
return (Tasklet)m_factory.create( locator, Tasklet.class );
}
catch( final RegistryException re )
{
throw new AntException( "Unable to locate task " + name, re );
}
catch( final FactoryException fe )
{
throw new AntException( "Unable to create task " + name, fe );
}
}

protected void doConfigure( final Tasklet tasklet,
final Configuration task,
@@ -203,20 +158,12 @@ public class DefaultTaskletEngine
}
}
protected void doCompose( final Tasklet tasklet,
final Configuration task,
final ComponentManager componentManager )
protected void doCompose( final Tasklet tasklet, final Configuration task )
throws AntException
{

final DefaultComponentManager subComponentManager =
new DefaultComponentManager( componentManager );

subComponentManager.put( "org.apache.ant.configuration.Configurer", m_configurer );

if( tasklet instanceof Composer )
{
try { ((Composer)tasklet).compose( subComponentManager ); }
try { ((Composer)tasklet).compose( m_componentManager ); }
catch( final Throwable throwable )
{
throw new AntException( "Error composing task " + task.getName() + " at " +
@@ -231,9 +178,6 @@ public class DefaultTaskletEngine
final TaskletContext context )
throws AntException
{
// Already done in container ...
//context.setProperty( TaskletContext.NAME, name );

try { tasklet.contextualize( context ); }
catch( final Throwable throwable )
{
@@ -272,22 +216,4 @@ public class DefaultTaskletEngine
}
}
}

protected Tasklet createTasklet( final String name )
throws AntException
{
try
{
final Locator locator = m_locatorRegistry.getLocator( name );
return (Tasklet)m_factory.create( locator, Tasklet.class );
}
catch( final RegistryException re )
{
throw new AntException( "Unable to locate task " + name, re );
}
catch( final FactoryException fe )
{
throw new AntException( "Unable to create task " + name, fe );
}
}
}

+ 21
- 21
proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTskDeployer.java View File

@@ -15,13 +15,13 @@ import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.apache.ant.datatypes.DataTypeEngine;
import org.apache.ant.convert.ConverterEngine;
import org.apache.ant.convert.ConverterRegistry;
import org.apache.ant.convert.DefaultConverterInfo;
import org.apache.avalon.Component;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.Configuration;
import org.apache.avalon.ConfigurationException;
@@ -29,6 +29,7 @@ import org.apache.avalon.camelot.AbstractZipDeployer;
import org.apache.avalon.camelot.DefaultLocator;
import org.apache.avalon.camelot.DefaultLocatorRegistry;
import org.apache.avalon.camelot.DeploymentException;
import org.apache.avalon.camelot.DeployerUtil;
import org.apache.avalon.camelot.Loader;
import org.apache.avalon.camelot.LocatorRegistry;
import org.apache.avalon.camelot.RegistryException;
@@ -55,7 +56,7 @@ public class DefaultTskDeployer
*/
public DefaultTskDeployer()
{
super( false );
super();
m_autoUndeploy = true;
m_type = "Tasklet";
}
@@ -64,34 +65,32 @@ public class DefaultTskDeployer
* Retrieve relevent services needed to deploy.
*
* @param componentManager the ComponentManager
* @exception ComponentNotFoundException if an error occurs
* @exception ComponentNotAccessibleException if an error occurs
* @exception ComponentManagerException if an error occurs
*/
public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
final TaskletEngine taskletEngine = (TaskletEngine)componentManager.
lookup( "org.apache.ant.tasklet.engine.TaskletEngine" );

final ConverterEngine converterEngine = taskletEngine.getConverterEngine();
m_taskletRegistry = taskletEngine.getRegistry();

final ConverterEngine converterEngine = (ConverterEngine)componentManager.
lookup( "org.apache.ant.convert.ConverterEngine" );

m_converterInfoRegistry = converterEngine.getInfoRegistry();
m_converterRegistry = converterEngine.getRegistry();

m_taskletRegistry = taskletEngine.getRegistry();
final DataTypeEngine dataTypeEngine = (DataTypeEngine)componentManager.
lookup( "org.apache.ant.datatypes.DataTypeEngine" );
m_dataTypeRegistry = taskletEngine.getDataTypeEngine().getRegistry();
}

public void setLogger( final Logger logger )
{
m_logger = logger;
m_dataTypeRegistry = dataTypeEngine.getRegistry();
}

protected void loadResources( final ZipFile zipFile, final String location, final URL url )
throws DeploymentException
{
final Configuration taskdefs = loadConfiguration( zipFile, TSKDEF_FILE );
final Configuration taskdefs = DeployerUtil.loadConfiguration( zipFile, TSKDEF_FILE );

try
{
@@ -126,8 +125,8 @@ public class DefaultTskDeployer
throws DeploymentException
{
checkDeployment( location, url );
final ZipFile zipFile = getZipFileFor( url );
final Configuration taskdefs = loadConfiguration( zipFile, TSKDEF_FILE );
final ZipFile zipFile = DeployerUtil.getZipFileFor( getFileFor( url ) );
final Configuration taskdefs = DeployerUtil.loadConfiguration( zipFile, TSKDEF_FILE );
try
{
@@ -152,8 +151,9 @@ public class DefaultTskDeployer
throws DeploymentException
{
checkDeployment( location, url );
final ZipFile zipFile = getZipFileFor( url );
final Configuration datatypedefs = loadConfiguration( zipFile, TSKDEF_FILE );
final ZipFile zipFile = DeployerUtil.getZipFileFor( getFileFor( url ) );
final Configuration datatypedefs =
DeployerUtil.loadConfiguration( zipFile, TSKDEF_FILE );
try
{
@@ -178,8 +178,8 @@ public class DefaultTskDeployer
throws DeploymentException
{
checkDeployment( location, url );
final ZipFile zipFile = getZipFileFor( url );
final Configuration taskdefs = loadConfiguration( zipFile, TSKDEF_FILE );
final ZipFile zipFile = DeployerUtil.getZipFileFor( getFileFor( url ) );
final Configuration taskdefs = DeployerUtil.loadConfiguration( zipFile, TSKDEF_FILE );
try
{


+ 0
- 29
proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletConverterEngine.java View File

@@ -1,29 +0,0 @@
/*
* 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 file.
*/
package org.apache.ant.tasklet.engine;

import org.apache.ant.convert.DefaultConverterEngine;
import org.apache.avalon.camelot.DefaultFactory;

public class TaskletConverterEngine
extends DefaultConverterEngine
{
/**
* Set the ConverterFactory.
* Package access intended.
*/
void setFactory( final DefaultFactory factory )
{
m_factory = factory;
}

protected DefaultFactory createFactory()
{
return m_factory;
}
}

+ 0
- 29
proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletDataTypeEngine.java View File

@@ -1,29 +0,0 @@
/*
* 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 file.
*/
package org.apache.ant.tasklet.engine;

import org.apache.ant.datatypes.DefaultDataTypeEngine;
import org.apache.avalon.camelot.DefaultFactory;

public class TaskletDataTypeEngine
extends DefaultDataTypeEngine
{
/**
* Set the DataTypeFactory.
* Package access intended.
*/
void setFactory( final DefaultFactory factory )
{
m_factory = factory;
}

protected DefaultFactory createFactory()
{
return m_factory;
}
}

+ 2
- 4
proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEngine.java View File

@@ -24,7 +24,7 @@ import org.apache.log.Logger;
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public interface TaskletEngine
extends Component, Loggable
extends Component
{
/**
* Retrieve deployer for engine.
@@ -60,8 +60,6 @@ public interface TaskletEngine
* @param task the configruation data for task
* @exception AntException if an error occurs
*/
void execute( Configuration task,
TaskletContext context,
ComponentManager componentManager )
void execute( Configuration task, TaskletContext context )
throws AntException;
}

+ 3
- 4
proposal/myrmidon/src/java/org/apache/ant/tasks/core/AbstractResourceRegisterer.java View File

@@ -14,8 +14,7 @@ import org.apache.ant.AntException;
import org.apache.ant.tasklet.AbstractTasklet;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.camelot.RegistryException;

@@ -34,7 +33,7 @@ public abstract class AbstractResourceRegisterer
protected TaskletEngine m_engine;
public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
m_engine = (TaskletEngine)componentManager.
lookup( "org.apache.ant.tasklet.engine.TaskletEngine" );
@@ -84,7 +83,7 @@ public abstract class AbstractResourceRegisterer
{
if( null != libName )
{
final File lib = new File( getContext().resolveFilename( libName ) );
final File lib = getContext().resolveFile( libName );
try { return lib.toURL(); }
catch( final MalformedURLException mue )
{


+ 2
- 3
proposal/myrmidon/src/java/org/apache/ant/tasks/core/AntCall.java View File

@@ -16,8 +16,7 @@ import org.apache.ant.tasklet.DefaultTaskletContext;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.Context;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;

/**
@@ -43,7 +42,7 @@ public class AntCall
}

public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
m_componentManager = componentManager;
m_projectEngine = (ProjectEngine)componentManager.


+ 13
- 10
proposal/myrmidon/src/java/org/apache/ant/tasks/core/Property.java View File

@@ -19,8 +19,7 @@ import org.apache.ant.tasklet.AbstractTasklet;
import org.apache.ant.tasklet.TaskletContext;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.ConfigurationException;
import org.apache.avalon.Resolvable;
@@ -40,16 +39,15 @@ public class Property
protected Configurer m_configurer;
public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
m_configurer = (Configurer)componentManager.
lookup( "org.apache.ant.configuration.Configurer" );
final TaskletEngine taskletEngine = (TaskletEngine)componentManager.
lookup( "org.apache.ant.tasklet.engine.TaskletEngine" );

m_engine = taskletEngine.getDataTypeEngine();
m_converter = taskletEngine.getConverterEngine();
m_engine = (DataTypeEngine)componentManager.
lookup( "org.apache.ant.datatypes.DataTypeEngine" );

m_converter = (Converter)componentManager.lookup( "org.apache.ant.convert.Converter" );
}

public void configure( final Configuration configuration )
@@ -71,7 +69,12 @@ public class Property

if( name.equals( "name" ) )
{
try { setName( (String)m_converter.convert( String.class, object ) ); }
try
{
final String convertedValue =
(String)m_converter.convert( String.class, object, getContext() );
setName( convertedValue );
}
catch( final Exception e )
{
throw new ConfigurationException( "Error converting value", e );
@@ -86,7 +89,7 @@ public class Property
try
{
final Boolean localScope =
(Boolean)m_converter.convert( Boolean.class, object );
(Boolean)m_converter.convert( Boolean.class, object, getContext() );
setLocalScope( Boolean.TRUE == localScope );
}
catch( final Exception e )


+ 4
- 5
proposal/myrmidon/src/java/org/apache/ant/tasks/core/RegisterConverter.java View File

@@ -17,8 +17,7 @@ import org.apache.ant.convert.DefaultConverterInfo;
import org.apache.ant.tasklet.AbstractTasklet;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.camelot.DeploymentException;
import org.apache.avalon.camelot.RegistryException;
@@ -39,7 +38,7 @@ public class RegisterConverter
protected TaskletEngine m_engine;
public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
m_engine = (TaskletEngine)componentManager.
lookup( "org.apache.ant.tasklet.engine.TaskletEngine" );
@@ -90,7 +89,7 @@ public class RegisterConverter
if( !isFullyDefined && null == url )
{
throw new AntException( "Must supply parameter if not fully specifying converter" );
}
}

if( !isFullyDefined )
{
@@ -126,7 +125,7 @@ public class RegisterConverter
{
if( null != libName )
{
final File lib = new File( getContext().resolveFilename( libName ) );
final File lib = getContext().resolveFile( libName );
try { return lib.toURL(); }
catch( final MalformedURLException mue )
{


+ 3
- 4
proposal/myrmidon/src/java/org/apache/ant/tasks/core/RegisterTasklib.java View File

@@ -14,8 +14,7 @@ import org.apache.ant.AntException;
import org.apache.ant.tasklet.AbstractTasklet;
import org.apache.ant.tasklet.engine.TaskletEngine;
import org.apache.avalon.ComponentManager;
import org.apache.avalon.ComponentNotAccessibleException;
import org.apache.avalon.ComponentNotFoundException;
import org.apache.avalon.ComponentManagerException;
import org.apache.avalon.Composer;
import org.apache.avalon.camelot.DeploymentException;

@@ -32,7 +31,7 @@ public class RegisterTasklib
protected TaskletEngine m_engine;
public void compose( final ComponentManager componentManager )
throws ComponentNotFoundException, ComponentNotAccessibleException
throws ComponentManagerException
{
m_engine = (TaskletEngine)componentManager.
lookup( "org.apache.ant.tasklet.engine.TaskletEngine" );
@@ -53,7 +52,7 @@ public class RegisterTasklib
URL url = null;

final File lib = new File( getContext().resolveFilename( m_lib ) );
final File lib = getContext().resolveFile( m_lib );
try { url = lib.toURL(); }
catch( final MalformedURLException mue )
{


proposal/myrmidon/src/java/org/apache/ant/datatypes/Condition.java → proposal/myrmidon/src/java/org/apache/ant/util/Condition.java View File

@@ -5,7 +5,7 @@
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.ant.datatypes;
package org.apache.ant.util;

import org.apache.ant.AntException;
import org.apache.avalon.Component;

+ 2
- 2
proposal/myrmidon/src/script/ant View File

@@ -25,7 +25,7 @@ while [ -h "$PRG" ] ; do
fi
done
MYRMIDON_HOME=`dirname "$PRG"`/..
ANT_HOME=`dirname "$PRG"`/..

if [ "$JAVA_HOME" == "" ] ; then

@@ -42,4 +42,4 @@ else
fi
fi

$JAVACMD $ANT_OPTS -jar ant.jar --ant-home=${MYRMIDON_HOME} $@
$JAVACMD $ANT_OPTS -jar $ANT_HOME/lib/ant.jar $@

+ 25
- 4
proposal/myrmidon/src/script/ant.bat View File

@@ -2,6 +2,30 @@

if exist "%HOME%\antrc_pre.bat" call "%HOME%\antrc_pre.bat"

if not "%OS%"=="Windows_NT" goto start

rem %~dp0 is name of current script under NT
set DEFAULT_ANT_HOME=%~dp0

rem : operator works similar to make : operator
set DEFAULT_ANT_HOME=%DEFAULT_ANT_HOME:\bin\=%

if "%ANT_HOME%"=="" set ANT_HOME=%DEFAULT_ANT_HOME%
set DEFAULT_ANT_HOME=

:start

if not "%ANT_HOME%" == "" goto ant_home_found

echo.
echo Warning: ANT_HOME environment variable is not set.
echo This needs to be set for Win9x as it's command prompt
echo scripting bites
echo.
goto end

:ant_home_found

if not "%JAVA_HOME%" == "" goto javaCmdSetup

echo.
@@ -10,7 +34,6 @@ echo If build fails because sun.* classes could not be found
echo you will need to set the JAVA_HOME environment variable
echo to the installation directory of java.
echo.
goto end

rem hope that there is java command in path
if "%JAVACMD%" == "" set JAVACMD=java
@@ -22,7 +45,6 @@ if "%JAVACMD%" == "" set JAVACMD=%JAVA_HOME%\bin\java

:argSetup

set THIS_FILE=%0
set ANT_CMD_LINE_ARGS=

rem Slurp all args...
@@ -35,9 +57,8 @@ goto setupArgs
:doneArgs
rem Mmmmmm tasty - finished slurping args

%JAVACMD% %ANT_OPTS% -jar lib\ant.jar "--bin-dir=%THIS_FILE%" %ANT_CMD_LINE_ARGS%
%JAVACMD% %ANT_OPTS% -jar %ANT_HOME%\lib\ant.jar %ANT_CMD_LINE_ARGS%

:end
if exist "%HOME%\antrc_post.bat" call "%HOME%\antrc_post.bat"
set THIS_FILE=
set ANT_CMD_LINE_ARGS=

+ 224
- 0
proposal/myrmidon/src/xdocs/design.html View File

@@ -0,0 +1,224 @@

<html>
<head>
<title>Myrmidon: The Ant2.0 Proposal</title>
</head>
<body BGCOLOR="#ffffff">

<center>
<h1>Myrmidon: The Ant2.0 Proposal</h1>
<i>by Peter Donald <a href="mailto:donaldp@apache.org">&lt;donaldp@apache.org&gt;</a></i>
</center>

<br />

<div align="center">
<table border="0" width="60%">
<tr>
<td width="100%">
<i>Myrmidon is a proposal for <a href="http://jakarta.apache.org/ant">Ant</a> 2.0, a
java based build tool. Unlike other proposals it was specifically designed as
both a tool a an API library that can be reused in other domains.</i>
</td>
</tr>
</table>
</div>

<br />

<h3>To do and what not to do</h3>

<blockquote>
<p>
There is a number of issues that this proposal addresses and a number of issues that
have been deliberately elided. The focus is currently at the lower levels - namely
the task execution engine, the notion of contexts/scopes, loading of tasklets,
datatypes and converters etc. While it does implement a Project engine API is still
being discussed on ant-dev and this proposal just adopts Ant1.x's model until a better
understanding is gained of what is required.
</p>

<p>
Neither this document nor the proposal is intended to be a vision statement. Rather it
is a description of how it could be implemented based on commonly accepted needs
requested on ant lists and discussed by ant-dev. The vision statement is more
strongly associated with the Project API and extentions (CJAN, import project trees,
preprocessing via xslt/css/whatever, templating etc). And thus is not addressed here.
</p>
</blockquote>

<h3>The Prime Directive: Execute tasks</h3>

<blockquote>
<p>
One of the primary concerns of ant is providing a task execution environment (TEE).
The TEE provides a number of services to tasks. The TEE manages the lifecycle of
the tasks. This includes providing the tasks with a logger instance, context
information and access to peer components. The lifecycle also involves executing
init(), run() and dispose() methods at appropriate times.
</p>

<p>
Instead of reinventing the wheel this proposal instead reuses the Avalon framework
that already provides facilities for many of the concepts required. It already has
interfaces/classes to model concepts of context, logger, containers etc.
</p>
<p>
One of the requirements identified was the need for dynamic interpretation and
instantiation of tasks. To implement this there needs to be an abstraction layer
between task object instances and the objects that are manipulated by projects
and tools outside tasklet API. This abstraction has the same requirements as
Configuration objects in Avalon and thus the task proxies are represented by
Avalons Configuration object.
</p>
</blockquote>

<h3>SOC, IOC and the alphabet soup</h3>

<blockquote>
<p>
The design of Myrmidon follows many of the design patterns found in Avalon. The strongest
influence cna be seen from the meta-patterns; Separation of Concerns (SOC) and Inversion of
Control (IOC).
</p>

<p>
SOC essentially is a design pattern used to separate the system accroding to relevent
dimensions. (SOC is often called multi-dimensional SOC). The definition of "relevent"
is domain specific and in our case there is a number of dimensions. For instance you
will notice that there is a separation between project, tasklet, conversion and datatype
functionality. Where in Ant1.x these were only partially separated or tightly coupled
there is now decoupling. This separation allows easy reuse of parts in other projects. ie
It is now extremely easy to reuse the tasklet api in other tools (such as Installshield
type apps or Cron-like deamons etc).
</p>

<p>
Another dimension in which myrmidon is separated is by users. For instance there is
a separation between engine code and client code. The client code is the code used by
those who implement the components. For instance tasklet developers only have to
look at client code for tasklets and never look at implementation of engine.
</p>

<p>
Inversion of Control (IOC) aka the Holywood Principle (Don't call us - we'll call you) is
another pattern applied within Myrmidon. In this pattern it is the container that provides
facilities and executes lifecycle by calling methods of child components. So instead of the
component calling methods to lookup or create peer components or method managing it's
own lifecycle the container is responsible for these functions.
</p>

<p>
These approach should be familiar to a servlet or EJB developer as they are also based on
SOC and IOC except they do it at a lower resolution. For more detailed explanation of
these design approaches have a look at <a
href="http://java.apache.org/framework/developer/index.html">
http://java.apache.org/framework/developer/index.html</a>.
</p>

<p>
The result of these design choices is a more flexable and reusable components.
</p>
</blockquote>

<h3>Enough theory - give me Nuts and Bolts</h3>

<blockquote>
<p>
The code is separated into 5 different sections. These are the project, tastlet,
converter, datatype and frontend APIs. The project API is concerned with building
and representing a project. The tasklet API is concerned with executing tasks in a
particular environment. The converter API is concerned with converting instances of one
type into another type. The datatype API is used to register, load and instantiate
instances of named datatypes. The frontend API involves instantiating and managing
all the other components and making it easy to build different frontends (CLI, GUI,
Servlet).
</p>

<p>
When Myrmidon is started it interacts with FrontEnd API. It aquires a ProjectBuilder
instance from FrontEnd API and uses it to build a project. It then aquires a
ProjectEngine instance from FrontEnd again and uses it to execute the created project.
This project will first execute the implicit target (which includes all of properties
outside target element). And then execute the default or specified target. Each target
executes it's dependencies first and then checks it's condition to see if it should
execute itself. Each target contains a list of tasks (in the form of Configuraiton
objects). These are passed to the tasklet API that instantiates and executes the tasks.
The tasklet API instantiates the relevent task and then applies rules to use the
Configuration object to configure the task. In some cases this involves resolving
properties and converting values to the correct type required by task. The convertion
is done by Converter API. Properties are associations between a name and a value, the
types of the value aremanaged by the DataType API and accessed via the Property task.
</p>

<p>
Now if you wanted to change a certain component of the system - lets say the ProjectBuilder
component. You instead want to use a component that you wrote yourself that builds a project
with the result of a xslt + xml -> xml process so that you can use static templating. The
way to do this would be to set the property "ant.comp.builder" to
"com.biz.ant.MyXSLTProjectBuilder" before handing the properties to the FrontEnd API. The
FrontEnd API would then wire together the components appropriately and the same process as
documented above would be used. Other components can be replaced in a similar manner. For
a full list of properties that can be set see the default FrontEnd implementation.
</p>

<p>
Now instead of replacing a component in the system say you wanted to add an extra task. In
this case you would create a task "com.biz.ant.tasks.ProcessFile" that extends
"org.apache.ant.tasklet.AbstractTasklet". You would then implement run() method to do the
work and and setter methods to accept parameters. The run method can throw AntException if
the task fails for any reason. The setter methods are in format of Ant1.x setters with one
extention. The extention allows '-' characters to appear in xml names and these will be
transferred into capitalisation of next character in java names. ie file-permission
attribute --&gt; setFilePermission() method. After implementing this task you would have
to define it in taskdef.xml of it's archive or else define it with a taskdef construct.
</p>
<p>
In a similar method new converters and datatypes can be added to the system. For example
if you needed to add a TestSet datatype that held a list of test names then this would
be possible. You could also add a converter that converted a list of comma separated
strings into a TestSet.
</p>

<p>
The one thing that this proposal does not address is validation concerns. You will notice
that the above is mainly aimed to reduce the complexity for task developers. Where in 1.x
you had to manage convertion manually (depending on version of Ant) and also had to explcitly
incorporate support for datatypes manually. The one other concern that was coded into every
task was validation. ie Were the correct parameters set ? It would be desirable to be able to
associate meta-information with the task that indicated the required parameters. This would
reduce the workload on task developers even more and encourage better task structure. This
is a future TODO.
</p>

</blockquote>

<h3>A Rose by any other name ...</h3>

<blockquote>
<p>
The name Myrmidon is a derivation of a mythological name for some anst that were turned
into soldiers by the god Zeus. It came to mean "a subordinate who executes orders
unquestioningly" which seemed suitable for a task execution/build tool. A more complete
description stolen from <a href="http://bondi-blue.parlez.com/previous_words/myrmidon.txt">
http://bondi-blue.parlez.com/previous_words/myrmidon.txt</a>.
</p>

<quote>
<i>The appellation Myrmidon was derived from the Greek word "myrmex",
meaning ant. According to Greek mythology, the Myrmidons were
transformed into humans by the god Zeus as an act of kindness to his
son Aeacus. King Aeacus, captivated by a colony of ants, prayed
that he should receive an increase in population equal to the
number of ants before him. When he awoke the next day, the ants
were his human subjects. Thereafter, they were known as the
Myrmidons. See "The Iliad" for Homers' account of the Myrmidons
during the Trojan War.</i>
</quote>

</blockquote>

</body>
</html>

proposal/myrmidon/bin/ant → proposal/myrmidon/tools/bin/ant View File

@@ -40,7 +40,7 @@ fi
LOCALCLASSPATH=`echo $ANT_HOME/lib/*.jar | tr ' ' ':'`

if [ "$CLASSPATH" != "" ] ; then
LOCALCLASSPATH=$CLASSPATH:$LOCALCLASSPATH
LOCALCLASSPATH=$LOCALCLASSPATH:$CLASSPATH
fi

if [ "$JAVA_HOME" != "" ] ; then

proposal/myrmidon/bin/ant.bat → proposal/myrmidon/tools/bin/ant.bat View File

@@ -1,4 +1,4 @@
rem @echo off
@echo off
rem find ANT_HOME
if not "%ANT_HOME%"=="" goto checkJava


proposal/myrmidon/bin/antRun → proposal/myrmidon/tools/bin/antRun View File


proposal/myrmidon/bin/antRun.bat → proposal/myrmidon/tools/bin/antRun.bat View File

@@ -2,7 +2,7 @@

cd %1
set ANT_RUN_CMD=%2
shift
shift
shift

%ANT_RUN_CMD% %1 %2 %3 %4 %5 %6 %7 %8 %9

proposal/myrmidon/bin/fixPath.awk → proposal/myrmidon/tools/bin/fixPath.awk View File


proposal/myrmidon/bin/lcp.bat → proposal/myrmidon/tools/bin/lcp.bat View File

@@ -1 +1,2 @@
set LOCALCLASSPATH=%LOCALCLASSPATH%;%1


BIN
proposal/myrmidon/tools/lib/ant.jar View File


Loading…
Cancel
Save