diff --git a/proposal/sandbox/embed/AntBean.java b/proposal/sandbox/embed/AntBean.java
new file mode 100644
index 000000000..b2170c0cb
--- /dev/null
+++ b/proposal/sandbox/embed/AntBean.java
@@ -0,0 +1,610 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.PrintStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+import java.util.Properties;
+import java.util.Enumeration;
+
+/**
+ * A bean to use to embed ant in a project.
+ *
+ * Based on Main.java.
+ *
+ * Note: this is the result of refactoring Main. Some methods are not
+ * usefull for embeded use or may have better names ( I used the
+ * option name from Main, for consistency ). I marked them with @experimental.
+ *
+ * @experimental: the current API is not yet stable.
+ *
+ * @author duncan@x180.com
+ * @author Costin Manolache
+ * @since ant1.5
+ */
+public class AntBean extends Task {
+
+ /** The default build file name */
+ public final static String DEFAULT_BUILD_FILENAME = "build.xml";
+
+ /** Our current message output status. Follows Project.MSG_XXX */
+ private int msgOutputLevel = Project.MSG_INFO;
+
+ /** File that we are using for configuration */
+ private File buildFile; /** null */
+ private String searchForThis=null;
+
+ /** Stream that we are using for logging */
+ private PrintStream out = System.out;
+
+ /** Stream that we are using for logging error messages */
+ private PrintStream err = System.err;
+
+ /** The build targets */
+ private Vector targets = new Vector(5);
+
+ /** Set of properties that can be used by tasks */
+ private Properties definedProps = new Properties();
+
+ /** Names of classes to add as listeners to project */
+ private Vector listeners = new Vector(5);
+
+ /** File names of property files to load on startup */
+ private Vector propertyFiles = new Vector(5);
+
+ /**
+ * The Ant logger class. There may be only one logger. It will have the
+ * right to use the 'out' PrintStream. The class must implements the BuildLogger
+ * interface
+ */
+ private String loggerClassname = null;
+
+ /**
+ * Indicates whether output to the log is to be unadorned.
+ */
+ private boolean emacsMode = false;
+
+ private ClassLoader coreLoader;
+
+ private ProjectHelper helper=null;
+
+ private Project newProject=null;
+
+ private boolean redirectOutput=true;
+
+
+ public AntBean() {
+ }
+
+ // -------------------- Bean properties --------------------
+ // extracted from Main's command line processing code
+
+ /** Global verbosity level
+ */
+ public void setOutputLevel( int level ) {
+ msgOutputLevel=level;
+ }
+
+ public void setBuildfile( String name ) {
+ buildFile = new File(name);
+ }
+
+ /** Add a listener class name
+ */
+ public void addListener( String s ) {
+ listeners.addElement(s);
+ }
+
+ /** Set the logger class name ( -logger option in command
+ * line ).
+ *
+ * @experimental LoggerClassName would be a better name
+ */
+ public void setLogger( String s ) {
+ if (loggerClassname != null) {
+ System.out.println("Only one logger class may be specified.");
+ return;
+ }
+ loggerClassname = s;
+ }
+
+ /** Emacs mode for the output
+ */
+ public void setEmacs( boolean b ) {
+ emacsMode = b;
+ }
+
+ /** The name of the build file to execute, by
+ * searching in the filesystem.
+ */
+ public void setFind( String s ) {
+ if (s==null) {
+ searchForThis = s;
+ } else {
+ searchForThis = DEFAULT_BUILD_FILENAME;
+ }
+ }
+
+ /** Same as -propertyfile
+ */
+ public void addPropertyfile( String s ) {
+ propertyFiles.addElement(s);
+ }
+
+ /** Set the core loader, to be used to execute.
+ */
+ public void setCoreLoader( ClassLoader coreLoader ) {
+ coreLoader=coreLoader;
+ }
+
+ /** Add a user-defined property
+ */
+ public void setUserProperty( String name, String value ) {
+ definedProps.put( name, value );
+ }
+
+
+ /** Add a target to be executed
+ */
+ public void addTarget(String arg ) {
+ targets.addElement(arg);
+ }
+
+ /** Log file. It'll redirect the System output and logs to this
+ * file. Supported by -logfile argument in ant - probably
+ * a bad idea if you embed ant in an application.
+ *
+ * @experimental - I don't think it's a good idea.
+ */
+ public void setLogfile( String name ) {
+ try {
+ File logFile = new File(name);
+ out = new PrintStream(new FileOutputStream(logFile));
+ err = out;
+ System.setOut(out);
+ System.setErr(out);
+ } catch (IOException ioe) {
+ String msg = "Cannot write on the specified log file. " +
+ "Make sure the path exists and you have write permissions.";
+ System.out.println(msg);
+ return;
+ }
+ }
+
+ /** Redirect the output and set a security manager before
+ * executing ant. Defaults to true for backward comptibility,
+ * you should set it to false if you embed ant.
+ */
+ public void setRedirectOutput( boolean b ) {
+ redirectOutput=b;
+ }
+
+ // -------------------- Property getters --------------------
+
+
+ /** Return the build file. If it was not explicitely specified, search
+ * for it in the parent directories
+ *
+ *
Takes the "find" property as a suffix to append to each
+ * parent directory in seach of a build file. Once the
+ * root of the file-system has been reached an exception
+ * is thrown.
+ */
+ public File getBuildFile()
+ throws BuildException
+ {
+ // if buildFile was not specified on the command line,
+ if (buildFile == null) {
+ // but -find then search for it
+ if (searchForThis != null) {
+ buildFile = findBuildFile(System.getProperty("user.dir"),
+ searchForThis);
+ } else {
+ buildFile = new File(DEFAULT_BUILD_FILENAME);
+ }
+ }
+ getProject().setUserProperty("ant.file" , buildFile.getAbsolutePath() );
+ return buildFile;
+ }
+
+ /** Return an (initialized) project constructed using the current
+ * settings.
+ * This will not load the build.xml file - you can 'load' the
+ * project object with tasks manually or execute 'standalone'
+ * tasks in the context of the project.
+ */
+ public Project getProject() {
+ if( newProject!=null )
+ return newProject;
+ loadProperties();
+
+ helper=ProjectHelper.getProjectHelper();
+ newProject = helper.createProject(coreLoader);
+ newProject.setCoreLoader(coreLoader);
+
+ addBuildListeners(newProject);
+
+ newProject.fireBuildStarted();
+
+ newProject.init();
+ newProject.setUserProperty("ant.version", getAntVersion());
+
+ // set user-define properties
+ Enumeration e = definedProps.keys();
+ while (e.hasMoreElements()) {
+ String arg = (String)e.nextElement();
+ String value = (String)definedProps.get(arg);
+ newProject.setUserProperty(arg, value);
+ }
+
+ return newProject;
+ }
+
+ private static String antVersion = null;
+
+ /** @experimental
+ * Ant version should be combined with the ProjectHelper version and type,
+ * since it'll determine the set of features supported by ant ( at the xml
+ * level ).
+ */
+ public static synchronized String getAntVersion() throws BuildException {
+ if (antVersion == null) {
+ try {
+ Properties props = new Properties();
+ InputStream in =
+ Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
+ props.load(in);
+ in.close();
+
+ String lSep = System.getProperty("line.separator");
+ StringBuffer msg = new StringBuffer();
+ msg.append("Apache Ant version ");
+ msg.append(props.getProperty("VERSION"));
+ msg.append(" compiled on ");
+ msg.append(props.getProperty("DATE"));
+ antVersion = msg.toString();
+ } catch (IOException ioe) {
+ throw new BuildException("Could not load the version information:"
+ + ioe.getMessage());
+ } catch (NullPointerException npe) {
+ throw new BuildException("Could not load the version information.");
+ }
+ }
+ return antVersion;
+ }
+
+
+
+ // -------------------- Bean methods --------------------
+ Throwable error = null;
+
+
+ /** Clean up allocated resources and finish the processing of the
+ * current Project.
+ */
+ public void done() {
+ newProject.fireBuildFinished(error);
+ }
+
+
+ /**
+ * Process an XML file and execute the targets.
+ *
+ * This method can be called multiple times, eventually after setting different
+ * build file and different targets - all executions will happen in the
+ * same execution context ( project ).
+ */
+ public void processBuildXml() throws BuildException {
+ checkBuildFile();
+ File buildFile=getBuildFile();
+ Project newProject=getProject();
+
+ // first use the ProjectHelper to create the project object
+ // from the given build file.
+ String noParserMessage =
+ "No JAXP compliant XML parser found. Please visit http://xml.apache.org for a suitable parser";
+ try {
+ Class.forName("javax.xml.parsers.SAXParserFactory");
+ helper.parse(newProject, buildFile);
+ } catch (NoClassDefFoundError ncdfe) {
+ throw new BuildException(noParserMessage, ncdfe);
+ } catch (ClassNotFoundException cnfe) {
+ throw new BuildException(noParserMessage, cnfe);
+ } catch (NullPointerException npe) {
+ throw new BuildException(noParserMessage, npe);
+ }
+
+ // make sure that we have a target to execute
+ if (targets.size() == 0) {
+ targets.addElement(newProject.getDefaultTarget());
+ }
+
+ newProject.executeTargets(targets);
+ }
+
+ public void execute() throws BuildException {
+
+ try {
+ if( redirectOutput ) {
+ pushSystemOut();
+ }
+
+ processBuildXml();
+ } catch(RuntimeException exc) {
+ error = exc;
+ throw exc;
+ } catch(Error err) {
+ error = err;
+ throw err;
+ } finally {
+ done();
+ if( redirectOutput )
+ popSystemOut();
+ }
+ }
+
+ // -------------------- Private methods --------------------
+
+ private void checkBuildFile() throws BuildException {
+ File buildFile=getBuildFile();
+
+ // make sure buildfile exists
+ if (!buildFile.exists()) {
+ System.out.println("Buildfile: " + buildFile + " does not exist!");
+ throw new BuildException("Build failed");
+ }
+
+ // make sure it's not a directory (this falls into the ultra
+ // paranoid lets check everything catagory
+ if (buildFile.isDirectory()) {
+ System.out.println("What? Buildfile: " + buildFile + " is a dir!");
+ throw new BuildException("Build failed");
+ }
+
+ // track when we started
+ if (msgOutputLevel >= Project.MSG_INFO) {
+ System.out.println("Buildfile: " + buildFile);
+ }
+ }
+
+ private PrintStream oldErr=null;
+ private PrintStream oldOut=null;
+ private SecurityManager oldsm = null;
+
+ private void pushSystemOut() {
+ oldErr = System.err;
+ oldOut = System.out;
+
+ // use a system manager that prevents from System.exit()
+ // only in JDK > 1.1
+ if ( !Project.JAVA_1_0.equals(Project.getJavaVersion()) &&
+ !Project.JAVA_1_1.equals(Project.getJavaVersion()) ){
+ oldsm = System.getSecurityManager();
+
+ //SecurityManager can not be installed here for backwards
+ //compatability reasons (PD). Needs to be loaded prior to
+ //ant class if we are going to implement it.
+ //System.setSecurityManager(new NoExitSecurityManager());
+ }
+ System.setOut(new PrintStream(new DemuxOutputStream(getProject(), false)));
+ System.setErr(new PrintStream(new DemuxOutputStream(getProject(), true)));
+ }
+
+ private void popSystemOut() {
+ // put back the original security manager
+ //The following will never eval to true. (PD)
+ if (oldsm != null){
+ System.setSecurityManager(oldsm);
+ }
+
+ if( oldOut!=null && oldErr!=null ) {
+ System.setOut(oldOut);
+ System.setErr(oldErr);
+ }
+ }
+
+ protected void addBuildListeners(Project newProject) {
+
+ // Add the default listener
+ newProject.addBuildListener(createLogger());
+
+ for (int i = 0; i < listeners.size(); i++) {
+ String className = (String) listeners.elementAt(i);
+ try {
+ BuildListener listener =
+ (BuildListener) Class.forName(className).newInstance();
+ newProject.addBuildListener(listener);
+ }
+ catch(Throwable exc) {
+ throw new BuildException("Unable to instantiate listener " + className, exc);
+ }
+ }
+ }
+
+ /**
+ * Creates the default build logger for sending build events to the ant log.
+ */
+ protected BuildLogger createLogger() {
+ BuildLogger logger = null;
+ if (loggerClassname != null) {
+ try {
+ logger = (BuildLogger)(Class.forName(loggerClassname).newInstance());
+ } catch (ClassCastException e) {
+ System.err.println("The specified logger class " + loggerClassname +
+ " does not implement the BuildLogger interface");
+ throw new RuntimeException();
+ } catch (Exception e) {
+ System.err.println("Unable to instantiate specified logger class " +
+ loggerClassname + " : " + e.getClass().getName());
+ throw new RuntimeException();
+ }
+ }
+ else {
+ logger = new DefaultLogger();
+ }
+
+ logger.setMessageOutputLevel(msgOutputLevel);
+ logger.setOutputPrintStream(out);
+ logger.setErrorPrintStream(err);
+ logger.setEmacsMode(emacsMode);
+
+ return logger;
+ }
+
+ /** Load all propertyFiles
+ */
+ private void loadProperties()
+ {
+ // Load the property files specified by -propertyfile
+ for (int propertyFileIndex=0;
+ propertyFileIndex < propertyFiles.size();
+ propertyFileIndex++) {
+ String filename = (String) propertyFiles.elementAt(propertyFileIndex);
+ Properties props = new Properties();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(filename);
+ props.load(fis);
+ }
+ catch (IOException e) {
+ System.out.println("Could not load property file "
+ + filename + ": " + e.getMessage());
+ } finally {
+ if (fis != null){
+ try {
+ fis.close();
+ } catch (IOException e){
+ }
+ }
+ }
+
+ // ensure that -D properties take precedence
+ Enumeration propertyNames = props.propertyNames();
+ while (propertyNames.hasMoreElements()) {
+ String name = (String) propertyNames.nextElement();
+ if (definedProps.getProperty(name) == null) {
+ definedProps.put(name, props.getProperty(name));
+ }
+ }
+ }
+ }
+
+ // -------------------- XXX Move to FileUtil --------------------
+
+ /**
+ * Helper to get the parent file for a given file.
+ *
+ *
Added to simulate File.getParentFile() from JDK 1.2.
+ *
+ * @param file File
+ * @return Parent file or null if none
+ */
+ private File getParentFile(File file) {
+ String filename = file.getAbsolutePath();
+ file = new File(filename);
+ filename = file.getParent();
+
+ if (filename != null && msgOutputLevel >= Project.MSG_VERBOSE) {
+ System.out.println("Searching in "+filename);
+ }
+
+ return (filename == null) ? null : new File(filename);
+ }
+
+ /**
+ * Search parent directories for the build file.
+ *
+ *
Takes the given target as a suffix to append to each
+ * parent directory in seach of a build file. Once the
+ * root of the file-system has been reached an exception
+ * is thrown.
+ *
+ * @param suffix Suffix filename to look for in parents.
+ * @return A handle to the build file
+ *
+ * @exception BuildException Failed to locate a build file
+ */
+ private File findBuildFile(String start, String suffix) throws BuildException {
+ if (msgOutputLevel >= Project.MSG_INFO) {
+ System.out.println("Searching for " + suffix + " ...");
+ }
+
+ File parent = new File(new File(start).getAbsolutePath());
+ File file = new File(parent, suffix);
+
+ // check if the target file exists in the current directory
+ while (!file.exists()) {
+ // change to parent directory
+ parent = getParentFile(parent);
+
+ // if parent is null, then we are at the root of the fs,
+ // complain that we can't find the build file.
+ if (parent == null) {
+ throw new BuildException("Could not locate a build file!");
+ }
+
+ // refresh our file handle
+ file = new File(parent, suffix);
+ }
+
+ return file;
+ }
+
+}
diff --git a/proposal/sandbox/embed/Main.java b/proposal/sandbox/embed/Main.java
new file mode 100644
index 000000000..cc62e0997
--- /dev/null
+++ b/proposal/sandbox/embed/Main.java
@@ -0,0 +1,422 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.PrintStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+import java.util.Properties;
+import java.util.Enumeration;
+
+/**
+ * Command line entry point into Ant. This class is entered via the
+ * cannonical "public static void main" entry point and reads the
+ * command line arguments. It then assembles and executes an Ant
+ * project.
+ *
+ * If you integrating Ant into some other tool, this is not the class
+ * to use as an entry point. Please see the source code of this
+ * class to see how it manipulates the Ant project classes.
+ *
+ * @author duncan@x180.com
+ */
+public class Main {
+
+ private AntBean ant=new AntBean();
+
+ /**
+ * Indicates if this ant should be run.
+ */
+ private boolean readyToRun = false;
+
+ /**
+ * Indicates we should only parse and display the project help information
+ */
+ private boolean projectHelp = false;
+
+ /**
+ * Prints the message of the Throwable if it's not null.
+ */
+ private static void printMessage(Throwable t) {
+ String message = t.getMessage();
+ if (message != null) {
+ System.err.println(message);
+ }
+ }
+
+ /**
+ * Entry point method.
+ */
+ public static void start(String[] args, Properties additionalUserProperties,
+ ClassLoader coreLoader) {
+ Main m = null;
+
+ try {
+ m = new Main(args);
+ } catch(Throwable exc) {
+ printMessage(exc);
+ System.exit(1);
+ }
+ AntBean ant=m.ant;
+ ant.setCoreLoader( coreLoader );
+
+ if (additionalUserProperties != null) {
+ for (Enumeration e = additionalUserProperties.keys(); e.hasMoreElements(); ) {
+ String key = (String) e.nextElement();
+ String property = additionalUserProperties.getProperty(key);
+ ant.setUserProperty(key, property);
+ }
+ }
+
+ try {
+ Project project=ant.getProject();
+
+ ant.execute();
+
+ System.exit(0);
+ } catch (BuildException be) {
+ // ?? What is that, and how should it be implemented
+ // XXX if (m.err != System.err) {
+ printMessage(be);
+ //}
+ System.exit(1);
+ } catch(Throwable exc) {
+ exc.printStackTrace();
+ printMessage(exc);
+ System.exit(1);
+ }
+ }
+
+
+
+ /**
+ * Command line entry point. This method kicks off the building
+ * of a project object and executes a build using either a given
+ * target or the default target.
+ *
+ * @param args Command line args.
+ */
+ public static void main(String[] args) {
+ start(args, null, null);
+ }
+
+ protected Main(String[] args) throws BuildException {
+
+ String searchForThis = null;
+
+ // cycle through given args
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+
+ if (arg.equals("-help")) {
+ printUsage();
+ return;
+ } else if (arg.equals("-version")) {
+ printVersion();
+ return;
+ } else if (arg.equals("-quiet") || arg.equals("-q")) {
+ ant.setOutputLevel( Project.MSG_WARN );
+ } else if (arg.equals("-verbose") || arg.equals("-v")) {
+ printVersion();
+ ant.setOutputLevel( Project.MSG_VERBOSE );
+ } else if (arg.equals("-debug")) {
+ printVersion();
+ ant.setOutputLevel( Project.MSG_DEBUG );
+ } else if (arg.equals("-logfile") || arg.equals("-l")) {
+ try {
+ ant.setLogfile( args[i+1] );
+ i++;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ String msg = "You must specify a log file when " +
+ "using the -log argument";
+ System.out.println(msg);
+ return;
+ }
+ } else if (arg.equals("-buildfile") || arg.equals("-file") || arg.equals("-f")) {
+ try {
+ ant.setBuildfile( args[i+1] );
+ i++;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ String msg = "You must specify a buildfile when " +
+ "using the -buildfile argument";
+ System.out.println(msg);
+ return;
+ }
+ } else if (arg.equals("-listener")) {
+ try {
+ ant.addListener(args[i+1]);
+ i++;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ String msg = "You must specify a classname when " +
+ "using the -listener argument";
+ System.out.println(msg);
+ return;
+ }
+ } else if (arg.startsWith("-D")) {
+
+ /* Interestingly enough, we get to here when a user
+ * uses -Dname=value. However, in some cases, the JDK
+ * goes ahead * and parses this out to args
+ * {"-Dname", "value"}
+ * so instead of parsing on "=", we just make the "-D"
+ * characters go away and skip one argument forward.
+ *
+ * I don't know how to predict when the JDK is going
+ * to help or not, so we simply look for the equals sign.
+ */
+
+ String name = arg.substring(2, arg.length());
+ String value = null;
+ int posEq = name.indexOf("=");
+ if (posEq > 0) {
+ value = name.substring(posEq+1);
+ name = name.substring(0, posEq);
+ } else if (i < args.length-1) {
+ value = args[++i];
+ }
+
+ ant.setUserProperty(name, value);
+
+ } else if (arg.equals("-logger")) {
+ try {
+ ant.setLogger( args[++i] );
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ System.out.println("You must specify a classname when " +
+ "using the -logger argument");
+ return;
+ }
+ } else if (arg.equals("-emacs")) {
+ ant.setEmacs( true );
+ } else if (arg.equals("-projecthelp")) {
+ // set the flag to display the targets and quit
+ projectHelp = true;
+ } else if (arg.equals("-find")) {
+ // eat up next arg if present, default to build.xml
+ if (i < args.length-1) {
+ ant.setFind( args[++i] );
+ } else {
+ ant.setFind( null );
+ }
+ } else if (arg.startsWith("-propertyfile")) {
+ try {
+ ant.addPropertyfile( args[i+1] );
+ i++;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ String msg = "You must specify a property filename when " +
+ "using the -propertyfile argument";
+ System.out.println(msg);
+ return;
+ }
+ } else if (arg.startsWith("-")) {
+ // we don't have any more args to recognize!
+ String msg = "Unknown argument: " + arg;
+ System.out.println(msg);
+ printUsage();
+ return;
+ } else {
+ // if it's no other arg, it may be the target
+ ant.addTarget(arg);
+ }
+ }
+
+ readyToRun = true;
+ }
+
+
+ protected void addBuildListeners(Project project) {
+ ant.addBuildListeners( project );
+ }
+
+ /**
+ * Prints the usage of how to use this class to System.out
+ */
+ private static void printUsage() {
+ String lSep = System.getProperty("line.separator");
+ StringBuffer msg = new StringBuffer();
+ msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
+ msg.append("Options: " + lSep);
+ msg.append(" -help print this message" + lSep);
+ msg.append(" -projecthelp print project help information" + lSep);
+ msg.append(" -version print the version information and exit" + lSep);
+ msg.append(" -quiet be extra quiet" + lSep);
+ msg.append(" -verbose be extra verbose" + lSep);
+ msg.append(" -debug print debugging information" + lSep);
+ msg.append(" -emacs produce logging information without adornments" + lSep);
+ msg.append(" -logfile use given file for log" + lSep);
+ msg.append(" -logger the class which is to perform logging" + lSep);
+ msg.append(" -listener add an instance of class as a project listener" + lSep);
+ msg.append(" -buildfile use given buildfile" + lSep);
+ msg.append(" -D= use value for given property" + lSep);
+ msg.append(" -propertyfile load all properties from file with -D" + lSep);
+ msg.append(" properties taking precedence" + lSep);
+ msg.append(" -find search for buildfile towards the root of the" + lSep);
+ msg.append(" filesystem and use it" + lSep);
+ System.out.println(msg.toString());
+ }
+
+ private static void printVersion() throws BuildException {
+ System.out.println(AntBean.getAntVersion());
+ }
+
+ public static synchronized String getAntVersion() throws BuildException {
+ return AntBean.getAntVersion();
+ }
+
+ /**
+ * Print the project description, if any
+ */
+ private static void printDescription(Project project) {
+ if (project.getDescription() != null) {
+ System.out.println(project.getDescription());
+ }
+ }
+
+ /**
+ * Print out a list of all targets in the current buildfile
+ */
+ private static void printTargets(Project project, boolean printSubTargets) {
+ // find the target with the longest name
+ int maxLength = 0;
+ Enumeration ptargets = project.getTargets().elements();
+ String targetName;
+ String targetDescription;
+ Target currentTarget;
+ // split the targets in top-level and sub-targets depending
+ // on the presence of a description
+ Vector topNames = new Vector();
+ Vector topDescriptions = new Vector();
+ Vector subNames = new Vector();
+
+ while (ptargets.hasMoreElements()) {
+ currentTarget = (Target)ptargets.nextElement();
+ targetName = currentTarget.getName();
+ targetDescription = currentTarget.getDescription();
+ // maintain a sorted list of targets
+ if (targetDescription == null) {
+ int pos = findTargetPosition(subNames, targetName);
+ subNames.insertElementAt(targetName, pos);
+ } else {
+ int pos = findTargetPosition(topNames, targetName);
+ topNames.insertElementAt(targetName, pos);
+ topDescriptions.insertElementAt(targetDescription, pos);
+ if (targetName.length() > maxLength) {
+ maxLength = targetName.length();
+ }
+ }
+ }
+
+ printTargets(topNames, topDescriptions, "Main targets:", maxLength);
+
+ if( printSubTargets ) {
+ printTargets(subNames, null, "Subtargets:", 0);
+ }
+
+ String defaultTarget = project.getDefaultTarget();
+ if (defaultTarget != null && !"".equals(defaultTarget)) { // shouldn't need to check but...
+ System.out.println( "Default target: " + defaultTarget );
+ }
+ }
+
+ /**
+ * Search for the insert position to keep names a sorted list of Strings
+ */
+ private static int findTargetPosition(Vector names, String name) {
+ int res = names.size();
+ for (int i=0; i.
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.xml.sax.AttributeList;
+
+
+/**
+ * Configures a Project (complete with Targets and Tasks) based on
+ * a XML build file. It'll rely on a plugin to do the actual processing
+ * of the xml file.
+ *
+ * This class also provide static wrappers for common introspection.
+ *
+ * All helper plugins must provide backward compatiblity with the
+ * original ant patterns, unless a different behavior is explicitely
+ * specified. For example, if namespace is used on the tag
+ * the helper can expect the entire build file to be namespace-enabled.
+ * Namespaces or helper-specific tags can provide meta-information to
+ * the helper, allowing it to use new ( or different policies ).
+ *
+ * However, if no namespace is used the behavior should be exactly
+ * identical with the default helper.
+ *
+ * @author duncan@x180.com
+ */
+public /*abstract*/ class ProjectHelper {
+
+ /**
+ * Configures the Project with the contents of the specified XML file.
+ * ( should it be deprecated ? Using getProjectHelper(), parse()
+ * is cleaner )
+ */
+ public static void configureProject(Project project, File buildFile)
+ throws BuildException
+ {
+ ProjectHelper helper=ProjectHelper.getProjectHelper();
+ helper.parse(project, buildFile);
+ }
+
+ public ProjectHelper() {
+ }
+
+ /**
+ * Constructs a new Ant parser for the specified XML file.
+ * @deprecated Use the plugin mechanism instead.
+ */
+ private ProjectHelper(Project project, File buildFile) {
+ // this.project = project;
+ // this.buildFile = new File(buildFile.getAbsolutePath());
+ // buildFileParent = new File(this.buildFile.getParent());
+ }
+
+ public Project createProject(ClassLoader coreLoader) {
+ return new Project();
+ }
+
+ /**
+ * Process an input source for the project.
+ *
+ * All processors must support at least File sources. It is usefull to also support
+ * InputSource - this allows the input to come from a non-filesystem source
+ * (like input stream of a POST, or a soap body ).
+ */
+ public /*abstract*/ void parse(Project project, Object source)
+ throws BuildException
+ {
+ throw new BuildException("You must use a real ProjectHelper implementation");
+ }
+
+ /* -------------------- Helper discovery -------------------- */
+ public static final String HELPER_PROPERTY =
+ "org.apache.tools.ant.ProjectHelper";
+
+ public static final String SERVICE_ID =
+ "/META-INF/services/org.apache.tools.ant.ProjectHelper";
+
+
+ /** Discover a project helper instance.
+ */
+ public static ProjectHelper getProjectHelper()
+ throws BuildException
+ {
+ // Identify the class loader we will be using. Ant may be
+ // in a webapp or embeded in a different app
+ ClassLoader classLoader = getContextClassLoader();
+ ProjectHelper helper=null;
+
+ // First, try the system property
+ try {
+ String helperClass = System.getProperty(HELPER_PROPERTY);
+ if (helperClass != null) {
+ helper = newHelper(helperClass, classLoader);
+ }
+ } catch (SecurityException e) {
+ // It's ok, we'll try next option
+ ;
+ }
+
+ // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
+ // automatically if in CLASSPATH, with the right META-INF/services.
+ if( helper==null ) {
+ try {
+ InputStream is=null;
+ if (classLoader == null) {
+ is=ClassLoader.getSystemResourceAsStream( SERVICE_ID );
+ } else {
+ is=classLoader.getResourceAsStream( SERVICE_ID );
+ }
+
+ if( is != null ) {
+ // This code is needed by EBCDIC and other strange systems.
+ // It's a fix for bugs reported in xerces
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ } catch (java.io.UnsupportedEncodingException e) {
+ rd = new BufferedReader(new InputStreamReader(is));
+ }
+
+ String helperClassName = rd.readLine();
+ rd.close();
+
+ if (helperClassName != null &&
+ ! "".equals(helperClassName)) {
+
+ helper= newHelper( helperClassName, classLoader );
+ }
+ }
+ } catch( Exception ex ) {
+ ;
+ }
+ }
+
+ // Default
+ return new ProjectHelperImpl();
+ }
+
+ private static ProjectHelper newHelper(String helperClass,
+ ClassLoader classLoader)
+ throws BuildException
+ {
+
+ try {
+ Class clazz = null;
+ if (classLoader == null) {
+ clazz = Class.forName(helperClass);
+ } else {
+ clazz = classLoader.loadClass(helperClass);
+ }
+ return ((ProjectHelper) clazz.newInstance());
+ } catch (Exception e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ */
+ public static ClassLoader getContextClassLoader()
+ throws BuildException
+ {
+ // Are we running on a JDK 1.2 or later system?
+ Method method = null;
+ try {
+ method = Thread.class.getMethod("getContextClassLoader", null);
+ } catch (NoSuchMethodException e) {
+ // we are running on JDK 1.1
+ return null;
+ }
+
+ // Get the thread context class loader (if there is one)
+ ClassLoader classLoader = null;
+ try {
+ classLoader = (ClassLoader)
+ method.invoke(Thread.currentThread(), null);
+ } catch (IllegalAccessException e) {
+ throw new BuildException
+ ("Unexpected IllegalAccessException", e);
+ } catch (InvocationTargetException e) {
+ throw new BuildException
+ ("Unexpected InvocationTargetException", e);
+ }
+
+ // Return the selected class loader
+ return (classLoader);
+ }
+
+
+ /* -------------------- Common utilities and wrappers -------------------- */
+
+ /** Configure a java object using ant's rules.
+ */
+ public static void configure(Object target, AttributeList attrs,
+ Project project) throws BuildException {
+ TaskAdapter adapter=null;
+ if( target instanceof TaskAdapter ) {
+ adapter=(TaskAdapter)target;
+ target=adapter.getProxy();
+ }
+
+ IntrospectionHelper ih =
+ IntrospectionHelper.getHelper(target.getClass());
+ if( adapter != null )
+ adapter.setIntrospectionHelper( ih );
+
+ // XXX What's that ?
+ project.addBuildListener(ih);
+
+ for (int i = 0; i < attrs.getLength(); i++) {
+ // reflect these into the target
+ String value=replaceProperties(project, attrs.getValue(i),
+ project.getProperties() );
+ String name=attrs.getName(i).toLowerCase(Locale.US);
+ try {
+ if (adapter!=null ) {
+ adapter.setAttribute( name, value );
+ } else {
+ ih.setAttribute(project, target,
+ name, value);
+ }
+ } catch (BuildException be) {
+ // id attribute must be set externally
+ // XXX Shuldn't it be 'name' ( i.e. lower-cased ) ?
+ if (!attrs.getName(i).equals("id")) {
+ throw be;
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds the content of #PCDATA sections to an element.
+ */
+ public static void addText(Project project, Object target, char[] buf, int start, int end)
+ throws BuildException {
+ addText(project, target, new String(buf, start, end));
+ }
+
+ /**
+ * Adds the content of #PCDATA sections to an element.
+ */
+ public static void addText(Project project, Object target, String text)
+ throws BuildException {
+
+ if (text == null ) {
+ return;
+ }
+
+ if(target instanceof TaskAdapter) {
+ target = ((TaskAdapter) target).getProxy();
+ }
+
+ IntrospectionHelper.getHelper(target.getClass()).addText(project, target, text);
+ }
+
+ /**
+ * Stores a configured child element into its parent object
+ */
+ public static void storeChild(Project project, Object parent, Object child, String tag) {
+ IntrospectionHelper ih = IntrospectionHelper.getHelper(parent.getClass());
+ ih.storeElement(project, parent, child, tag);
+ }
+
+ /**
+ * Replace ${} style constructions in the given value with the string value of
+ * the corresponding data types.
+ *
+ * @param value the string to be scanned for property references.
+ * @since 1.5
+ */
+ public static String replaceProperties(Project project, String value)
+ throws BuildException {
+ return project.replaceProperties(value);
+ }
+
+ /**
+ * Replace ${} style constructions in the given value with the string value of
+ * the corresponding data types.
+ *
+ * @param value the string to be scanned for property references.
+ */
+ public static String replaceProperties(Project project, String value, Hashtable keys)
+ throws BuildException {
+ if (value == null) {
+ return null;
+ }
+
+ Vector fragments = new Vector();
+ Vector propertyRefs = new Vector();
+ parsePropertyString(value, fragments, propertyRefs);
+
+ StringBuffer sb = new StringBuffer();
+ Enumeration i = fragments.elements();
+ Enumeration j = propertyRefs.elements();
+ while (i.hasMoreElements()) {
+ String fragment = (String)i.nextElement();
+ if (fragment == null) {
+ String propertyName = (String)j.nextElement();
+ if (!keys.containsKey(propertyName)) {
+ project.log("Property ${" + propertyName + "} has not been set", Project.MSG_VERBOSE);
+ }
+ fragment = (keys.containsKey(propertyName)) ? (String) keys.get(propertyName)
+ : "${" + propertyName + "}";
+ }
+ sb.append(fragment);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * This method will parse a string containing ${value} style
+ * property values into two lists. The first list is a collection
+ * of text fragments, while the other is a set of string property names
+ * null entries in the first list indicate a property reference from the
+ * second list.
+ */
+ public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs)
+ throws BuildException {
+ int prev = 0;
+ int pos;
+ while ((pos = value.indexOf("$", prev)) >= 0) {
+ if (pos > 0) {
+ fragments.addElement(value.substring(prev, pos));
+ }
+
+ if( pos == (value.length() - 1)) {
+ fragments.addElement("$");
+ prev = pos + 1;
+ }
+ else if (value.charAt(pos + 1) != '{' ) {
+ fragments.addElement(value.substring(pos + 1, pos + 2));
+ prev = pos + 2;
+ } else {
+ int endName = value.indexOf('}', pos);
+ if (endName < 0) {
+ throw new BuildException("Syntax error in property: "
+ + value );
+ }
+ String propertyName = value.substring(pos + 2, endName);
+ fragments.addElement(null);
+ propertyRefs.addElement(propertyName);
+ prev = endName + 1;
+ }
+ }
+
+ if (prev < value.length()) {
+ fragments.addElement(value.substring(prev));
+ }
+ }
+
+}
diff --git a/proposal/sandbox/embed/ProjectHelperImpl.java b/proposal/sandbox/embed/ProjectHelperImpl.java
new file mode 100644
index 000000000..a825a687a
--- /dev/null
+++ b/proposal/sandbox/embed/ProjectHelperImpl.java
@@ -0,0 +1,750 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Locale;
+import org.xml.sax.Locator;
+import org.xml.sax.InputSource;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.SAXException;
+import org.xml.sax.DocumentHandler;
+import org.xml.sax.AttributeList;
+import org.xml.sax.helpers.XMLReaderAdapter;
+
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.ParserConfigurationException;
+
+// Note: Use of local classes can create problems with various compilers
+// like gcc or even jikes. In addition it makes the code harder to read
+// for many beginners ( at least for me - Costin ).
+// I changed the code to avoid the tricks that the compiler does, now
+// jikes works ( for me ). Note that declaring the classes 'private'
+// is probably overriden by the compiler - a feature of the internal class impl.
+
+/**
+ * "Original" implementation of the project helper. Or at least
+ * what is present in ant1.4.
+ *
+ * @author duncan@x180.com
+ */
+public class ProjectHelperImpl extends ProjectHelper {
+ private static SAXParserFactory parserFactory = null;
+
+ protected Project project;
+ protected Object source;
+ protected File buildFile;
+ protected File buildFileParent;
+ private org.xml.sax.Parser parser;
+ private Locator locator;
+
+ /** Return a handler for project. This can be used by xml helpers to fallback to
+ the original behavior ( non-namespace aware ).
+ When the callback is received, if no namespaces are used ( or no
+ new attributes, etc ) then the easiest way to achieve backward compatibility
+ is to use the original.
+
+ A helper needs to call this method, which will switch the HandlerBase in
+ the SAX parser and return it to the original on
+
+ @experimental This is likely to change
+ */
+ public HandlerBase defaultProjectHandler( Project project,
+ org.xml.sax.Parser parser,
+ String tag, AttributeList attrs,
+ DocumentHandler parent )
+ throws SAXParseException
+ {
+ this.project=project;
+ this.parser=parser;
+ ProjectHandler h=new ProjectHandler(this, parent);
+ h.init( tag, attrs );
+ return h;
+ }
+
+ /**
+ * Parses the project file.
+ */
+ public void parse(Project project, Object source) throws BuildException {
+ if( ! (source instanceof File) )
+ throw new BuildException( "Only File source is supported by the default helper");
+
+ File buildFile=(File)source;
+ this.project = project;
+ this.buildFile = new File(buildFile.getAbsolutePath());
+ buildFileParent = new File(this.buildFile.getParent());
+
+ FileInputStream inputStream = null;
+ InputSource inputSource = null;
+
+ try {
+ SAXParser saxParser = getParserFactory().newSAXParser();
+ try {
+ parser = saxParser.getParser();
+ } catch (SAXException exc) {
+ parser = new XMLReaderAdapter(saxParser.getXMLReader());
+ }
+
+ String uri = "file:" + buildFile.getAbsolutePath().replace('\\', '/');
+ for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
+ uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
+ }
+
+ inputStream = new FileInputStream(buildFile);
+ inputSource = new InputSource(inputStream);
+ inputSource.setSystemId(uri);
+ project.log("parsing buildfile " + buildFile + " with URI = " + uri, Project.MSG_VERBOSE);
+
+ HandlerBase hb = new RootHandler(this);
+ parser.setDocumentHandler(hb);
+ parser.setEntityResolver(hb);
+ parser.setErrorHandler(hb);
+ parser.setDTDHandler(hb);
+ parser.parse(inputSource);
+ }
+ catch(ParserConfigurationException exc) {
+ throw new BuildException("Parser has not been configured correctly", exc);
+ }
+ catch(SAXParseException exc) {
+ Location location =
+ new Location(buildFile.toString(), exc.getLineNumber(), exc.getColumnNumber());
+
+ Throwable t = exc.getException();
+ if (t instanceof BuildException) {
+ BuildException be = (BuildException) t;
+ if (be.getLocation() == Location.UNKNOWN_LOCATION) {
+ be.setLocation(location);
+ }
+ throw be;
+ }
+
+ throw new BuildException(exc.getMessage(), t, location);
+ }
+ catch(SAXException exc) {
+ Throwable t = exc.getException();
+ if (t instanceof BuildException) {
+ throw (BuildException) t;
+ }
+ throw new BuildException(exc.getMessage(), t);
+ }
+ catch(FileNotFoundException exc) {
+ throw new BuildException(exc);
+ }
+ catch(IOException exc) {
+ throw new BuildException("Error reading project file", exc);
+ }
+ finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (IOException ioe) {
+ // ignore this
+ }
+ }
+ }
+ }
+
+ /**
+ * The common superclass for all sax event handlers in Ant. Basically
+ * throws an exception in each method, so subclasses should override
+ * what they can handle.
+ *
+ * Each type of xml element (task, target, etc) in ant will
+ * have its own subclass of AbstractHandler.
+ *
+ * In the constructor, this class takes over the handling of sax
+ * events from the parent handler, and returns
+ * control back to the parent in the endElement method.
+ */
+ private static class AbstractHandler extends HandlerBase {
+ protected DocumentHandler parentHandler;
+ protected ProjectHelperImpl helper;
+
+ public AbstractHandler(ProjectHelperImpl helper, DocumentHandler parentHandler) {
+ this.parentHandler = parentHandler;
+ this.helper=helper;
+
+ // Start handling SAX events
+ helper.parser.setDocumentHandler(this);
+ }
+
+ public void startElement(String tag, AttributeList attrs) throws SAXParseException {
+ throw new SAXParseException("Unexpected element \"" + tag + "\"", helper.locator);
+ }
+
+ public void characters(char[] buf, int start, int end) throws SAXParseException {
+ String s = new String(buf, start, end).trim();
+
+ if (s.length() > 0) {
+ throw new SAXParseException("Unexpected text \"" + s + "\"", helper.locator);
+ }
+ }
+
+ /**
+ * Called when this element and all elements nested into it have been
+ * handled.
+ */
+ protected void finished() {}
+
+ public void endElement(String name) throws SAXException {
+
+ finished();
+ // Let parent resume handling SAX events
+ helper.parser.setDocumentHandler(parentHandler);
+ }
+ }
+
+ /**
+ * Handler for the root element. It's only child must be the "project" element.
+ */
+ private static class RootHandler extends HandlerBase {
+ private ProjectHelperImpl helper;
+
+ public RootHandler( ProjectHelperImpl helper ) {
+ this.helper=helper;
+ }
+
+ /**
+ * resolve file: URIs as relative to the build file.
+ */
+ public InputSource resolveEntity(String publicId,
+ String systemId) {
+
+ helper.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
+
+ if (systemId.startsWith("file:")) {
+ String path = systemId.substring(5);
+ int index = path.indexOf("file:");
+
+ // we only have to handle these for backward compatibility
+ // since they are in the FAQ.
+ while (index != -1) {
+ path = path.substring(0, index) + path.substring(index + 5);
+ index = path.indexOf("file:");
+ }
+
+ String entitySystemId = path;
+ index = path.indexOf("%23");
+ // convert these to #
+ while (index != -1) {
+ path = path.substring(0, index) + "#" + path.substring(index + 3);
+ index = path.indexOf("%23");
+ }
+
+ File file = new File(path);
+ if (!file.isAbsolute()) {
+ file = new File(helper.buildFileParent, path);
+ }
+
+ try {
+ InputSource inputSource = new InputSource(new FileInputStream(file));
+ inputSource.setSystemId("file:" + entitySystemId);
+ return inputSource;
+ } catch (FileNotFoundException fne) {
+ helper.project.log(file.getAbsolutePath()+" could not be found",
+ Project.MSG_WARN);
+ }
+ }
+ // use default if not file or file not found
+ return null;
+ }
+
+ public void startElement(String tag, AttributeList attrs) throws SAXParseException {
+ if (tag.equals("project")) {
+ new ProjectHandler(helper, this).init(tag, attrs);
+ } else {
+ throw new SAXParseException("Config file is not of expected XML type", helper.locator);
+ }
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ helper.locator = locator;
+ }
+ }
+
+ /**
+ * Handler for the top level "project" element.
+ */
+ private static class ProjectHandler extends AbstractHandler {
+ public ProjectHandler(ProjectHelperImpl helper, DocumentHandler parentHandler) {
+ super(helper, parentHandler);
+ }
+
+ public void init(String tag, AttributeList attrs) throws SAXParseException {
+ String def = null;
+ String name = null;
+ String id = null;
+ String baseDir = null;
+
+ for (int i = 0; i < attrs.getLength(); i++) {
+ String key = attrs.getName(i);
+ String value = attrs.getValue(i);
+
+ if (key.equals("default")) {
+ def = value;
+ } else if (key.equals("name")) {
+ name = value;
+ } else if (key.equals("id")) {
+ id = value;
+ } else if (key.equals("basedir")) {
+ baseDir = value;
+ } else {
+ throw new SAXParseException("Unexpected attribute \"" + attrs.getName(i) + "\"", helper.locator);
+ }
+ }
+
+ if (def == null) {
+ throw new SAXParseException("The default attribute of project is required",
+ helper.locator);
+ }
+
+
+ helper.project.setDefaultTarget(def);
+
+ if (name != null) {
+ helper.project.setName(name);
+ helper.project.addReference(name, helper.project);
+ }
+
+ if (id != null) {
+ helper.project.addReference(id, helper.project);
+ }
+
+ if (helper.project.getProperty("basedir") != null) {
+ helper.project.setBasedir(helper.project.getProperty("basedir"));
+ } else {
+ if (baseDir == null) {
+ helper.project.setBasedir(helper.buildFileParent.getAbsolutePath());
+ } else {
+ // check whether the user has specified an absolute path
+ if ((new File(baseDir)).isAbsolute()) {
+ helper.project.setBasedir(baseDir);
+ } else {
+ helper.project.setBaseDir(helper.project.resolveFile(baseDir, helper.buildFileParent));
+ }
+ }
+ }
+
+ }
+
+ public void startElement(String name, AttributeList attrs) throws SAXParseException {
+ if (name.equals("taskdef")) {
+ handleTaskdef(name, attrs);
+ } else if (name.equals("typedef")) {
+ handleTypedef(name, attrs);
+ } else if (name.equals("property")) {
+ handleProperty(name, attrs);
+ } else if (name.equals("target")) {
+ handleTarget(name, attrs);
+ } else if (helper.project.getDataTypeDefinitions().get(name) != null) {
+ handleDataType(name, attrs);
+ } else {
+ throw new SAXParseException("Unexpected element \"" + name + "\"", helper.locator);
+ }
+ }
+
+ private void handleTaskdef(String name, AttributeList attrs) throws SAXParseException {
+ (new TaskHandler(helper, this, null, null, null)).init(name, attrs);
+ }
+
+ private void handleTypedef(String name, AttributeList attrs) throws SAXParseException {
+ (new TaskHandler(helper, this, null, null, null)).init(name, attrs);
+ }
+
+ private void handleProperty(String name, AttributeList attrs) throws SAXParseException {
+ (new TaskHandler(helper, this, null, null, null)).init(name, attrs);
+ }
+
+ private void handleTarget(String tag, AttributeList attrs) throws SAXParseException {
+ new TargetHandler(helper, this).init(tag, attrs);
+ }
+
+ private void handleDataType(String name, AttributeList attrs) throws SAXParseException {
+ new DataTypeHandler(helper, this).init(name, attrs);
+ }
+
+ }
+
+ /**
+ * Handler for "target" elements.
+ */
+ private static class TargetHandler extends AbstractHandler {
+ private Target target;
+
+ public TargetHandler(ProjectHelperImpl helper, DocumentHandler parentHandler) {
+ super(helper, parentHandler);
+ }
+
+ public void init(String tag, AttributeList attrs) throws SAXParseException {
+ String name = null;
+ String depends = "";
+ String ifCond = null;
+ String unlessCond = null;
+ String id = null;
+ String description = null;
+
+ for (int i = 0; i < attrs.getLength(); i++) {
+ String key = attrs.getName(i);
+ String value = attrs.getValue(i);
+
+ if (key.equals("name")) {
+ name = value;
+ } else if (key.equals("depends")) {
+ depends = value;
+ } else if (key.equals("if")) {
+ ifCond = value;
+ } else if (key.equals("unless")) {
+ unlessCond = value;
+ } else if (key.equals("id")) {
+ id = value;
+ } else if (key.equals("description")) {
+ description = value;
+ } else {
+ throw new SAXParseException("Unexpected attribute \"" + key + "\"", helper.locator);
+ }
+ }
+
+ if (name == null) {
+ throw new SAXParseException("target element appears without a name attribute", helper.locator);
+ }
+
+ target = new Target();
+ target.setName(name);
+ target.setIf(ifCond);
+ target.setUnless(unlessCond);
+ target.setDescription(description);
+ helper.project.addTarget(name, target);
+
+ if (id != null && !id.equals("")) {
+ helper.project.addReference(id, target);
+ }
+
+ // take care of dependencies
+
+ if (depends.length() > 0) {
+ target.setDepends(depends);
+ }
+ }
+
+ public void startElement(String name, AttributeList attrs) throws SAXParseException {
+ if (helper.project.getDataTypeDefinitions().get(name) != null) {
+ new DataTypeHandler(helper, this, target).init(name, attrs);
+ } else {
+ new TaskHandler(helper, this, target, null, target).init(name, attrs);
+ }
+ }
+ }
+
+ /**
+ * Handler for all task elements.
+ */
+ private static class TaskHandler extends AbstractHandler {
+ private Target target;
+ private TaskContainer container;
+ private Task task;
+ private RuntimeConfigurable parentWrapper;
+ private RuntimeConfigurable wrapper = null;
+
+ public TaskHandler(ProjectHelperImpl helper,
+ DocumentHandler parentHandler,
+ TaskContainer container,
+ RuntimeConfigurable parentWrapper,
+ Target target)
+ {
+ super(helper, parentHandler);
+ this.container = container;
+ this.parentWrapper = parentWrapper;
+ this.target = target;
+ }
+
+ public void init(String tag, AttributeList attrs) throws SAXParseException {
+ try {
+ task = helper.project.createTask(tag);
+ } catch (BuildException e) {
+ // swallow here, will be thrown again in
+ // UnknownElement.maybeConfigure if the problem persists.
+ }
+
+ if (task == null) {
+ task = new UnknownElement(tag);
+ task.setProject(helper.project);
+ task.setTaskType(tag);
+ task.setTaskName(tag);
+ }
+
+ task.setLocation(new Location(helper.buildFile.toString(),
+ helper.locator.getLineNumber(),
+ helper.locator.getColumnNumber()));
+ helper.configureId(task, attrs);
+
+ // Top level tasks don't have associated targets
+ if (target != null) {
+ task.setOwningTarget(target);
+ container.addTask(task);
+ task.init();
+ wrapper = task.getRuntimeConfigurableWrapper();
+ wrapper.setAttributes(attrs);
+ if (parentWrapper != null) {
+ parentWrapper.addChild(wrapper);
+ }
+ } else {
+ task.init();
+ configure(task, attrs, helper.project);
+ }
+ }
+
+ protected void finished() {
+ if (task != null && target == null) {
+ task.execute();
+ }
+ }
+
+ public void characters(char[] buf, int start, int end) throws SAXParseException {
+ if (wrapper == null) {
+ try {
+ addText(helper.project, task, buf, start, end);
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), helper.locator, exc);
+ }
+ } else {
+ wrapper.addText(buf, start, end);
+ }
+ }
+
+ public void startElement(String name, AttributeList attrs) throws SAXParseException {
+ if (task instanceof TaskContainer) {
+ // task can contain other tasks - no other nested elements possible
+ new TaskHandler(helper, this, (TaskContainer)task, wrapper, target).init(name, attrs);
+ }
+ else {
+ new NestedElementHandler(helper, this, task, wrapper, target).init(name, attrs);
+ }
+ }
+ }
+
+ /**
+ * Handler for all nested properties.
+ */
+ private static class NestedElementHandler extends AbstractHandler {
+ private Object parent;
+ private Object child;
+ private RuntimeConfigurable parentWrapper;
+ private RuntimeConfigurable childWrapper = null;
+ private TaskAdapter adapter=null;
+ private Target target;
+
+ public NestedElementHandler(ProjectHelperImpl helper,
+ DocumentHandler parentHandler,
+ Object parent,
+ RuntimeConfigurable parentWrapper,
+ Target target) {
+ super(helper, parentHandler);
+
+ if (parent instanceof TaskAdapter) {
+ this.adapter= (TaskAdapter)parent;
+ this.parent = adapter.getProxy();
+ } else {
+ this.parent = parent;
+ }
+ this.parentWrapper = parentWrapper;
+ this.target = target;
+ }
+
+ public void init(String propType, AttributeList attrs) throws SAXParseException {
+ Class parentClass = parent.getClass();
+ IntrospectionHelper ih =
+ IntrospectionHelper.getHelper(parentClass);
+ if( adapter!=null ) {
+ adapter.setIntrospectionHelper( ih );
+ }
+
+ try {
+ String elementName = propType.toLowerCase(Locale.US);
+ if (parent instanceof UnknownElement) {
+ UnknownElement uc = new UnknownElement(elementName);
+ uc.setProject(helper.project);
+ ((UnknownElement) parent).addChild(uc);
+ child = uc;
+ } else {
+ child = ih.createElement(helper.project, parent, elementName);
+ }
+
+ helper.configureId(child, attrs);
+
+ if (parentWrapper != null) {
+ childWrapper = new RuntimeConfigurable(child, propType);
+ childWrapper.setAttributes(attrs);
+ parentWrapper.addChild(childWrapper);
+ } else {
+ configure(child, attrs, helper.project);
+ ih.storeElement(helper.project, parent, child, elementName);
+ }
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), helper.locator, exc);
+ }
+ }
+
+ public void characters(char[] buf, int start, int end) throws SAXParseException {
+ if (parentWrapper == null) {
+ try {
+ addText(helper.project, child, buf, start, end);
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), helper.locator, exc);
+ }
+ } else {
+ childWrapper.addText(buf, start, end);
+ }
+ }
+
+ public void startElement(String name, AttributeList attrs) throws SAXParseException {
+ if (child instanceof TaskContainer) {
+ // taskcontainer nested element can contain other tasks - no other
+ // nested elements possible
+ new TaskHandler(helper, this, (TaskContainer)child, childWrapper, target).init(name, attrs);
+ }
+ else {
+ new NestedElementHandler(helper, this, child, childWrapper, target).init(name, attrs);
+ }
+ }
+ }
+
+ /**
+ * Handler for all data types at global level.
+ */
+ private static class DataTypeHandler extends AbstractHandler {
+ private Target target;
+ private Object element;
+ private RuntimeConfigurable wrapper = null;
+
+ public DataTypeHandler(ProjectHelperImpl helper, DocumentHandler parentHandler) {
+ this(helper, parentHandler, null);
+ }
+
+ public DataTypeHandler(ProjectHelperImpl helper,
+ DocumentHandler parentHandler,
+ Target target)
+ {
+ super(helper, parentHandler);
+ this.target = target;
+ }
+
+ public void init(String propType, AttributeList attrs) throws SAXParseException {
+ try {
+ element = helper.project.createDataType(propType);
+ if (element == null) {
+ throw new BuildException("Unknown data type "+propType);
+ }
+
+ if (target != null) {
+ wrapper = new RuntimeConfigurable(element, propType);
+ wrapper.setAttributes(attrs);
+ target.addDataType(wrapper);
+ } else {
+ configure(element, attrs, helper.project);
+ helper.configureId(element, attrs);
+ }
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), helper.locator, exc);
+ }
+ }
+
+ public void characters(char[] buf, int start, int end) throws SAXParseException {
+ try {
+ addText(helper.project, element, buf, start, end);
+ } catch (BuildException exc) {
+ throw new SAXParseException(exc.getMessage(), helper.locator, exc);
+ }
+ }
+
+ public void startElement(String name, AttributeList attrs) throws SAXParseException {
+ new NestedElementHandler(helper, this, element, wrapper, target).init(name, attrs);
+ }
+ }
+
+ public ProjectHelperImpl() {
+ }
+
+ private static SAXParserFactory getParserFactory() {
+ if (parserFactory == null) {
+ parserFactory = SAXParserFactory.newInstance();
+ }
+
+ return parserFactory;
+ }
+
+ /**
+ * Scan AttributeList for the id attribute and maybe add a
+ * reference to project.
+ *
+ * Moved out of {@link #configure configure} to make it happen
+ * at parser time.
+ */
+ private void configureId(Object target, AttributeList attr) {
+ String id = attr.getValue("id");
+ if (id != null) {
+ project.addReference(id, target);
+ }
+ }
+
+}
diff --git a/proposal/sandbox/embed/README b/proposal/sandbox/embed/README
new file mode 100644
index 000000000..35782ee72
--- /dev/null
+++ b/proposal/sandbox/embed/README
@@ -0,0 +1,2 @@
+Copy the files in o.a.t.ant, recompile.
+
diff --git a/proposal/sandbox/embed/TaskAdapter.java b/proposal/sandbox/embed/TaskAdapter.java
new file mode 100644
index 000000000..5a6dad92c
--- /dev/null
+++ b/proposal/sandbox/embed/TaskAdapter.java
@@ -0,0 +1,214 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.tools.ant;
+
+import java.lang.reflect.Method;
+
+
+
+/**
+ * Use introspection to "adapt" an arbitrary Bean ( not extending Task, but with similar
+ * patterns).
+ *
+ * The adapter can also be used to wrap tasks that are loaded in a different class loader
+ * by ant, when used in programatic mode.
+ *
+ * @author Costin Manolache
+ */
+public class TaskAdapter extends Task {
+
+ private Object proxy;
+ private String methodName="execute";
+
+ /**
+ * Checks a class, whether it is suitable to be adapted by TaskAdapter.
+ *
+ * Checks conditions only, which are additionally required for a tasks
+ * adapted by TaskAdapter. Thus, this method should be called by
+ * {@link Project#checkTaskClass}.
+ *
+ * Throws a BuildException and logs as Project.MSG_ERR for
+ * conditions, that will cause the task execution to fail.
+ * Logs other suspicious conditions with Project.MSG_WARN.
+ */
+ public static void checkTaskClass(final Class taskClass, final Project project) {
+ // Any task can be used via adapter. If it doesn't have any execute()
+ // method, no problem - it will do nothing, but still get an 'id'
+ // and be registered in the project reference table and useable by other
+ // tasks.
+
+ if( true )
+ return;
+
+ // don't have to check for interface, since then
+ // taskClass would be abstract too.
+ try {
+ final Method executeM = taskClass.getMethod( "execute", null );
+ // don't have to check for public, since
+ // getMethod finds public method only.
+ // don't have to check for abstract, since then
+ // taskClass would be abstract too.
+ if(!Void.TYPE.equals(executeM.getReturnType())) {
+ final String message =
+ "return type of execute() should be void but was \""+
+ executeM.getReturnType()+"\" in " + taskClass;
+ project.log(message, Project.MSG_WARN);
+ }
+ } catch(NoSuchMethodException e) {
+ final String message = "No public execute() in " + taskClass;
+ project.log(message, Project.MSG_ERR);
+ throw new BuildException(message);
+ }
+ }
+
+ private IntrospectionHelper ih;
+
+ void setIntrospectionHelper( IntrospectionHelper ih ) {
+ this.ih=ih;
+ }
+
+ IntrospectionHelper getIntrospectionHelper() {
+ if( ih==null ) {
+ ih = IntrospectionHelper.getHelper(target.getClass());
+ }
+ return ih;
+ }
+
+ /** Experimental, non-public method for better 'adaptation'
+ *
+ */
+ void setAttribute( String name, String value )
+ throws BuildException
+ {
+ try {
+ ih.setAttribute( project, proxy, name, value );
+ } catch( BuildException ex ) {
+ if( "do".equals( name ) ) {
+ setDo( value );
+ } else {
+ throw ex;
+ }
+ }
+ }
+
+ /** Set the 'action' method. This allow beans implementing multiple
+ * actions or using methods other than 'execute()' to be used in ant
+ * without any modification.
+ *
+ * @ant:experimental
+ */
+ public void setDo(String methodName ) {
+ this.methodName=methodName;
+ }
+
+ /**
+ * Do the execution.
+ */
+ public void execute() throws BuildException {
+ Method setProjectM = null;
+ try {
+ Class c = proxy.getClass();
+ setProjectM =
+ c.getMethod( "setProject", new Class[] {Project.class});
+ if(setProjectM != null) {
+ setProjectM.invoke(proxy, new Object[] {project});
+ }
+ } catch (NoSuchMethodException e) {
+ // ignore this if the class being used as a task does not have
+ // a set project method.
+ } catch( Exception ex ) {
+ log("Error setting project in " + proxy.getClass(),
+ Project.MSG_ERR);
+ throw new BuildException( ex );
+ }
+
+
+ Method executeM=null;
+ try {
+ Class c=proxy.getClass();
+ executeM=c.getMethod( methodName, new Class[0] );
+ if( executeM == null ) {
+ log("No public " + methodName + "() in " + proxy.getClass(), Project.MSG_ERR);
+ throw new BuildException("No public " + methodName +"() in " + proxy.getClass());
+ }
+ executeM.invoke(proxy, null);
+ return;
+ } catch (java.lang.reflect.InvocationTargetException ie) {
+ log("Error in " + proxy.getClass(), Project.MSG_ERR);
+ Throwable t = ie.getTargetException();
+ if (t instanceof BuildException) {
+ throw ((BuildException) t);
+ } else {
+ throw new BuildException(t);
+ }
+ } catch( Exception ex ) {
+ log("Error in " + proxy.getClass(), Project.MSG_ERR);
+ throw new BuildException( ex );
+ }
+
+ }
+
+ /**
+ * Set the target object class
+ */
+ public void setProxy(Object o) {
+ this.proxy = o;
+ }
+
+ public Object getProxy() {
+ return this.proxy ;
+ }
+
+}