diff --git a/proposal/myrmidon/.ant.properties b/proposal/myrmidon/.ant.properties new file mode 100644 index 000000000..a1e728061 --- /dev/null +++ b/proposal/myrmidon/.ant.properties @@ -0,0 +1 @@ +build.compiler=jikes \ No newline at end of file diff --git a/proposal/myrmidon/build.bat b/proposal/myrmidon/build.bat new file mode 100755 index 000000000..ce02ad3f1 --- /dev/null +++ b/proposal/myrmidon/build.bat @@ -0,0 +1,16 @@ +@echo off + +echo. +echo Ant Build System +echo ---------------- + +set ANT_HOME=. + +set CLASSPATH= + +%ANT_HOME%\bin\ant.bat -emacs %1 %2 %3 %4 %5 %6 %7 %8 +goto cleanup + +:cleanup +set ANT_HOME= +set CLASSPATH= diff --git a/proposal/myrmidon/build.sh b/proposal/myrmidon/build.sh new file mode 100644 index 000000000..00b3cbf1c --- /dev/null +++ b/proposal/myrmidon/build.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +echo +echo "Ant Build System" +echo "----------------" + +chmod u+x $PWD/bin/antRun +chmod u+x $PWD/bin/ant +#export ANT_OPTS="-Djava.compiler=" + +$PWD/bin/ant -emacs $@ | awk -f $PWD/bin/fixPath.awk diff --git a/proposal/myrmidon/build.xml b/proposal/myrmidon/build.xml new file mode 100644 index 000000000..f90cffa37 --- /dev/null +++ b/proposal/myrmidon/build.xml @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proposal/myrmidon/emacs-jprj.el b/proposal/myrmidon/emacs-jprj.el new file mode 100644 index 000000000..ddf0be918 --- /dev/null +++ b/proposal/myrmidon/emacs-jprj.el @@ -0,0 +1,7 @@ +(setq jprj-base-path (message "%s/" (expand-file-name (substitute-in-file-name "."))) ) +(setq jprj-src-path (message "%ssrc/java/" jprj-base-path) ) +(setq jprj-compile-command "./build.bat") +(setq jprj-run-command "./build.bat&");; cd dist; bin/ant.bat -f ../src/make/sample.xmk&") +;(setq tab-expansion-size 4) + +(load "update-prj") diff --git a/proposal/myrmidon/lib/ant.jar b/proposal/myrmidon/lib/ant.jar new file mode 100644 index 000000000..f74662db3 Binary files /dev/null and b/proposal/myrmidon/lib/ant.jar differ diff --git a/proposal/myrmidon/lib/avalonapi.jar b/proposal/myrmidon/lib/avalonapi.jar new file mode 100644 index 000000000..1238e40f0 Binary files /dev/null and b/proposal/myrmidon/lib/avalonapi.jar differ diff --git a/proposal/myrmidon/lib/xerces.jar b/proposal/myrmidon/lib/xerces.jar new file mode 100644 index 000000000..f4708953a Binary files /dev/null and b/proposal/myrmidon/lib/xerces.jar differ diff --git a/proposal/myrmidon/src/java/org/apache/ant/AntContextResources.java b/proposal/myrmidon/src/java/org/apache/ant/AntContextResources.java new file mode 100644 index 000000000..fff46f0c9 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/AntContextResources.java @@ -0,0 +1,29 @@ +/* + * 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; + +public interface AntContextResources +{ + // the directory of ant + String HOME_DIR = "ant.install.dir"; + + // the bin directory of ant + String BIN_DIR = "ant.install.bin"; + + // the lib directory of ant + String LIB_DIR = "ant.install.lib"; + + // the tasklib directory of ant + String TASKLIB_DIR = "ant.install.task-lib"; + + // the directory to look for per user ant information + String USER_DIR = "ant.user.dir"; + + // the directory to look for per project ant information + String PROJECT_DIR = "ant.project.dir"; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/AntException.java b/proposal/myrmidon/src/java/org/apache/ant/AntException.java new file mode 100644 index 000000000..846b52c35 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/AntException.java @@ -0,0 +1,25 @@ +/* + * 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 org.apache.avalon.CascadingRuntimeException; + +public class AntException + extends CascadingRuntimeException +{ + public AntException( final String message ) + { + this( message, null ); + } + + public AntException( final String message, final Throwable throwable ) + { + super( message, throwable ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/Main.java b/proposal/myrmidon/src/java/org/apache/ant/Main.java new file mode 100644 index 000000000..f474e65d6 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/Main.java @@ -0,0 +1,797 @@ +/* + * 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.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +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.List; +import java.util.Iterator; +import org.apache.ant.project.DefaultProjectEngine; +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.tasklet.JavaVersion; +import org.apache.ant.tasklet.TaskletContext; +import org.apache.avalon.Disposable; +import org.apache.avalon.Initializable; +import org.apache.avalon.camelot.Deployer; +import org.apache.avalon.camelot.DeploymentException; +import org.apache.avalon.util.StringUtil; +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; +import org.apache.log.Priority; + +/** + * The class to kick the tires and light the fires. + * Starts ant, loads ProjectBuilder, builds project then uses ProjectEngine + * to run project. + * + * @author Peter Donald + */ +public class Main + extends AbstractMain +{ + public final static String BUILD_DATE = "@@DATE@@"; + public final static String BUILD_VERSION = "@@VERSION@@"; + public final static String VERSION = + "Ant " + BUILD_VERSION + " compiled on " + BUILD_DATE; + + protected final static String DEFAULT_LOGLEVEL = "INFO"; + protected final static String DEFAULT_LIB_DIRECTORY = ".." + File.separator + "lib"; + protected final static String DEFAULT_TASKLIB_DIRECTORY = DEFAULT_LIB_DIRECTORY; + protected final static String DEFAULT_FILENAME = "build.xmk"; + protected final static String DEFAULT_LISTENER = + "org.apache.ant.project.DefaultProjectListener"; + + protected final static String DEFAULT_BUILDER = + "org.apache.ant.project.DefaultProjectBuilder"; + + private static final int HELP_OPT = 'h'; + private static final int QUIET_OPT = 'q'; + private static final int VERBOSE_OPT = 'v'; + private static final int FILE_OPT = 'f'; + private static final int LOG_LEVEL_OPT = 'l'; + 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; + + //incompatable options for info options + private static final int INFO_OPT_INCOMPAT[] = new int[] + { + 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 + }; + + //incompatable options for other logging options + private static final int LOG_OPT_INCOMPAT[] = new int[] + { + QUIET_OPT, VERBOSE_OPT, LOG_LEVEL_OPT + }; + + protected Logger m_logger; + + protected File m_binDir; + protected File m_homeDir; + protected File m_libDir; + protected File m_taskLibDir; + protected File m_buildFile; + protected File m_userDir; + + public static void main( final String args[] ) + { + final Main main = new Main(); + + try { main.execute( args ); } + catch( final AntException ae ) + { + main.m_logger.error( "Error: " + ae.getMessage() ); + main.m_logger.debug( "Exception..." + StringUtil.printStackTrace( ae ) ); + } + catch( final Throwable throwable ) + { + main.m_logger.error( "Error: " + throwable ); + main.m_logger.debug( "Exception..." + StringUtil.printStackTrace( throwable ) ); + } + } + + /** + * Initialise the options for command line parser. + */ + protected CLOptionDescriptor[] createCLOptions() + { + //TODO: localise + final CLOptionDescriptor options[] = new CLOptionDescriptor[ 13 ]; + + options[0] = + new CLOptionDescriptor( "help", + CLOptionDescriptor.ARGUMENT_DISALLOWED, + HELP_OPT, + "display this help message", + INFO_OPT_INCOMPAT ); + + options[1] = + new CLOptionDescriptor( "file", + CLOptionDescriptor.ARGUMENT_REQUIRED, + FILE_OPT, + "the build file." ); + + options[2] = + new CLOptionDescriptor( "log-level", + CLOptionDescriptor.ARGUMENT_REQUIRED, + LOG_LEVEL_OPT, + "the verbosity level at which to log messages. " + + "(DEBUG|INFO|WARN|ERROR|FATAL_ERROR)", + LOG_OPT_INCOMPAT ); + + options[3] = + new CLOptionDescriptor( "quiet", + CLOptionDescriptor.ARGUMENT_DISALLOWED, + QUIET_OPT, + "equivelent to --log-level=FATAL_ERROR", + LOG_OPT_INCOMPAT ); + + options[4] = + new CLOptionDescriptor( "verbose", + CLOptionDescriptor.ARGUMENT_DISALLOWED, + VERBOSE_OPT, + "equivelent to --log-level=INFO", + LOG_OPT_INCOMPAT ); + + options[5] = + new CLOptionDescriptor( "listener", + CLOptionDescriptor.ARGUMENT_REQUIRED, + LISTENER_OPT, + "the listener for log events." ); + + options[6] = + new CLOptionDescriptor( "version", + CLOptionDescriptor.ARGUMENT_DISALLOWED, + VERSION_OPT, + "display version", + 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] = + new CLOptionDescriptor( "incremental", + CLOptionDescriptor.ARGUMENT_DISALLOWED, + INCREMENTAL_OPT, + "Run in incremental mode" ); + options[11] = + new CLOptionDescriptor( "ant-home", + CLOptionDescriptor.ARGUMENT_REQUIRED, + HOME_DIR_OPT, + "Specify ant home directory" ); + options[12] = + new CLOptionDescriptor( "define", + CLOptionDescriptor.ARGUMENTS_REQUIRED_2, + DEFINE_OPT, + "Define a variable (ie -Dfoo=var)" ); + return options; + } + + /** + * Entry point for standard ant. + * + * @param clOptions the list of command line options + */ + protected void execute( final List clOptions ) + throws Throwable + { + final int size = clOptions.size(); + 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(); + + for( int i = 0; i < size; i++ ) + { + final CLOption option = (CLOption)clOptions.get( i ); + + switch( option.getId() ) + { + case 0: targets.add( option.getArgument() ); break; + 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; + case QUIET_OPT: logLevel = "ERROR"; break; + case LOG_LEVEL_OPT: logLevel = option.getArgument(); break; + case LISTENER_OPT: listenerName = option.getArgument(); break; + case INCREMENTAL_OPT: incremental = true; break; + + case DEFINE_OPT: + defines.put( option.getArgument( 0 ), option.getArgument( 1 ) ); + break; + } + } + + 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(); + + 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 + { + m_binDir = getBinDir( binDir ); + m_homeDir = m_binDir.getParentFile(); + } + + m_libDir = getLibDir( m_homeDir, libDir ); + m_taskLibDir = getTaskLibDir( m_homeDir, taskLibDir ); + m_buildFile = getFile( filename ); + + m_logger.info( "Ant Base Directory: " + m_homeDir ); + m_logger.info( "Ant Bin Directory: " + m_binDir ); + m_logger.info( "Ant Build File: " + m_buildFile ); + m_logger.debug( "Ant Lib Directory: " + m_libDir ); + m_logger.debug( "Ant Task Lib Directory: " + m_taskLibDir ); + + setupContextClassLoader( m_libDir ); + + final Project project = getProject( builderName, m_buildFile ); + setupProjectContext( project, defines ); + + final ProjectEngine engine = getProjectEngine(); + + //make sure Engine is sweet... + if( engine instanceof Initializable ) + { + ((Initializable)engine).init(); + } + + deployDefaultTaskLibs( engine, m_taskLibDir ); + + BufferedReader reader = null; + + while( true ) + { + doBuild( engine, project, targets ); + + if( !incremental ) break; + + System.out.println( "Continue ? (Enter no to stop)" ); + + if( null == reader ) + { + reader = new BufferedReader( new InputStreamReader( System.in ) ); + } + + String line = reader.readLine(); + + if( line.equalsIgnoreCase( "no" ) ) break; + + } + + if( engine instanceof Disposable ) + { + ((Disposable)engine).dispose(); + } + } + + protected void deployDefaultTaskLibs( final ProjectEngine engine, + final File taskLibDirectory ) + + { + final ExtensionFileFilter filter = + new ExtensionFileFilter( new String[] { ".tsk" } ); + + final File files[] = taskLibDirectory.listFiles( filter ); + final Deployer deployer = engine.getDeployer(); + + 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 ); + } + } + } + + protected void doBuild( final ProjectEngine engine, + final Project project, + final ArrayList targets ) + { + try + { + final int targetCount = targets.size(); + + if( 0 == targetCount ) + { + engine.execute( project, project.getDefaultTargetName() ); + } + else + { + for( int i = 0; i < targetCount; i++ ) + { + engine.execute( project, (String)targets.get( i ) ); + } + } + } + catch( final AntException ae ) + { + m_logger.error( "BUILD FAILED" ); + m_logger.error( "Reason:\n" + StringUtil.printStackTrace( ae, 5, true ) ); + } + } + + protected void setupLogger( final String logLevel ) + { + m_logger = createLogger( logLevel ); + } + + protected void setupListener( final String listenerName ) + { + final ProjectListener listener = createListener( listenerName ); + m_logger.addLogTarget( listener ); + } + + protected void setupContextClassLoader( final File libDir ) + { + final ClassLoader classLoader = createClassLoader( libDir ); + Thread.currentThread().setContextClassLoader( classLoader ); + } + + protected ClassLoader createClassLoader( final File libDir ) + { + final ExtensionFileFilter filter = + new ExtensionFileFilter( new String[] { ".jar", ".zip" } ); + + final ArrayList urlList = new ArrayList(); + toURLS( urlList, libDir.listFiles( filter ) ); + + final URL urls[] = (URL[])urlList.toArray( new URL[0] ); + + return new URLClassLoader( urls, ClassLoader.getSystemClassLoader() ); + } + + protected void toURLS( final ArrayList urls, final File files[] ) + { + for( int i = 0; i < files.length; i++ ) + { + try { urls.add( files[ i ].toURL() ); } + catch( final MalformedURLException mue ) {} + } + } + + 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; + } + + protected void setupProjectContext( final Project project, final HashMap defines ) + throws AntException + { + final TaskletContext context = project.getContext(); + + final Iterator keys = defines.keySet().iterator(); + //make sure these come before following so they get overidden if user tries to + //confuse the system + while( keys.hasNext() ) + { + final String key = (String)keys.next(); + final String value = (String)defines.get( key ); + context.setProperty( key, value ); + } + + context.setProperty( AntContextResources.HOME_DIR, m_homeDir ); + context.setProperty( AntContextResources.BIN_DIR, m_binDir ); + context.setProperty( AntContextResources.LIB_DIR, m_libDir ); + context.setProperty( AntContextResources.TASKLIB_DIR, m_taskLibDir ); + //context.put( AntContextResources.USER_DIR, m_userDir ); + context.setProperty( TaskletContext.LOGGER, m_logger ); + context.setProperty( TaskletContext.JAVA_VERSION, getJavaVersion() ); + } + + 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; + } + + protected ProjectEngine getProjectEngine() + { + final ProjectEngine engine = createProjectEngine(); + engine.setLogger( m_logger ); + return engine; + } + + protected ProjectEngine createProjectEngine() + { + return new DefaultProjectEngine(); + } + + protected File getHomeDir( final String homeDir ) + throws AntException + { + final File file = new File( homeDir ); + 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 Logger createLogger( final String logLevel ) + throws AntException + { + final String logLevelCapitalized = logLevel.toUpperCase(); + final Priority.Enum priority = LogKit.getPriorityForName( logLevelCapitalized ); + + if( !priority.getName().equals( logLevelCapitalized ) ) + { + throw new AntException( "Unknown log level - " + logLevel ); + } + + final Category category = LogKit.createCategory( "ant", priority ); + return LogKit.createLogger( category ); + } + + 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 + { + final Class clazz = Class.forName( objectName ); + return clazz.newInstance(); + } + 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; + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/configuration/Configurable.java b/proposal/myrmidon/src/java/org/apache/ant/configuration/Configurable.java new file mode 100644 index 000000000..44903516e --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/configuration/Configurable.java @@ -0,0 +1,39 @@ +/* + * 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.configuration; + +import org.apache.avalon.ConfigurationException; + +/** + * This interface should be implemented by classes that need to be + * configured with custom parameters before initialization. + *
+ * + * The contract surrounding a Configurable is that the + * instantiating entity must call the configure + * method before it is valid. The configure method + * must be called after the constructor, and before any other method. + * + * @author Federico Barbieri + * @author Pierpaolo Fumagalli + * @author Stefano Mazzocchi + * @author Berin Loritsch + * @author Peter Donald + */ +public interface Configurable +{ + /** + * Pass the Configuration to the Configurable + * class. This method must always be called after the constructor + * and before any other method. + * + * @param configuration the class configurations. + */ + void configure( Configuration configuration ) + throws ConfigurationException; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/configuration/Configuration.java b/proposal/myrmidon/src/java/org/apache/ant/configuration/Configuration.java new file mode 100644 index 000000000..c410857e3 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/configuration/Configuration.java @@ -0,0 +1,31 @@ +/* + * 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.configuration; + +import java.util.Iterator; + +/** + * Hostile fork till Avalon gets equivelent functionality ;) + */ +public interface Configuration + extends org.apache.avalon.Configuration +{ + /** + * Retrieve a list of all child names. + * + * @return the child names + */ + Iterator getChildren(); + + /** + * Retrieve a list of all attribute names. + * + * @return the attribute names + */ + Iterator getAttributeNames(); +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/configuration/ConfigurationBuilder.java b/proposal/myrmidon/src/java/org/apache/ant/configuration/ConfigurationBuilder.java new file mode 100644 index 000000000..a90c6c875 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/configuration/ConfigurationBuilder.java @@ -0,0 +1,28 @@ +/* + * 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.configuration; + +import org.xml.sax.SAXException; + +/** + * Hostile fork till Avalon gets equivelent functionality ;) + */ +public class ConfigurationBuilder + extends org.apache.avalon.DefaultConfigurationBuilder +{ + public ConfigurationBuilder() + throws SAXException + { + super(); + } + + protected org.apache.avalon.SAXConfigurationHandler getHandler() + { + return new SAXConfigurationHandler(); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/configuration/DefaultConfiguration.java b/proposal/myrmidon/src/java/org/apache/ant/configuration/DefaultConfiguration.java new file mode 100644 index 000000000..916a5dc40 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/configuration/DefaultConfiguration.java @@ -0,0 +1,45 @@ +/* + * 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.configuration; + +import java.util.Iterator; + +/** + * Hostile fork till Avalon gets equivelent functionality ;) + */ +public class DefaultConfiguration + extends org.apache.avalon.DefaultConfiguration + implements Configuration +{ + public DefaultConfiguration( final String localname, final String location ) + { + super( localname, location ); + } + + /** + * Retrieve a list of all child names. + * + * @return the child names + */ + public Iterator getChildren() + { + if( null == m_children ) return EMPTY_ITERATOR; + else return m_children.iterator(); + } + + /** + * Retrieve a list of all attribute names. + * + * @return the attribute names + */ + public Iterator getAttributeNames() + { + if( null == m_attributes ) return EMPTY_ITERATOR; + else return m_attributes.keySet().iterator(); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/configuration/SAXConfigurationHandler.java b/proposal/myrmidon/src/java/org/apache/ant/configuration/SAXConfigurationHandler.java new file mode 100644 index 000000000..0a3569bea --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/configuration/SAXConfigurationHandler.java @@ -0,0 +1,21 @@ +/* + * 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.configuration; + +/** + * Hostile fork till Avalon gets equivelent functionality ;) + */ +public class SAXConfigurationHandler + extends org.apache.avalon.SAXConfigurationHandler +{ + protected org.apache.avalon.DefaultConfiguration + createConfiguration( final String localName, final String location ) + { + return new DefaultConfiguration( localName, location ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/AbstractConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/AbstractConverter.java new file mode 100644 index 000000000..bdadecdea --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/AbstractConverter.java @@ -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.convert; + +/** + * Instances of this interface are used to convert between different types. + * + * @author Peter Donald + */ +public abstract class AbstractConverter + implements Converter +{ + protected final Class m_source; + protected final Class m_destination; + + public AbstractConverter( final Class source, final Class destination ) + { + m_source = source; + m_destination = destination; + } + + public Object convert( final Class destination, final Object original ) + throws Exception + { + if( m_destination != destination ) + { + throw new IllegalArgumentException( "Destination type " + destination.getName() + + " is not equal to " + m_destination ); + } + + if( !m_source.isInstance( original ) ) + { + throw new IllegalArgumentException( "Object '" + original + "' is not an " + + "instance of " + m_source.getName() ); + } + + return convert( original ); + } + + protected abstract Object convert( Object original ) + throws Exception; +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/Converter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/Converter.java new file mode 100644 index 000000000..a16b13a60 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/Converter.java @@ -0,0 +1,19 @@ +/* + * 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; + +/** + * Instances of this interface are used to convert between different types. + * + * @author Peter Donald + */ +public interface Converter +{ + Object convert( Class destination, Object original ) + throws Exception; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterEntry.java b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterEntry.java new file mode 100644 index 000000000..18c7b1ee3 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterEntry.java @@ -0,0 +1,31 @@ +/* + * 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; + +import org.apache.ant.convert.Converter; +import org.apache.avalon.camelot.AbstractEntry; + +public class ConverterEntry + extends AbstractEntry +{ + public ConverterEntry( final ConverterInfo info, final Converter converter ) + { + super( info, converter ); + } + + /** + * Retrieve instance of converter. + * + * @return the component instance + */ + public Converter getConverter() + { + return (Converter)getInstance(); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterFactory.java b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterFactory.java new file mode 100644 index 000000000..504025622 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterFactory.java @@ -0,0 +1,23 @@ +/* + * 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; + +import org.apache.avalon.camelot.Factory; +import org.apache.avalon.camelot.FactoryException; + +/** + * Facility used to load Converters. + * + * @author Peter Donald + */ +public interface ConverterFactory + extends Factory +{ + ConverterEntry create( ConverterInfo info ) + throws FactoryException; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterInfo.java b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterInfo.java new file mode 100644 index 000000000..f4937cd34 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterInfo.java @@ -0,0 +1,51 @@ +/* + * 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; + +import java.net.URL; +import org.apache.avalon.camelot.Info; + +/** + * This info represents meta-information about a converter. + * + * @author Peter Donald + */ +public interface ConverterInfo + extends Info +{ + /** + * Retrieve the source type from which it can convert. + * NB: Should this be an array ???? + * + * @return the classname from which object produced + */ + String getSource(); + + /** + * Retrieve the type to which the converter converts. + * NB: Should this be an array ???? + * + * @return the classname of the produced object + */ + String getDestination(); + + /** + * Retrieve classname for concerter. + * + * @return the taskname + */ + String getClassname(); + + /** + * Retrieve location of task library where task is contained. + * + * @return the location of task library + */ + URL getLocation(); +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterLoader.java b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterLoader.java new file mode 100644 index 000000000..13c975dae --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterLoader.java @@ -0,0 +1,22 @@ +/* + * 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; + +import org.apache.avalon.camelot.Loader; + +/** + * Class used to load converters et al from a source. + * + * @author Peter Donald + */ +public interface ConverterLoader + extends Loader +{ + Converter loadConverter( String converter ) + throws Exception; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterRegistry.java b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterRegistry.java new file mode 100644 index 000000000..8feccecf5 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/ConverterRegistry.java @@ -0,0 +1,16 @@ +/* + * 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; + +import org.apache.avalon.camelot.Registry; + +public interface ConverterRegistry + extends Registry +{ + ConverterInfo getConverterInfo( String source, String destination ); +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterFactory.java b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterFactory.java new file mode 100644 index 000000000..256735905 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterFactory.java @@ -0,0 +1,75 @@ +/* + * 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; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import org.apache.ant.convert.Converter; +import org.apache.avalon.camelot.Entry; +import org.apache.avalon.camelot.Factory; +import org.apache.avalon.camelot.Loader; +import org.apache.avalon.camelot.FactoryException; +import org.apache.avalon.camelot.Info; + +/** + * Facility used to load Converters. + * + * @author Peter Donald + */ +public class DefaultConverterFactory + implements ConverterFactory +{ + protected final HashMap m_loaders = new HashMap(); + + public Entry create( final Info info ) + throws FactoryException + { + if( info.getClass().equals( ConverterInfo.class ) ) + { + throw new IllegalArgumentException( "Passed incorrect Info type to factory" ); + } + return create( (ConverterInfo)info ); + } + + public ConverterEntry create( final ConverterInfo info ) + throws FactoryException + { + final ConverterLoader loader = getLoader( info.getLocation() ); + + Object object = null; + + try { object = loader.load( info.getClassname() ); } + catch( final Exception e ) + { + throw new FactoryException( "Failed loading converter from " + info.getLocation() + + " due to " + e, e ); + } + + return new ConverterEntry( info, (Converter)object ); + } + + protected ConverterLoader getLoader( final URL location ) + { + ConverterLoader loader = (ConverterLoader)m_loaders.get( location ); + + if( null == loader ) + { + loader = createLoader( location ); + m_loaders.put( location, loader ); + } + + return loader; + } + + protected ConverterLoader createLoader( final URL location ) + { + if( null != location ) return new DefaultConverterLoader( location ); + else return new DefaultConverterLoader(); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterInfo.java b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterInfo.java new file mode 100644 index 000000000..bfa3d663f --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterInfo.java @@ -0,0 +1,78 @@ +/* + * 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; + +import java.net.URL; + +/** + * This info represents meta-information about a converter. + * + * @author Peter Donald + */ +public class DefaultConverterInfo + implements ConverterInfo +{ + protected final String m_source; + protected final String m_destination; + protected final String m_classname; + protected final URL m_location; + + public DefaultConverterInfo( final String source, + final String destination, + final String classname, + final URL location ) + { + m_source = source; + m_destination = destination; + m_classname = classname; + m_location = location; + } + + /** + * Retrieve the source type from which it can convert. + * NB: Should this be an array ???? + * + * @return the classname from which object produced + */ + public String getSource() + { + return m_source; + } + + /** + * Retrieve the type to which the converter converts. + * NB: Should this be an array ???? + * + * @return the classname of the produced object + */ + public String getDestination() + { + return m_destination; + } + + /** + * Retrieve classname for concerter. + * + * @return the taskname + */ + public String getClassname() + { + return m_classname; + } + + /** + * Retrieve location of task library where task is contained. + * + * @return the location of task library + */ + public URL getLocation() + { + return m_location; + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterLoader.java b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterLoader.java new file mode 100644 index 000000000..f4c37f183 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterLoader.java @@ -0,0 +1,39 @@ +/* + * 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; + +import java.net.URL; +import java.net.URLClassLoader; +import org.apache.avalon.camelot.AbstractLoader; + +/** + * Class used to load converters et al from a source. + * + * @author Peter Donald + */ +public class DefaultConverterLoader + extends AbstractLoader + implements ConverterLoader +{ + public DefaultConverterLoader() + { + super( new URLClassLoader( new URL[0], + Thread.currentThread().getContextClassLoader() ) ); + } + + public DefaultConverterLoader( final URL location ) + { + super( new URLClassLoader( new URL[] { location } ) ); + } + + public Converter loadConverter( final String converter ) + throws Exception + { + return (Converter)load( converter ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterRegistry.java b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterRegistry.java new file mode 100644 index 000000000..54eaaecb3 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/DefaultConverterRegistry.java @@ -0,0 +1,51 @@ +/* + * 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; + +import java.util.HashMap; +import org.apache.avalon.camelot.AbstractRegistry; +import org.apache.avalon.camelot.Info; +import org.apache.avalon.camelot.RegistryException; + +public class DefaultConverterRegistry + extends AbstractRegistry + implements ConverterRegistry +{ + protected final HashMap m_mapping = new HashMap(); + + public ConverterInfo getConverterInfo( final String source, final String destination ) + { + final HashMap map = (HashMap)m_mapping.get( source ); + if( null == map ) return null; + return (ConverterInfo)map.get( destination ); + } + + protected void checkInfo( final String name, final Info info ) + throws RegistryException + { + super.checkInfo( name, info ); + + final ConverterInfo converterInfo = (ConverterInfo)info; + final String source = converterInfo.getSource(); + final String destination = converterInfo.getDestination(); + + HashMap map = (HashMap)m_mapping.get( source ); + if( null == map ) + { + map = new HashMap(); + m_mapping.put( source, map ); + } + + map.put( destination, info ); + } + + protected Class getInfoClass() + { + return ConverterInfo.class; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToByteConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToByteConverter.java new file mode 100644 index 000000000..64f009cb0 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToByteConverter.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.ant.convert.AbstractConverter; + +/** + * String to byte converter + * + * @author Peter Donald + */ +public class StringToByteConverter + extends AbstractConverter +{ + public StringToByteConverter() + { + super( String.class, Byte.class ); + } + + public Object convert( final Object original ) + throws Exception + { + return new Byte( (String)original ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToDoubleConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToDoubleConverter.java new file mode 100644 index 000000000..9fd30be83 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToDoubleConverter.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.ant.convert.AbstractConverter; + +/** + * String to double converter + * + * @author Peter Donald + */ +public class StringToDoubleConverter + extends AbstractConverter +{ + public StringToDoubleConverter() + { + super( String.class, Double.class ); + } + + public Object convert( final Object original ) + throws Exception + { + return new Double( (String)original ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFloatConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFloatConverter.java new file mode 100644 index 000000000..53405b1c1 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToFloatConverter.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.ant.convert.AbstractConverter; + +/** + * String to float converter + * + * @author Peter Donald + */ +public class StringToFloatConverter + extends AbstractConverter +{ + public StringToFloatConverter() + { + super( String.class, Float.class ); + } + + public Object convert( final Object original ) + throws Exception + { + return new Float( (String)original ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToIntegerConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToIntegerConverter.java new file mode 100644 index 000000000..7bc118077 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToIntegerConverter.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.ant.convert.AbstractConverter; + +/** + * String to integer converter. + * + * @author Peter Donald + */ +public class StringToIntegerConverter + extends AbstractConverter +{ + public StringToIntegerConverter() + { + super( String.class, Integer.class ); + } + + public Object convert( final Object original ) + throws Exception + { + return new Integer( (String)original ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToLongConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToLongConverter.java new file mode 100644 index 000000000..e70f29307 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToLongConverter.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.ant.convert.AbstractConverter; + +/** + * String to long converter + * + * @author Peter Donald + */ +public class StringToLongConverter + extends AbstractConverter +{ + public StringToLongConverter() + { + super( String.class, Long.class ); + } + + public Object convert( final Object original ) + throws Exception + { + return new Long( (String)original ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToShortConverter.java b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToShortConverter.java new file mode 100644 index 000000000..d5f1e7848 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/StringToShortConverter.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.ant.convert.AbstractConverter; + +/** + * String to short converter + * + * @author Peter Donald + */ +public class StringToShortConverter + extends AbstractConverter +{ + public StringToShortConverter() + { + super( String.class, Short.class ); + } + + public Object convert( final Object original ) + throws Exception + { + return new Short( (String)original ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/convert/core/converters.properties b/proposal/myrmidon/src/java/org/apache/ant/convert/core/converters.properties new file mode 100644 index 000000000..52c6bb2a5 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/convert/core/converters.properties @@ -0,0 +1,6 @@ +org.apache.ant.convert.core.StringToLongConverter=java.lang.String, java.lang.Long +org.apache.ant.convert.core.StringToIntegerConverter=java.lang.String, java.lang.Integer +org.apache.ant.convert.core.StringToShortConverter=java.lang.String, java.lang.Short +org.apache.ant.convert.core.StringToByteConverter=java.lang.String, java.lang.Byte +org.apache.ant.convert.core.StringToDoubleConverter=java.lang.String, java.lang.Double +org.apache.ant.convert.core.StringToFloatConverter=java.lang.String, java.lang.Float diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProject.java b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProject.java new file mode 100644 index 000000000..2fc70820f --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProject.java @@ -0,0 +1,77 @@ +/* + * 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.project; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import org.apache.ant.AntException; +import org.apache.ant.tasklet.DefaultTaskletContext; +import org.apache.ant.tasklet.TaskletContext; + +public class DefaultProject + implements Project +{ + protected final TaskletContext m_baseContext = new DefaultTaskletContext(); + protected final HashMap m_targets = new HashMap(); + protected Target m_implicitTarget; + protected String m_defaultTarget; + + public Target getImplicitTarget() + { + return m_implicitTarget; + } + + public void setImplicitTarget( final Target target ) + { + m_implicitTarget = target; + } + + public Target getTarget( final String targetName ) + { + return (Target)m_targets.get( targetName ); + } + + public String getDefaultTargetName() + { + return m_defaultTarget; + } + + public Iterator getTargetNames() + { + return m_targets.keySet().iterator(); + } + + public TaskletContext getContext() + { + return m_baseContext; + } + + public void setDefaultTargetName( final String defaultTarget ) + { + m_defaultTarget = defaultTarget; + } + + public void addTarget( final String name, final Target target ) + throws AntException + { + if( null != m_targets.get( name ) ) + { + throw new AntException( "Can not have two targets in a file with the name " + + name ); + } + else + { + m_targets.put( name, target ); + } + } +} + + diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectBuilder.java b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectBuilder.java new file mode 100644 index 000000000..ab760516a --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectBuilder.java @@ -0,0 +1,215 @@ +/* + * 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.project; + +import java.io.File; +import java.io.IOException; +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.tasklet.TaskletContext; +import org.apache.avalon.ConfigurationException; +import org.apache.log.Logger; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class DefaultProjectBuilder + implements ProjectBuilder +{ + protected final ConfigurationBuilder m_configurationBuilder; + protected Logger m_logger; + + 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; + } + + 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 ); + 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 ); + } + } + + protected Project build( final File file, final Configuration configuration ) + throws IOException, AntException, ConfigurationException + { + if( !configuration.getName().equals("project") ) + { + throw new AntException( "Project file must be enclosed in project element" ); + } + + 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 ); + + final File baseDirectory = + (new File( file.getParentFile(), baseDirectoryName )).getAbsoluteFile(); + + m_logger.debug( "Project " + projectName + " base directory: " + baseDirectory ); + + final TaskletContext context = project.getContext(); + context.setProperty( TaskletContext.BASE_DIRECTORY, baseDirectory ); + context.setProperty( Project.PROJECT_FILE, file ); + context.setProperty( Project.PROJECT, projectName ); + + buildTopLevelProject( project, configuration ); + + return project; + } + + protected void buildTopLevelProject( final DefaultProject project, + final Configuration configuration ) + throws AntException + { + final Iterator elements = configuration.getChildren(); + + while( elements.hasNext() ) + { + final Configuration element = (Configuration)elements.next(); + final String name = element.getName(); + + if( name.equals( "target" ) ) buildTarget( project, element ); + else if( name.equals( "property" ) ) buildProperty( project, element ); + else + { + throw new AntException( "Unknown top-level element " + name + + " at " + element.getLocation() ); + } + } + } + + protected void buildTarget( final DefaultProject project, + final Configuration configuration ) + { + 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 ); + + if( null == name ) + { + throw new AntException( "Discovered un-named target at " + + configuration.getLocation() ); + } + + m_logger.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() ); + } + + final DefaultTarget target = new DefaultTarget(); + + if( null != ifCondition ) + { + m_logger.debug( "Target if condition: " + ifCondition ); + target.setIfCondition( true ); + target.setCondition( ifCondition ); + } + else if( null != unlessCondition ) + { + m_logger.debug( "Target unless condition: " + unlessCondition ); + target.setIfCondition( false ); + target.setCondition( unlessCondition ); + } + + if( null != depends ) + { + int start = 0; + int end = depends.indexOf( ',' ); + + while( -1 != end ) + { + final String dependency = + parseDependency( configuration, depends.substring( start, end ) ); + + target.addDependency( dependency ); + start = end++; + end = depends.indexOf( ',', start ); + } + + final String dependency = + parseDependency( configuration, depends.substring( start ) ); + + target.addDependency( dependency ); + } + + final Iterator tasks = configuration.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() ); + } + + m_logger.debug( "Target dependency: " + dependency ); + + return dependency; + } + + protected void buildProperty( final DefaultProject project, + final Configuration configuration ) + { + DefaultTarget target = (DefaultTarget)project.getImplicitTarget(); + + if( null == target ) + { + target = new DefaultTarget(); + project.setImplicitTarget( target ); + } + + m_logger.debug( "Parsed implicit task: " + configuration.getName() ); + target.addTask( configuration ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectEngine.java b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectEngine.java new file mode 100644 index 000000000..a9c2463d1 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectEngine.java @@ -0,0 +1,183 @@ +/* + * 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.project; + +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.ant.AntException; +import org.apache.ant.configuration.Configuration; +import org.apache.ant.convert.ConverterRegistry; +import org.apache.ant.convert.DefaultConverterRegistry; +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.DefaultTaskletInfo; +import org.apache.ant.tasklet.engine.DefaultTaskletRegistry; +import org.apache.ant.tasklet.engine.TaskletEngine; +import org.apache.ant.tasklet.engine.TaskletRegistry; +import org.apache.ant.tasklet.engine.TskDeployer; +import org.apache.avalon.DefaultComponentManager; +import org.apache.avalon.Disposable; +import org.apache.avalon.Initializable; +import org.apache.avalon.camelot.Deployer; +import org.apache.avalon.camelot.DeploymentException; +import org.apache.avalon.camelot.RegistryException; +import org.apache.log.Logger; + +public class DefaultProjectEngine + implements ProjectEngine, Initializable, Disposable +{ + protected Deployer m_deployer; + protected TaskletRegistry m_taskletRegistry; + protected ConverterRegistry m_converterRegistry; + protected TaskletEngine m_taskletEngine; + protected Logger m_logger; + + public void setLogger( final Logger logger ) + { + m_logger = logger; + } + + public void init() + throws Exception + { + m_taskletEngine = createTaskletEngine(); + + m_taskletRegistry = createTaskletRegistry(); + m_converterRegistry = createConverterRegistry(); + m_deployer = createDeployer(); + + //final DefaultTaskletContext context = new DefaultTaskletContext(); + //m_taskletEngine.contextualize( context ); + + final DefaultComponentManager componentManager = new DefaultComponentManager(); + componentManager.put( "org.apache.ant.tasklet.engine.TaskletRegistry", + m_taskletRegistry ); + + componentManager.put( "org.apache.ant.convert.ConverterRegistry", + m_converterRegistry ); + + componentManager.put( "org.apache.avalon.camelot.Deployer", m_deployer ); + + m_taskletEngine.compose( componentManager ); + + if( m_taskletEngine instanceof Initializable ) + { + ((Initializable)m_taskletEngine).init(); + } + } + + public void dispose() + throws Exception + { + if( m_taskletEngine instanceof Disposable ) + { + ((Disposable)m_taskletEngine).dispose(); + } + } + + public Deployer getDeployer() + { + return m_deployer; + } + + protected TaskletEngine createTaskletEngine() + { + return new DefaultTaskletEngine(); + } + + protected TaskletRegistry createTaskletRegistry() + { + return new DefaultTaskletRegistry(); + } + + protected ConverterRegistry createConverterRegistry() + { + return new DefaultConverterRegistry(); + } + + protected Deployer createDeployer() + { + final TskDeployer deployer = + new TskDeployer( m_taskletRegistry, m_converterRegistry ); + deployer.setLogger( m_logger ); + return deployer; + } + + public void execute( final Project project, final String target ) + throws AntException + { + m_taskletEngine.contextualize( project.getContext() ); + executeTarget( "", project.getImplicitTarget() ); + + final ArrayList done = new ArrayList(); + execute( project, target, done ); + } + + protected void execute( final Project project, + final String targetName, + final ArrayList done ) + throws AntException + { + final Target target = project.getTarget( targetName ); + + if( null == target ) + { + throw new AntException( "Unable to find target " + targetName ); + } + + done.add( targetName ); + + final Iterator dependencies = target.getDependencies(); + while( dependencies.hasNext() ) + { + final String dependency = (String)dependencies.next(); + if( !done.contains( dependency ) ) + { + execute( project, dependency, done ); + } + } + + final TaskletContext context = getContextFor( project, targetName ); + m_taskletEngine.contextualize( context ); + executeTarget( targetName, target ); + } + + protected TaskletContext getContextFor( final Project project, final String targetName ) + { + final DefaultTaskletContext context = + new DefaultTaskletContext( project.getContext() ); + + context.setProperty( Project.TARGET, targetName ); + context.put( TaskletContext.LOGGER, m_logger ); + + return context; + } + + protected void executeTarget( final String targetName, final Target target ) + throws AntException + { + m_logger.debug( "Executing target " + targetName ); + + final Iterator tasks = target.getTasks(); + while( tasks.hasNext() ) + { + final Configuration task = (Configuration)tasks.next(); + executeTask( task ); + } + } + + protected void executeTask( final Configuration configuration ) + throws AntException + { + final String name = configuration.getName(); + m_logger.debug( "Executing task " + name ); + + m_taskletEngine.execute( configuration ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectListener.java b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectListener.java new file mode 100644 index 000000000..51f9e203d --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultProjectListener.java @@ -0,0 +1,62 @@ +/* + * 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.project; + +import org.apache.log.format.PatternFormatter; +import org.apache.log.output.DefaultOutputLogTarget; + +public class DefaultProjectListener + extends DefaultOutputLogTarget + implements ProjectListener +{ + protected String m_prefix; + + /** + * Initialize the default pattern. + */ + protected void initPattern() + { + final PatternFormatter formatrer = new PatternFormatter(); + formatrer.setFormat( "%{message}\\n%{throwable}" ); + m_formatter = formatrer; + } + + public void projectStarted( final String projectName ) + { + output( "Starting project " + projectName + "\n" ); + } + + public void projectFinished() + { + } + + public void targetStarted( final String targetName ) + { + output( targetName + ":\n" ); + } + + public void targetFinished() + { + } + + public void taskletStarted( final String taskletName ) + { + m_prefix = taskletName; + } + + public void taskletFinished() + { + m_prefix = null; + } + + protected void output( final String data ) + { + if( null != m_prefix ) super.output( "[" + m_prefix + "] " + data ); + else super.output( data ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/DefaultTarget.java b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultTarget.java new file mode 100644 index 000000000..242062aa5 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/DefaultTarget.java @@ -0,0 +1,61 @@ +/* + * 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.project; + +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.ant.configuration.Configuration; + +public class DefaultTarget + implements Target +{ + protected ArrayList m_dependencies = new ArrayList(); + protected ArrayList m_tasks = new ArrayList(); + protected String m_condition; + protected boolean m_isIfCondition; + + public Iterator getDependencies() + { + return m_dependencies.iterator(); + } + + public Iterator getTasks() + { + return m_tasks.iterator(); + } + + public String getCondition() + { + return m_condition; + } + + public void setCondition( final String condition ) + { + m_condition = condition; + } + + public boolean isIfCondition() + { + return m_isIfCondition; + } + + public void setIfCondition( final boolean isIfCondition ) + { + m_isIfCondition = isIfCondition; + } + + public void addDependency( final String dependency ) + { + m_dependencies.add( dependency ); + } + + public void addTask( final Configuration taskConfiguration ) + { + m_tasks.add( taskConfiguration ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/Project.java b/proposal/myrmidon/src/java/org/apache/ant/project/Project.java new file mode 100644 index 000000000..88bf83eff --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/Project.java @@ -0,0 +1,30 @@ +/* + * 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.project; + +import java.util.Iterator; +import org.apache.ant.AntException; +import org.apache.ant.tasklet.TaskletContext; + +public interface Project +{ + // the name of currently executing project + String PROJECT = "ant.project.name"; + + // the name of currently executing project + String PROJECT_FILE = "ant.project.file"; + + // the name of currently executing target + String TARGET = "ant.target.name"; + + String getDefaultTargetName(); + Target getImplicitTarget(); + Target getTarget( String name ); + Iterator getTargetNames(); + TaskletContext getContext(); +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/ProjectBuilder.java b/proposal/myrmidon/src/java/org/apache/ant/project/ProjectBuilder.java new file mode 100644 index 000000000..ac98b8097 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/ProjectBuilder.java @@ -0,0 +1,23 @@ +/* + * 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.project; + +import java.io.File; +import java.io.IOException; +import org.apache.ant.AntException; +import org.apache.log.Logger; + +public interface ProjectBuilder +{ + void setLogger( Logger logger ); + + Project build( File projectFile ) + throws IOException, AntException; +} + + diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/ProjectEngine.java b/proposal/myrmidon/src/java/org/apache/ant/project/ProjectEngine.java new file mode 100644 index 000000000..04d8b5a5a --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/ProjectEngine.java @@ -0,0 +1,21 @@ +/* + * 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.project; + +import org.apache.ant.AntException; +import org.apache.avalon.camelot.Deployer; +import org.apache.avalon.camelot.Registry; +import org.apache.log.Logger; + +public interface ProjectEngine +{ + Deployer getDeployer(); + void setLogger( Logger logger ); + void execute( Project project, String target ) + throws AntException; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/ProjectListener.java b/proposal/myrmidon/src/java/org/apache/ant/project/ProjectListener.java new file mode 100644 index 000000000..b3b92dea9 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/ProjectListener.java @@ -0,0 +1,23 @@ +/* + * 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.project; + +import org.apache.log.LogTarget; + +public interface ProjectListener + extends LogTarget +{ + void projectStarted( String projectName ); + void projectFinished(); + + void targetStarted( String targetName ); + void targetFinished(); + + void taskletStarted( String taskletName ); + void taskletFinished(); +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/project/Target.java b/proposal/myrmidon/src/java/org/apache/ant/project/Target.java new file mode 100644 index 000000000..f86c5e901 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/project/Target.java @@ -0,0 +1,20 @@ +/* + * 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.project; + +import java.util.Iterator; + +public interface Target +{ + Iterator getDependencies(); + Iterator getTasks(); + String getCondition(); + boolean isIfCondition(); +} + + diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/AbstractTasklet.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/AbstractTasklet.java new file mode 100644 index 000000000..82f415300 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/AbstractTasklet.java @@ -0,0 +1,82 @@ +/* + * 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; + +import org.apache.ant.AntException; +import org.apache.avalon.Context; +import org.apache.avalon.Initializable; +import org.apache.log.Logger; + +/** + * This is abstract base class for tasklets. + * + * @author Peter Donald + */ +public abstract class AbstractTasklet + implements Tasklet, Initializable +{ + protected JavaVersion m_requiredJavaVersion; + + private TaskletContext m_context; + private Logger m_logger; + + /** + * Retrieve context from container. + * + * @param context the context + */ + public void contextualize( final Context context ) + { + m_context = (TaskletContext)context; + m_logger = (Logger)m_context.getLogger(); + } + + /** + * This will be called before run() method and checks any preconditions. + * + * Intially preconditions just include JVM version but in future it + * will automagically also check if all required parameters are present. + * + * @exception AntException if an error occurs + */ + public void init() + throws AntException + { + if( null != m_requiredJavaVersion ) + { + final JavaVersion suppliedVersion = m_context.getJavaVersion(); + + if( m_requiredJavaVersion.isLessThan( suppliedVersion ) ) + { + throw new AntException( "Task requires a JavaVersion of at least " + + m_requiredJavaVersion + " but current version is " + + suppliedVersion ); + } + } + } + + /** + * Convenience method for sub-class to retrieve context. + * + * @return the context + */ + protected TaskletContext getContext() + { + return m_context; + } + + /** + * Convenience method for subclass to get logger. + * + * @return the Logger + */ + protected Logger getLogger() + { + return m_logger; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/DefaultTaskletContext.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/DefaultTaskletContext.java new file mode 100644 index 000000000..34437ffcc --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/DefaultTaskletContext.java @@ -0,0 +1,236 @@ +/* + * 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; + +import java.io.File; +import org.apache.ant.AntException; +import org.apache.avalon.DefaultContext; +import org.apache.avalon.util.PropertyException; +import org.apache.avalon.util.PropertyUtil; +import org.apache.avalon.util.io.FileUtil; +import org.apache.log.Logger; + +/** + * This represents the *Context* in which a task can be executed. + * + * @author Peter Donald + */ +public class DefaultTaskletContext + extends DefaultContext + implements TaskletContext +{ + protected File m_baseDirectory; + + /** + * Constructor for Context with no parent contexts. + */ + public DefaultTaskletContext() + { + this( null ); + } + /** + * Constructor. + */ + public DefaultTaskletContext( final TaskletContext parent ) + { + super( parent ); + + if( null != parent ) + { + m_baseDirectory = (File)parent.get( BASE_DIRECTORY ); + } + } + + /** + * Retrieve JavaVersion running under. + * + * @return the version of JVM + */ + public JavaVersion getJavaVersion() + { + return (JavaVersion)get( JAVA_VERSION ); + } + + + /** + * Retrieve Name of tasklet. + * + * @return the name + */ + public String getName() + { + return (String)get( NAME ); + } + + /** + * Retrieve Logger associated with task. + * + * @return the logger + */ + public Logger getLogger() + { + return (Logger)get( LOGGER ); + } + + /** + * Retrieve base directory. + * + * @return the base directory + */ + public File getBaseDirectory() + { + return m_baseDirectory; + } + + /** + * Resolve filename. + * This involves resolving it against baseDirectory and + * removing ../ and ./ references. It also means formatting + * it appropriately for the particular OS (ie different OS have + * different volumes, file conventions etc) + * + * @param filename the filename to resolve + * @return the resolved filename + */ + public String resolveFilename( final String filename ) + { + final File result = FileUtil.resolveFile( m_baseDirectory, filename ); + if( null != result ) return result.toString(); + else return null; + } + + /** + * Resolve property. + * This evaluates all property substitutions based on current context. + * + * @param property the property to resolve + * @return the resolved property + */ + public Object resolveValue( final String property ) + { + try { return PropertyUtil.resolveProperty( property, this, false ); } + catch( final PropertyException pe ) + { + throw new AntException( "Error resolving " + property + " due to " +pe.getMessage(), + pe ); + } + } + + /** + * Retrieve property for name. + * + * @param name the name of property + * @return the value of the property + */ + public Object getProperty( final String name ) + { + return get( name ); + } + + /** + * Set property value in current context. + * + * @param name the name of property + * @param value the value of property + */ + public void setProperty( final String name, final Object value ) + { + setProperty( name, value, CURRENT ); + } + + /** + * Set property value. + * + * @param property the property + */ + public void setProperty( final String name, final Object value, final ScopeEnum scope ) + { + checkPropertyValid( name, value ); + + if( CURRENT == scope ) put( name, value ); + else if( PARENT == scope ) + { + if( null == m_parent ) + { + throw new AntException( "Can't set a property with parent scope when context " + + " has no parent" ); + } + else + { + ((DefaultTaskletContext)m_parent).put( name, value ); + } + } + else if( TOP_LEVEL == scope ) + { + DefaultTaskletContext context = this; + + while( null != context.m_parent ) + { + context = (DefaultTaskletContext)context.m_parent; + } + + context.put( name, value ); + } + else + { + throw new AntException( "Can't set a property with an unknown " + + "property context! (" + scope + ")" ); + } + } + + public void put( final Object key, final Object value ) + { + if( key.equals( BASE_DIRECTORY ) ) + { + try { m_baseDirectory = (File)value; } + catch( final ClassCastException cce ) + { + throw new AntException( "Can not set baseDirectory to a non-file value.", + cce ); + } + } + + super.put( key, value ); + } + + /** + * Make sure property is valid if it is one of the "magic" properties. + * + * @param name the name of property + * @param value the value of proeprty + * @exception AntException if an error occurs + */ + protected void checkPropertyValid( final String name, final Object value ) + throws AntException + { + if( LOGGER.equals( name ) && !( value instanceof Logger ) ) + { + throw new AntException( "property " + LOGGER + + " must have a value of type " + + Logger.class.getName() ); + } + else if( BASE_DIRECTORY.equals( name ) && !( value instanceof File ) ) + { + throw new AntException( "Property " + BASE_DIRECTORY + + " must have a value of type " + + File.class.getName() ); + } + else if( NAME.equals( name ) && !( value instanceof String ) ) + { + throw new AntException( "Property " + NAME + + " must have a value of type " + + String.class.getName() ); + } + else if( JAVA_VERSION.equals( name ) && !( value instanceof JavaVersion ) ) + { + throw new AntException( "property " + JAVA_VERSION + + " must have a value of type " + + JavaVersion.class.getName() ); + } + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/JavaVersion.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/JavaVersion.java new file mode 100644 index 000000000..e702b1bd1 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/JavaVersion.java @@ -0,0 +1,28 @@ +/* + * 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; + +import org.apache.avalon.util.ValuedEnum; + +/** + * Type safe wrapper class for Java Version enums. + */ +public final class JavaVersion + extends ValuedEnum +{ + //standard enums for version of JVM + public final static JavaVersion JAVA1_0 = new JavaVersion( "Java 1.0", 100 ); + public final static JavaVersion JAVA1_1 = new JavaVersion( "Java 1.1", 110 ); + public final static JavaVersion JAVA1_2 = new JavaVersion( "Java 1.2", 120 ); + public final static JavaVersion JAVA1_3 = new JavaVersion( "Java 1.3", 130 ); + + private JavaVersion( final String name, final int value ) + { + super( name, value ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/Tasklet.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/Tasklet.java new file mode 100644 index 000000000..a19e92935 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/Tasklet.java @@ -0,0 +1,21 @@ +/* + * 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; + +import org.apache.avalon.Component; +import org.apache.avalon.Contextualizable; + +/** + * This represents the individual tasks. + * + * @author Peter Donald + */ +public interface Tasklet + extends Component, Contextualizable, Runnable +{ +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/TaskletContext.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/TaskletContext.java new file mode 100644 index 000000000..3c089d7d0 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/TaskletContext.java @@ -0,0 +1,122 @@ +/* + * 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; + +import java.io.File; +import org.apache.avalon.Context; +import org.apache.avalon.util.Enum; +import org.apache.avalon.util.ValuedEnum; +import org.apache.log.Logger; + +/** + * This represents the *Context* in which a task can be executed. + * + * @author Peter Donald + */ +public interface TaskletContext + extends Context +{ + //these values are used when setting properties to indicate the scope at + //which properties are set + ScopeEnum CURRENT = new ScopeEnum( "Current" ); + ScopeEnum PARENT = new ScopeEnum( "Parent" ); + ScopeEnum TOP_LEVEL = new ScopeEnum( "TopLevel" ); + + //these are the names of properties that every TaskContext must contain + String JAVA_VERSION = "ant.java.version"; + String BASE_DIRECTORY = "ant.base.directory"; + String LOGGER = "ant.logger"; + String NAME = "ant.task.name"; + + /** + * Retrieve JavaVersion running under. + * + * @return the version of JVM + */ + JavaVersion getJavaVersion(); + + /** + * Retrieve Name of tasklet. + * + * @return the name + */ + String getName(); + + /** + * Retrieve Logger associated with task. + * + * @return the logger + */ + Logger getLogger(); + + /** + * Retrieve base directory. + * + * @return the base directory + */ + File getBaseDirectory(); + + /** + * Resolve filename. + * This involves resolving it against baseDirectory and + * removing ../ and ./ references. It also means formatting + * it appropriately for the particular OS (ie different OS have + * different volumes, file conventions etc) + * + * @param filename the filename to resolve + * @return the resolved filename + */ + String resolveFilename( String filename ); + + /** + * Resolve property. + * This evaluates all property substitutions based on current context. + * + * @param property the property to resolve + * @return the resolved property + */ + Object resolveValue( String property ); + + /** + * Retrieve property for name. + * + * @param name the name of property + * @return the value of property + */ + Object getProperty( String name ); + + /** + * Set property value in current context. + * + * @param name the name of property + * @param value the value of property + */ + void setProperty( String name, Object value ); + + /** + * Set property value. + * + * @param name the name of property + * @param value the value of property + * @param scope the scope at which to set property + */ + void setProperty( String name, Object value, ScopeEnum scope ); + + /** + * Safe wrapper class for Scope enums. + */ + final class ScopeEnum + extends Enum + { + ScopeEnum( final String name ) + { + super( name ); + } + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletConfigurer.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletConfigurer.java new file mode 100644 index 000000000..1348abbbb --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletConfigurer.java @@ -0,0 +1,438 @@ +/* + * 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 java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.ant.configuration.Configurable; +import org.apache.ant.configuration.Configuration; +import org.apache.ant.convert.Converter; +import org.apache.ant.convert.ConverterEntry; +import org.apache.ant.convert.ConverterFactory; +import org.apache.ant.convert.ConverterInfo; +import org.apache.ant.convert.ConverterRegistry; +import org.apache.ant.tasklet.Tasklet; +import org.apache.avalon.ComponentManager; +import org.apache.avalon.ComponentNotAccessibleException; +import org.apache.avalon.ComponentNotFoundException; +import org.apache.avalon.Composer; +import org.apache.avalon.ConfigurationException; +import org.apache.avalon.Context; +import org.apache.avalon.camelot.FactoryException; +import org.apache.avalon.util.PropertyException; +import org.apache.avalon.util.PropertyUtil; + +/** + * Class used to configure tasks. + * + * @author Peter Donald + */ +public class DefaultTaskletConfigurer + implements TaskletConfigurer, Composer +{ + protected final static String RESERVED_ATTRIBUTES[] = + { + "id" + }; + + protected final static String RESERVED_ELEMENTS[] = + { + "content" + }; + + protected ConverterRegistry m_converterRegistry; + protected ConverterFactory m_converterFactory; + + public void compose( final ComponentManager componentManager ) + throws ComponentNotFoundException, ComponentNotAccessibleException + { + m_converterRegistry = (ConverterRegistry)componentManager. + lookup( "org.apache.ant.convert.ConverterRegistry" ); + m_converterFactory = (ConverterFactory)componentManager. + lookup( "org.apache.ant.convert.ConverterFactory" ); + } + + public void configure( final Tasklet tasklet, + final Configuration configuration, + final Context context ) + throws ConfigurationException + { + configure( (Object)tasklet, configuration, context ); + } + + public void configure( final Object object, + final Configuration configuration, + final Context context ) + throws ConfigurationException + { + if( object instanceof Configurable ) + { + ((Configurable)object).configure( configuration ); + } + else + { + final Iterator attributes = configuration.getAttributeNames(); + + while( attributes.hasNext() ) + { + final String name = (String)attributes.next(); + final String value = configuration.getAttribute( name ); + configureAttribute( object, name, value, context ); + } + + final Iterator elements = configuration.getChildren(); + + while( elements.hasNext() ) + { + final Configuration element = (Configuration)elements.next(); + configureElement( object, element, context ); + } + + final String content = configuration.getValue( null ); + + if( null != content ) + { + if( !content.trim().equals( "" ) ) + { + configureContent( object, content, context ); + } + } + } + } + + protected void configureContent( final Object object, + final String content, + final Context context ) + throws ConfigurationException + { + setValue( object, "addContent", content, context ); + } + + protected void configureAttribute( final Object object, + final String name, + final String value, + final Context context ) + throws ConfigurationException + { + for( int i = 0; i < RESERVED_ATTRIBUTES.length; i++ ) + { + if( RESERVED_ATTRIBUTES[ i ].equals( name ) ) return; + } + + final String methodName = getMethodNameFor( name ); + setValue( object, methodName, value, context ); + } + + protected void setValue( final Object object, + final String methodName, + final String value, + final Context context ) + throws ConfigurationException + { + // OMFG the rest of this is soooooooooooooooooooooooooooooooo + // slow. Need to cache results per class etc. + + final Class clazz = object.getClass(); + final Method methods[] = getMethodsFor( clazz, methodName ); + + if( 0 == methods.length ) + { + throw new ConfigurationException( "Unable to set attribute via " + methodName + + " due to not finding any appropriate " + + "accessor method" ); + } + + setValue( object, value, context, methods ); + } + + protected void setValue( final Object object, + final String value, + final Context context, + final Method methods[] ) + throws ConfigurationException + { + try + { + final Object objectValue = + PropertyUtil.resolveProperty( value, context, false ); + + setValue( object, objectValue, methods ); + } + catch( final PropertyException pe ) + { + throw new ConfigurationException( "Error resolving property " + value, + pe ); + } + } + + protected void setValue( final Object object, Object value, final Method methods[] ) + throws ConfigurationException + { + final Class sourceClass = value.getClass(); + final String source = sourceClass.getName(); + + for( int i = 0; i < methods.length; i++ ) + { + if( setValue( object, value, methods[ i ], sourceClass, source ) ) + { + return; + } + } + + throw new ConfigurationException( "Unable to set attribute via " + + methods[ 0 ].getName() + " as could not convert " + + source + " to a matching type" ); + } + + protected boolean setValue( final Object object, + Object value, + final Method method, + final Class sourceClass, + final String source ) + throws ConfigurationException + { + Class parameterType = method.getParameterTypes()[ 0 ]; + if( parameterType.isPrimitive() ) + { + parameterType = getComplexTypeFor( parameterType ); + } + + if( !parameterType.isAssignableFrom( sourceClass ) ) + { + final String destination = parameterType.getName(); + + try + { + final ConverterInfo info = m_converterRegistry. + getConverterInfo( source, destination ); + + if( null == info ) return false; + + final ConverterEntry entry = m_converterFactory.create( info ); + final Converter converter = entry.getConverter(); + value = converter.convert( parameterType, value ); + } + catch( final FactoryException fe ) + { + throw new ConfigurationException( "Badly configured ConverterFactory ", + fe ); + } + catch( final Exception e ) + { + throw new ConfigurationException( "Error converting attribute for " + + method.getName(), + e ); + } + } + + try + { + method.invoke( object, new Object[] { value } ); + } + catch( final IllegalAccessException iae ) + { + //should never happen .... + throw new ConfigurationException( "Error retrieving methods with " + + "correct access specifiers", + iae ); + } + catch( final InvocationTargetException ite ) + { + throw new ConfigurationException( "Error calling method attribute " + + method.getName(), + ite ); + } + + return true; + } + + protected Class getComplexTypeFor( final Class clazz ) + { + if( String.class == clazz ) return String.class; + else if( Integer.TYPE.equals( clazz ) ) return Integer.class; + else if( Long.TYPE.equals( clazz ) ) return Long.class; + else if( Short.TYPE.equals( clazz ) ) return Short.class; + else if( Byte.TYPE.equals( clazz ) ) return Byte.class; + else if( Boolean.TYPE.equals( clazz ) ) return Boolean.class; + else if( Float.TYPE.equals( clazz ) ) return Float.class; + else if( Double.TYPE.equals( clazz ) ) return Double.class; + else + { + throw new IllegalArgumentException( "Can not get complex type for non-primitive " + + "type " + clazz.getName() ); + } + } + + protected Method[] getMethodsFor( final Class clazz, final String methodName ) + { + final Method methods[] = clazz.getMethods(); + final ArrayList matches = new ArrayList(); + + for( int i = 0; i < methods.length; i++ ) + { + final Method method = methods[ i ]; + if( methodName.equals( method.getName() ) && + Method.PUBLIC == (method.getModifiers() & Method.PUBLIC) ) + { + if( method.getReturnType().equals( Void.TYPE ) ) + { + final Class parameters[] = method.getParameterTypes(); + if( 1 == parameters.length ) + { + matches.add( method ); + } + } + } + } + + return (Method[])matches.toArray( new Method[0] ); + } + + protected Method[] getCreateMethodsFor( final Class clazz, final String methodName ) + { + final Method methods[] = clazz.getMethods(); + final ArrayList matches = new ArrayList(); + + for( int i = 0; i < methods.length; i++ ) + { + final Method method = methods[ i ]; + if( methodName.equals( method.getName() ) && + Method.PUBLIC == (method.getModifiers() & Method.PUBLIC) ) + { + final Class returnType = method.getReturnType(); + if( !returnType.equals( Void.TYPE ) && + !returnType.isPrimitive() ) + { + final Class parameters[] = method.getParameterTypes(); + if( 0 == parameters.length ) + { + matches.add( method ); + } + } + } + } + + return (Method[])matches.toArray( new Method[0] ); + } + + protected String getMethodNameFor( final String attribute ) + { + return "set" + getJavaNameFor( attribute ); + } + + protected String getJavaNameFor( final String name ) + { + final StringBuffer sb = new StringBuffer(); + + int index = name.indexOf( '-' ); + int last = 0; + + while( -1 != index ) + { + final String word = name.substring( last, index ).toLowerCase(); + sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); + sb.append( word.substring( 1, word.length() ) ); + last = index + 1; + index = name.indexOf( '-', last ); + } + + index = name.length(); + final String word = name.substring( last, index ).toLowerCase(); + sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); + sb.append( word.substring( 1, word.length() ) ); + + return sb.toString(); + } + + protected void configureElement( final Object object, + final Configuration configuration, + final Context context ) + throws ConfigurationException + { + final String name = configuration.getName(); + + for( int i = 0; i < RESERVED_ELEMENTS.length; i++ ) + { + if( RESERVED_ATTRIBUTES[ i ].equals( name ) ) return; + } + + final String javaName = getJavaNameFor( name ); + + // OMFG the rest of this is soooooooooooooooooooooooooooooooo + // slow. Need to cache results per class etc. + final Class clazz = object.getClass(); + Method methods[] = getMethodsFor( clazz, "add" + javaName ); + + if( 0 != methods.length ) + { + //guess it is first method ???? + addElement( object, methods[ 0 ], configuration, context ); + } + else + { + methods = getCreateMethodsFor( clazz, "create" + javaName ); + + if( 0 == methods.length ) + { + throw new ConfigurationException( "Unable to set attribute " + javaName + + " due to not finding any appropriate " + + "accessor method" ); + } + + //guess it is first method ???? + createElement( object, methods[ 0 ], configuration, context ); + } + } + + protected void createElement( final Object object, + final Method method, + final Configuration configuration, + final Context context ) + throws ConfigurationException + { + try + { + final Object created = method.invoke( object, new Object[ 0 ] ); + configure( created, configuration, context ); + } + catch( final ConfigurationException ce ) + { + throw ce; + } + catch( final Exception e ) + { + throw new ConfigurationException( "Error creating sub-element", e ); + } + } + + protected void addElement( final Object object, + final Method method, + final Configuration configuration, + final Context context ) + throws ConfigurationException + { + try + { + final Class clazz = method.getParameterTypes()[ 0 ]; + final Object created = clazz.newInstance(); + + configure( created, configuration, context ); + method.invoke( object, new Object[] { created } ); + } + catch( final ConfigurationException ce ) + { + throw ce; + } + catch( final Exception e ) + { + throw new ConfigurationException( "Error creating sub-element", e ); + } + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletEngine.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletEngine.java new file mode 100644 index 000000000..9dc964946 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletEngine.java @@ -0,0 +1,231 @@ +/* + * 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 java.util.HashMap; +import org.apache.ant.AntException; +import org.apache.ant.configuration.Configurable; +import org.apache.ant.configuration.Configuration; +import org.apache.ant.convert.ConverterFactory; +import org.apache.ant.convert.ConverterRegistry; +import org.apache.ant.tasklet.Tasklet; +import org.apache.ant.tasklet.TaskletContext; +import org.apache.avalon.ComponentManager; +import org.apache.avalon.ComponentNotAccessibleException; +import org.apache.avalon.ComponentNotFoundException; +import org.apache.avalon.Composer; +import org.apache.avalon.Context; +import org.apache.avalon.Contextualizable; +import org.apache.avalon.DefaultComponentManager; +import org.apache.avalon.Disposable; +import org.apache.avalon.Initializable; +import org.apache.avalon.camelot.FactoryException; +import org.apache.avalon.camelot.RegistryException; +import org.apache.log.Logger; + +public class DefaultTaskletEngine + implements TaskletEngine, Initializable +{ + protected ComponentManager m_componentManager; + protected TaskletContext m_context; + protected TaskletFactory m_taskletFactory; + protected ConverterFactory m_converterFactory; + protected TaskletRegistry m_taskletRegistry; + protected ConverterRegistry m_converterRegistry; + protected TaskletConfigurer m_configurer; + protected Logger m_logger; + + public void contextualize( final Context context ) + { + m_context = (TaskletContext)context; + m_logger = m_context.getLogger(); + } + + public void compose( final ComponentManager componentManager ) + throws ComponentNotFoundException, ComponentNotAccessibleException + { + m_componentManager = componentManager; + m_taskletRegistry = (TaskletRegistry)componentManager. + lookup( "org.apache.ant.tasklet.engine.TaskletRegistry" ); + m_converterRegistry = (ConverterRegistry)componentManager. + lookup( "org.apache.ant.convert.ConverterRegistry" ); + } + + public void init() + throws Exception + { + m_taskletFactory = createTaskletFactory(); + m_converterFactory = createConverterFactory(); + m_configurer = createTaskletConfigurer(); + + if( m_configurer instanceof Composer ) + { + final DefaultComponentManager componentManager = + new DefaultComponentManager( m_componentManager ); + componentManager.put( "org.apache.ant.convert.ConverterFactory", + m_converterFactory ); + + ((Composer)m_configurer).compose( componentManager ); + } + + if( m_configurer instanceof Initializable ) + { + ((Initializable)m_configurer).init(); + } + } + + protected TaskletConfigurer createTaskletConfigurer() + { + return new DefaultTaskletConfigurer(); + } + + protected TaskletFactory createTaskletFactory() + { + return new DefaultTaskletFactory(); + } + + protected ConverterFactory createConverterFactory() + { + return (ConverterFactory)m_taskletFactory; + } + + public void execute( final Configuration task ) + throws AntException + { + final Tasklet tasklet = createTasklet( task ); + + final String name = task.getName(); + m_logger.debug( "Created task " + name ); + + doContextualize( tasklet, task ); + m_logger.debug( "Contextualized task " + name ); + + doCompose( tasklet, task ); + m_logger.debug( "Composed task " + name ); + + doConfigure( tasklet, task ); + m_logger.debug( "Configured task " + name ); + + doInitialize( tasklet, task ); + m_logger.debug( "Initialize task " + name ); + + tasklet.run(); + m_logger.debug( "Ran task " + name ); + + doDispose( tasklet, task ); + m_logger.debug( "Dispose task " + name ); + } + + protected void doConfigure( final Tasklet tasklet, final Configuration task ) + throws AntException + { + try { m_configurer.configure( tasklet, task, m_context ); } + catch( final Throwable throwable ) + { + throw new AntException( "Error configuring task " + task.getName() + " at " + + task.getLocation() + "(Reason: " + + throwable.getMessage() + ")", throwable ); + } + } + + protected TaskletContext getContextFor( final String name ) + { + //If we are single threaded we really don't need to have a new object + //for context ... if we are not single threaded then we need to create new + //context. Alternatively we could remove getName from TaskletContext + + //final DefaultTaskletContext context = new DefaultTaskletContext( m_context ); + m_context.setProperty( TaskletContext.NAME, name ); + return m_context; + } + + protected void doCompose( final Tasklet tasklet, final Configuration task ) + throws AntException + { + if( tasklet instanceof Composer ) + { + try { ((Composer)tasklet).compose( m_componentManager ); } + catch( final Throwable throwable ) + { + throw new AntException( "Error composing task " + task.getName() + " at " + + task.getLocation() + "(Reason: " + + throwable.getMessage() + ")", throwable ); + } + } + } + + protected void doContextualize( final Tasklet tasklet, final Configuration task ) + throws AntException + { + final TaskletContext context = getContextFor( task.getName() ); + + try { tasklet.contextualize( context ); } + catch( final Throwable throwable ) + { + throw new AntException( "Error contextualizing task " + task.getName() + " at " + + task.getLocation() + "(Reason: " + + throwable.getMessage() + ")", throwable ); + } + } + + protected void doDispose( final Tasklet tasklet, final Configuration task ) + throws AntException + { + if( tasklet instanceof Disposable ) + { + try { ((Disposable)tasklet).dispose(); } + catch( final Throwable throwable ) + { + throw new AntException( "Error disposing task " + task.getName() + " at " + + task.getLocation() + "(Reason: " + + throwable.getMessage() + ")", throwable ); + } + } + } + + protected void doInitialize( final Tasklet tasklet, final Configuration task ) + throws AntException + { + if( tasklet instanceof Initializable ) + { + try { ((Initializable)tasklet).init(); } + catch( final Throwable throwable ) + { + throw new AntException( "Error initializing task " + task.getName() + " at " + + task.getLocation() + "(Reason: " + + throwable.getMessage() + ")", throwable ); + } + } + } + + protected Tasklet createTasklet( final Configuration configuration ) + throws AntException + { + final String name = configuration.getName(); + TaskletInfo info = null; + + try { info = (TaskletInfo)m_taskletRegistry.getInfo( name ); } + catch( final RegistryException re ) + { + throw new AntException( "Unable to locate task " + name, re ); + } + + TaskletEntry entry = null; + + try { entry = m_taskletFactory.create( info ); } + catch( final FactoryException fe ) + { + throw new AntException( "Unable to create task " + name + + " (of type " + info.getClassname() + " from " + + info.getLocation() + ")", + fe ); + } + + return entry.getTasklet(); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletFactory.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletFactory.java new file mode 100644 index 000000000..553f8ea39 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletFactory.java @@ -0,0 +1,65 @@ +/* + * 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 java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import org.apache.ant.tasklet.Tasklet; +import org.apache.ant.convert.ConverterLoader; +import org.apache.ant.convert.DefaultConverterFactory; +import org.apache.avalon.camelot.Entry; +import org.apache.avalon.camelot.Factory; +import org.apache.avalon.camelot.FactoryException; +import org.apache.avalon.camelot.Info; + +/** + * Facility used to load Tasklets. + * + * @author Peter Donald + */ +public class DefaultTaskletFactory + extends DefaultConverterFactory + implements TaskletFactory +{ + public Entry create( final Info info ) + throws FactoryException + { + if( !info.getClass().equals( TaskletInfo.class ) ) + { + return super.create( info ); + } + else + { + return create( (TaskletInfo)info ); + } + } + + public TaskletEntry create( final TaskletInfo info ) + throws FactoryException + { + final TaskletLoader loader = (TaskletLoader)getLoader( info.getLocation() ); + + Object object = null; + + try { object = loader.load( info.getClassname() ); } + catch( final Exception e ) + { + throw new FactoryException( "Failed loading tasklet from " + info.getLocation() + + " due to " + e, e ); + } + + return new TaskletEntry( info, (Tasklet)object ); + } + + protected ConverterLoader createLoader( final URL location ) + { + if( null != location ) return new DefaultTaskletLoader( location ); + else return new DefaultTaskletLoader(); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletInfo.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletInfo.java new file mode 100644 index 000000000..d4abdd6ba --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletInfo.java @@ -0,0 +1,54 @@ +/* + * 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 java.net.URL; +import org.apache.avalon.camelot.Info; + +/** + * This is default container of information about a task. + * A BeanInfo equivelent for a task. Eventually it will auto-magically + * generate a schema via reflection for Validator/Editor tools. + * + * @author Peter Donald + */ +public class DefaultTaskletInfo + implements TaskletInfo +{ + protected final String m_classname; + protected final URL m_location; + + /** + * Constructor that takes classname and taskLibraryLocation. + */ + public DefaultTaskletInfo( final String classname, final URL location ) + { + m_location = location; + m_classname = classname; + } + + /** + * Retrieve classname for task. + * + * @return the taskname + */ + public String getClassname() + { + return m_classname; + } + + /** + * Retrieve tasklib location from which task is loaded. + * + * @return the location + */ + public URL getLocation() + { + return m_location; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletLoader.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletLoader.java new file mode 100644 index 000000000..87e9eac97 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletLoader.java @@ -0,0 +1,37 @@ +/* + * 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 java.net.URL; +import org.apache.ant.tasklet.Tasklet; +import org.apache.ant.convert.DefaultConverterLoader; + +/** + * Class used to load tasks et al from a source. + * + * @author Peter Donald + */ +public class DefaultTaskletLoader + extends DefaultConverterLoader + implements TaskletLoader +{ + public DefaultTaskletLoader() + { + } + + public DefaultTaskletLoader( final URL location ) + { + super( location ); + } + + public Tasklet loadTasklet( final String tasklet ) + throws Exception + { + return (Tasklet)load( tasklet ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletRegistry.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletRegistry.java new file mode 100644 index 000000000..04e95fab3 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/DefaultTaskletRegistry.java @@ -0,0 +1,20 @@ +/* + * 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.avalon.camelot.AbstractRegistry; + +public class DefaultTaskletRegistry + extends AbstractRegistry + implements TaskletRegistry +{ + protected Class getInfoClass() + { + return TaskletInfo.class; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletConfigurer.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletConfigurer.java new file mode 100644 index 000000000..3e23680a0 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletConfigurer.java @@ -0,0 +1,24 @@ +/* + * 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.configuration.Configuration; +import org.apache.ant.tasklet.Tasklet; +import org.apache.avalon.ConfigurationException; +import org.apache.avalon.Context; + +/** + * Class used to configure tasks. + * + * @author Peter Donald + */ +public interface TaskletConfigurer +{ + void configure( Tasklet tasklet, Configuration configuration, Context context ) + throws ConfigurationException; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEngine.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEngine.java new file mode 100644 index 000000000..cf2d576ce --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEngine.java @@ -0,0 +1,20 @@ +/* + * 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.AntException; +import org.apache.ant.configuration.Configuration; +import org.apache.avalon.Composer; +import org.apache.avalon.Contextualizable; + +public interface TaskletEngine + extends Contextualizable, Composer +{ + void execute( final Configuration task ) + throws AntException; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEntry.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEntry.java new file mode 100644 index 000000000..b8003b772 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletEntry.java @@ -0,0 +1,31 @@ +/* + * 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.tasklet.Tasklet; +import org.apache.avalon.camelot.AbstractEntry; + +public class TaskletEntry + extends AbstractEntry +{ + public TaskletEntry( final TaskletInfo info, final Tasklet tasklet ) + { + super( info, tasklet ); + } + + /** + * Retrieve instance of tasklet. + * + * @return the component instance + */ + public Tasklet getTasklet() + { + return (Tasklet)getInstance(); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletFactory.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletFactory.java new file mode 100644 index 000000000..eaaf8be55 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletFactory.java @@ -0,0 +1,23 @@ +/* + * 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.avalon.camelot.Factory; +import org.apache.avalon.camelot.FactoryException; + +/** + * Facility used to load Tasklets. + * + * @author Peter Donald + */ +public interface TaskletFactory + extends Factory +{ + TaskletEntry create( TaskletInfo info ) + throws FactoryException; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletInfo.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletInfo.java new file mode 100644 index 000000000..62496ae02 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletInfo.java @@ -0,0 +1,36 @@ +/* + * 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 java.net.URL; +import org.apache.avalon.camelot.Info; + +/** + * This is information about a task. + * A BeanInfo equivelent for a task. Eventually it will auto-magically + * generate a schema via reflection for Validator/Editor tools. + * + * @author Peter Donald + */ +public interface TaskletInfo + extends Info +{ + /** + * Retrieve classname for task. + * + * @return the taskname + */ + String getClassname(); + + /** + * Retrieve location of task library where task is contained. + * + * @return the location of task library + */ + URL getLocation(); +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletLoader.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletLoader.java new file mode 100644 index 000000000..913469aff --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletLoader.java @@ -0,0 +1,23 @@ +/* + * 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.tasklet.Tasklet; +import org.apache.avalon.camelot.Loader; + +/** + * Class used to load tasks et al from a source. + * + * @author Peter Donald + */ +public interface TaskletLoader + extends Loader +{ + Tasklet loadTasklet( String tasklet ) + throws Exception; +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletRegistry.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletRegistry.java new file mode 100644 index 000000000..59cf3a03c --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TaskletRegistry.java @@ -0,0 +1,15 @@ +/* + * 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.avalon.camelot.Registry; + +public interface TaskletRegistry + extends Registry +{ +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TskDeployer.java b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TskDeployer.java new file mode 100644 index 000000000..ed76ccb23 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasklet/engine/TskDeployer.java @@ -0,0 +1,200 @@ +/* + * 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 java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Properties; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import org.apache.ant.tasklet.engine.DefaultTaskletInfo; +import org.apache.ant.convert.ConverterRegistry; +import org.apache.ant.convert.DefaultConverterInfo; +import org.apache.avalon.Component; +import org.apache.avalon.camelot.AbstractDeployer; +import org.apache.avalon.camelot.DeploymentException; +import org.apache.avalon.camelot.RegistryException; +import org.apache.log.Logger; + +/** + * This class deploys a .tsk file into a registry. + * + * @author Peter Donald + */ +public class TskDeployer + extends AbstractDeployer +{ + protected final static String TASKDEF_FILE = "TASK-LIB/taskdefs.properties"; + protected final static String CONVERTER_FILE = "TASK-LIB/converters.properties"; + + protected TaskletRegistry m_taskletRegistry; + protected ConverterRegistry m_converterRegistry; + + public TskDeployer( final TaskletRegistry taskletRegistry, + final ConverterRegistry converterRegistry ) + { + m_taskletRegistry = taskletRegistry; + m_converterRegistry = converterRegistry; + m_autoUndeploy = true; + m_type = "Tasklet"; + } + + public void setLogger( final Logger logger ) + { + m_logger = logger; + } + + protected boolean isValidLocation( final String location ) + { + //TODO: Make sure it is valid JavaIdentifier + //that optionally has '-' embedded in it + return true; + } + + /** + * Deploy Tasklets from a .tsk file. + * Eventually this should be cached for performance reasons. + * + * @param location the location + * @param file the file + * @exception DeploymentException if an error occurs + */ + protected void deployFromFile( final String location, final File file ) + throws DeploymentException + { + m_logger.info( "Deploying .tsk file (" + file + ") as " + location ); + + ZipFile zipFile = null; + + try { zipFile = new ZipFile( file ); } + catch( final IOException ioe ) + { + throw new DeploymentException( "Error opening " + file + + " due to " + ioe.getMessage(), + ioe ); + } + + try + { + final Properties taskdefs = loadProperties( zipFile, TASKDEF_FILE ); + final Properties converters = loadProperties( zipFile, CONVERTER_FILE ); + + try { zipFile.close(); } + catch( final IOException ioe ) {} + + URL url = null; + + try { url = file.toURL(); } + catch( final MalformedURLException mue ) {} + + handleTaskdefs( taskdefs, url ); + handleConverters( converters, url ); + } + catch( final DeploymentException de ) + { + try { zipFile.close(); } + catch( final IOException ioe ) {} + + throw de; + } + } + + protected void handleConverters( final Properties properties, final URL url ) + throws DeploymentException + { + final Enumeration enum = properties.propertyNames(); + + while( enum.hasMoreElements() ) + { + final String key = (String)enum.nextElement(); + final String value = (String)properties.get( key ); + final int index = value.indexOf( ',' ); + + if( -1 == index ) + { + throw new DeploymentException( "Malformed converter definition (" + + key + ")" ); + } + + final String source = value.substring( 0, index ).trim(); + final String destination = value.substring( index + 1 ).trim(); + + final DefaultConverterInfo info = + new DefaultConverterInfo( source, destination, key, url ); + + try { m_converterRegistry.register( key, info ); } + catch( final RegistryException re ) + { + throw new DeploymentException( "Error registering converter " + + key + " due to " + re, + re ); + } + } + } + + protected void handleTaskdefs( final Properties properties, final URL url ) + throws DeploymentException + { + final Enumeration enum = properties.propertyNames(); + + while( enum.hasMoreElements() ) + { + final String key = (String)enum.nextElement(); + final String value = (String)properties.get( key ); + final DefaultTaskletInfo info = new DefaultTaskletInfo( value, url ); + + try { m_taskletRegistry.register( key, info ); } + catch( final RegistryException re ) + { + throw new DeploymentException( "Error registering " + key + " due to " + re, + re ); + } + } + } + + protected Properties loadProperties( final ZipFile zipFile, final String filename ) + throws DeploymentException + { + final ZipEntry entry = zipFile.getEntry( filename ); + if( null == entry ) + { + throw new DeploymentException( "Unable to locate " + filename + + " in " + zipFile.getName() ); + } + + Properties properties = new Properties(); + + try + { + properties.load( zipFile.getInputStream( entry ) ); + } + catch( final IOException ioe ) + { + throw new DeploymentException( "Error reading " + filename + + " from " + zipFile.getName(), + ioe ); + } + + return properties; + } + + protected boolean canUndeploy( final Component component ) + throws DeploymentException + { + return true; + } + + protected void shutdownDeployment( final Component component ) + throws DeploymentException + { + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/ConfigurationTest.java b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/ConfigurationTest.java new file mode 100644 index 000000000..5d18585ef --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/ConfigurationTest.java @@ -0,0 +1,47 @@ +/* + * 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.tasks.core; + +import org.apache.ant.AntException; +import org.apache.ant.configuration.Configurable; +import org.apache.ant.configuration.Configuration; +import org.apache.ant.tasklet.AbstractTasklet; +import org.apache.avalon.ConfigurationException; + +/** + * This is abstract base class for tasklets. + * + * @author Peter Donald + */ +public class ConfigurationTest + extends AbstractTasklet + implements Configurable +{ + protected String m_message; + + public void configure( final Configuration configuration ) + throws ConfigurationException + { + String message = configuration.getAttribute( "message" ); + final Object object = getContext().resolveValue( message ); + if( object instanceof String ) + { + m_message = (String)object; + } + else + { + m_message = object.toString(); + } + } + + public void run() + throws AntException + { + getLogger().info( m_message ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/ContentTest.java b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/ContentTest.java new file mode 100644 index 000000000..08faf803a --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/ContentTest.java @@ -0,0 +1,37 @@ +/* + * 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.tasks.core; + +import org.apache.ant.AntException; +import org.apache.ant.tasklet.AbstractTasklet; + +/** + * This is abstract base class for tasklets. + * + * @author Peter Donald + */ +public class ContentTest + extends AbstractTasklet +{ + public void addContent( final Integer value ) + { + getLogger().info( "Integer content: " + value ); + } + + /* + public void addContent( final String blah ) + { + System.out.println( "String: " + blah ); + } + */ + + public void run() + throws AntException + { + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/Echo.java b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/Echo.java new file mode 100644 index 000000000..0d5d918e0 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/Echo.java @@ -0,0 +1,33 @@ +/* + * 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.tasks.core; + +import org.apache.ant.AntException; +import org.apache.ant.tasklet.AbstractTasklet; + +/** + * This is abstract base class for tasklets. + * + * @author Peter Donald + */ +public class Echo + extends AbstractTasklet +{ + protected String m_message; + + public void setMessage( final String message ) + { + m_message = message; + } + + public void run() + throws AntException + { + getLogger().info( m_message ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/PrimitiveTypesTest.java b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/PrimitiveTypesTest.java new file mode 100644 index 000000000..121e0f3ff --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/PrimitiveTypesTest.java @@ -0,0 +1,90 @@ + +/* + * 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.tasks.core; + +import org.apache.ant.AntException; +import org.apache.ant.tasklet.AbstractTasklet; + +/** + * + * @author Peter Donald + */ +public class PrimitiveTypesTest + extends AbstractTasklet +{ + public void setInteger( final Integer value ) + { + getLogger().info( "setInteger( " + value + " );" ); + } + + public void setInteger2( final int value ) + { + getLogger().info( "setInteger2( " + value + " );" ); + } + + public void setShort( final Short value ) + { + getLogger().info( "setShort( " + value + " );" ); + } + + public void setShort2( final short value ) + { + getLogger().info( "setShort2( " + value + " );" ); + } + + public void setByte( final Byte value ) + { + getLogger().info( "setByte( " + value + " );" ); + } + + public void setByte2( final byte value ) + { + getLogger().info( "setByte2( " + value + " );" ); + } + + public void setLong( final Long value ) + { + getLogger().info( "setLong( " + value + " );" ); + } + + public void setLong2( final long value ) + { + getLogger().info( "setLong2( " + value + " );" ); + } + + public void setFloat( final Float value ) + { + getLogger().info( "setFloat( " + value + " );" ); + } + + public void setFloat2( final float value ) + { + getLogger().info( "setFloat2( " + value + " );" ); + } + + public void setDouble( final Double value ) + { + getLogger().info( "setDouble( " + value + " );" ); + } + + public void setDouble2( final double value ) + { + getLogger().info( "setDouble2( " + value + " );" ); + } + + public void setString( final String value ) + { + getLogger().info( "setString( " + value + " );" ); + } + + public void run() + throws AntException + { + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/Property.java b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/Property.java new file mode 100644 index 000000000..dcf2a892d --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/Property.java @@ -0,0 +1,64 @@ +/* + * 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.tasks.core; + +import org.apache.ant.AntException; +import org.apache.ant.tasklet.AbstractTasklet; +import org.apache.ant.tasklet.TaskletContext; + +/** + * @author Peter Donald + */ +public class Property + extends AbstractTasklet +{ + protected String m_name; + protected String m_value; + protected boolean m_localScope = true; + + public void setName( final String name ) + { + m_name = name; + } + + public void setValue( final String value ) + { + m_value = value; + } + + public void setLocalScope( final boolean localScope ) + { + m_localScope = localScope; + } + + public void run() + throws AntException + { + if( null == m_name ) + { + throw new AntException( "Name must be specified" ); + } + + if( null == m_value ) + { + throw new AntException( "Value must be specified" ); + } + + final TaskletContext context = getContext(); + final Object value = context.resolveValue( m_value ); + + if( m_localScope ) + { + context.setProperty( m_name, value ); + } + else + { + context.setProperty( m_name, value, TaskletContext.PARENT ); + } + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/SubElementTest.java b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/SubElementTest.java new file mode 100644 index 000000000..e580a35e4 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/SubElementTest.java @@ -0,0 +1,43 @@ + +/* + * 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.tasks.core; + +import org.apache.ant.AntException; +import org.apache.ant.tasklet.AbstractTasklet; + +/** + * @author Peter Donald + */ +public class SubElementTest + extends AbstractTasklet +{ + public static final class Beep + { + public void setMessage( final String string ) + { + System.out.println( string ); + } + } + + public Beep createCreateBeep() + { + System.out.println( "createCreateBeep()" ); + return new Beep(); + } + + public void addAddBeep( final Beep beep ) + { + System.out.println( "addBeeper(" + beep + ");" ); + } + + public void run() + throws AntException + { + } +} diff --git a/proposal/myrmidon/src/java/org/apache/ant/tasks/core/taskdefs.properties b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/taskdefs.properties new file mode 100644 index 000000000..f3476cfb9 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/ant/tasks/core/taskdefs.properties @@ -0,0 +1,7 @@ +# TASK-LIB/taskdefs.properties +echo=org.apache.ant.tasks.core.Echo +prim-test=org.apache.ant.tasks.core.PrimitiveTypesTest +sub-elements-test=org.apache.ant.tasks.core.SubElementTest +conf-test=org.apache.ant.tasks.core.ConfigurationTest +content-test=org.apache.ant.tasks.core.ContentTest +property=org.apache.ant.tasks.core.Property \ No newline at end of file diff --git a/proposal/myrmidon/src/make/sample.xmk b/proposal/myrmidon/src/make/sample.xmk new file mode 100644 index 000000000..db04135d8 --- /dev/null +++ b/proposal/myrmidon/src/make/sample.xmk @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + 123 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/proposal/myrmidon/src/script/ant b/proposal/myrmidon/src/script/ant new file mode 100644 index 000000000..9667d7de9 --- /dev/null +++ b/proposal/myrmidon/src/script/ant @@ -0,0 +1,58 @@ +#!/bin/sh + +if [ -f $HOME/.antrc ] ; then + . $HOME/.antrc +fi + +# Cygwin support. +if [ "$OSTYPE" == "cygwin32" ] || [ "$OSTYPE" = "cygwin" ]; then + + if [ ! "$JAVA_HOME" = "" ]; then + JAVA_HOME=`cygpath --path --unix $JAVA_HOME` + fi +fi + +## resolve links - $0 may be a link to ant's home +PRG=$0 +progname=`basename $0` + +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '.*/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname $PRG`/$link" + fi +done + +ANT_HOME=`dirname "$PRG"`/.. + +# Allow .antrc to specifiy flags to java cmd +if [ "$JAVACMD" = "" ] ; then + JAVACMD=java +fi + +LOCALCLASSPATH=`echo $ANT_HOME/lib/*.jar | tr ' ' ':'` + +if [ "$CLASSPATH" != "" ] ; then + LOCALCLASSPATH=$CLASSPATH:$LOCALCLASSPATH +fi + +if [ "$JAVA_HOME" != "" ] ; then + if test -f $JAVA_HOME/lib/tools.jar ; then + LOCALCLASSPATH=$LOCALCLASSPATH:$JAVA_HOME/lib/tools.jar + fi +else + echo "Warning: JAVA_HOME environment variable is not set." + 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." +fi + +# More Cygwin support +if [ "$OSTYPE" == "cygwin32" ] || [ "$OSTYPE" = "cygwin" ] ; then + LOCALCLASSPATH=`cygpath --path --windows "$LOCALCLASSPATH"` +fi + +$JAVACMD -classpath $LOCALCLASSPATH $ANT_OPTS org.apache.ant.Main --ant-home=${ANT_HOME} $@ \ No newline at end of file diff --git a/proposal/myrmidon/src/script/ant.bat b/proposal/myrmidon/src/script/ant.bat new file mode 100644 index 000000000..af3a91dc9 --- /dev/null +++ b/proposal/myrmidon/src/script/ant.bat @@ -0,0 +1,35 @@ +@echo off + +:checkJava +if "%JAVACMD%" == "" set JAVACMD=%JAVA_HOME%\bin\java +if not "%JAVA_HOME%" == "" goto setupClasspath + +echo. +echo Warning: JAVA_HOME environment variable is not set. +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 + +:setupClasspath +set LOCALCLASSPATH=lib\xerces.jar;lib\ant.jar;lib\avalonapi.jar;%JAVA_HOME%\lib\tools.jar + +set THIS_FILE=%0 + +set ANT_CMD_LINE_ARGS= + +rem Slurp all args... +:setupArgs +if "%0" == "" goto doneArgs +set ANT_CMD_LINE_ARGS=%ANT_CMD_LINE_ARGS% %1 +shift +goto setupArgs + +:doneArgs +rem Mmmmmm tasty - finished slurping args + +%JAVACMD% -classpath "%LOCALCLASSPATH%" %ANT_OPTS% org.apache.ant.Main "--bin-dir=%THIS_FILE%" %ANT_CMD_LINE_ARGS% + +:end +set LOCALCLASSPATH= \ No newline at end of file diff --git a/proposal/myrmidon/src/script/antRun b/proposal/myrmidon/src/script/antRun new file mode 100644 index 000000000..f0a18f165 --- /dev/null +++ b/proposal/myrmidon/src/script/antRun @@ -0,0 +1,9 @@ +#! /bin/sh + +# Args: DIR command +cd "$1" +CMD="$2" +shift +shift + +exec $CMD "$@" diff --git a/proposal/myrmidon/src/script/antRun.bat b/proposal/myrmidon/src/script/antRun.bat new file mode 100644 index 000000000..fe0d1ceeb --- /dev/null +++ b/proposal/myrmidon/src/script/antRun.bat @@ -0,0 +1,18 @@ +@echo off + +cd %1 +set ANT_RUN_CMD=%2 +shift +shift + +set PARAMS= +:loop +if "%1" == "" goto runCommand +set PARAMS=%PARAMS% %1 +shift +goto loop + +:runCommand +echo %ANT_RUN_CMD% %PARAMS% +%ANT_RUN_CMD% %PARAMS% +