git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@819284 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -174,6 +174,11 @@ Changes that could break older environments: | |||
| (i.e. in a very unlikely event) then the new syntax would yield a | |||
| different result (an expanded property) than Ant 1.7.1 did. | |||
| * A ProjectHelper implementation can now provide the default build file | |||
| name it is expecting, and can specify if they can support a specific build | |||
| file. So Ant is now capable of supporting several ProjectHelper | |||
| implementations, deciding on which to use depending of the input build file. | |||
| Fixed bugs: | |||
| ----------- | |||
| @@ -37,6 +37,7 @@ | |||
| <a href="develop.html#integration">Source-code Integration</a><br/> | |||
| <a href="inputhandler.html">InputHandler</a><br/> | |||
| <a href="antexternal.html">Using Ant Tasks Outside of Ant</a><br/> | |||
| <a href="projecthelper.html">The Ant frontend: ProjectHelper</a><br/> | |||
| <br/>Tutorials<br/> | |||
| <a href="tutorial-HelloWorldWithAnt.html">Hello World with Ant</a><br/> | |||
| @@ -0,0 +1,131 @@ | |||
| <!-- | |||
| Licensed to the Apache Software Foundation (ASF) under one or more | |||
| contributor license agreements. See the NOTICE file distributed with | |||
| this work for additional information regarding copyright ownership. | |||
| The ASF licenses this file to You under the Apache License, Version 2.0 | |||
| (the "License"); you may not use this file except in compliance with | |||
| the License. You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| --> | |||
| <html> | |||
| <head> | |||
| <meta http-equiv="Content-Language" content="en-us"> | |||
| <link rel="stylesheet" type="text/css" href="stylesheets/style.css"> | |||
| <title>The Ant frontend: ProjectHelper</title> | |||
| </head> | |||
| <body> | |||
| <h1>The Ant frontend: ProjectHelper</h1> | |||
| <h2><a name="definition">What is a ProjectHelper?</a></h2> | |||
| <p> | |||
| The <code>ProjectHelper</code> in Ant is responsible to parse the build file | |||
| and create java instances representing the build workflow. It also declares which | |||
| kind of file it can parse, and which file name it expects as default input file. | |||
| </p> | |||
| <p> | |||
| So in Ant there is a default <code>ProjectHelper</code> | |||
| (<code>org.apache.tools.ant.helper.ProjectHelper2</code>) which will parse the | |||
| usual build.xml files. And if no build file is specified on the command line, it | |||
| will expect to find a build.xml file. | |||
| </p> | |||
| <p> | |||
| The immediate benefit of a such abstraction it that it is possible to make Ant | |||
| understand other kind of descriptive language than XML. Some experiment have | |||
| been done around a pure java frontend, and a groovy one too (ask the dev mailing | |||
| list for further info about these). | |||
| </p> | |||
| <h2><a name="repository">How is Ant is selecting the proper ProjectHelper</a></h2> | |||
| <p> | |||
| Ant can now know about several implementations of <code>ProjectHelper</code> | |||
| and have to decide which to use for each build file. | |||
| </p> | |||
| <p>So Ant at startup will list the found implementations and will keep it | |||
| ordered as it finds them in an internal 'repository': | |||
| <ul> | |||
| <li>the first to be searched for is the one declared by the system property | |||
| <code>org.apache.tools.ant.ProjectHelper</code> (see | |||
| <a href="running.html#sysprops">Java System Properties</a>);</li> | |||
| <li>then it searches with its class loader for a <code>ProjectHelper</code> | |||
| service declarations in the META-INF: it searches in the classpath for a | |||
| file <code>META-INF/services/org.apache.tools.ant.ProjectHelper</code>. | |||
| This file will just contain the fully qualified name of the | |||
| implementation of <code>ProjectHelper</code> to instanciate;</li> | |||
| <li>it will also search with the system class loader for | |||
| <code>ProjectHelper</code> service declarations in the META-INF;</li> | |||
| <li>last but not least it will add its default <code>ProjectHelper</code> | |||
| that can parse classical build.xml files.</li> | |||
| </ul> | |||
| In case of error while trying to instanciate a <code>ProjectHelper</code>, Ant | |||
| will log an error but still won't stop. If you want further debugging | |||
| info about the <code>ProjectHelper</code> internal 'repository', use the system | |||
| property <code>ant.project-helper-repo.debug</code> and set it to | |||
| <code>true</code>; the full stack trace will then also be printed. | |||
| </p> | |||
| <p> | |||
| Then when Ant is expected to parse a file, it will ask the | |||
| <code>ProjectHelper</code> repository to found an implementation that will be | |||
| able to parse the input file. Actually it will just iterate on the ordered list | |||
| and the first implementation that returns <code>true</code> to | |||
| <code>supportsBuildFile(File buildFile)</code> will be selected. | |||
| </p> | |||
| <p> | |||
| And when Ant is launching and there is no input file specified, it will search for | |||
| a default input file. It will iterate on the list of <code>ProjectHelper</code> | |||
| and will select the first one that expects a default file that actually exist. | |||
| </p> | |||
| <h2><a name="writing">Writing your own ProjectHelper</a></h2> | |||
| <p> | |||
| The class <code>org.apache.tools.ant.ProjectHelper</code> is the API expected to | |||
| be implemented. So write your own <code>ProjectHelper</code> by extending that | |||
| abstract class. You are then expected to implement at least the function | |||
| <code>parse(Project project, Object source)</code>. Note also that your | |||
| implementation will be instanciated by Ant, and it is expecting a default | |||
| constructor with no arguments. | |||
| </p> | |||
| <p> | |||
| Then there are some functions that will help you define what your helper is | |||
| capable of and what is is expecting: | |||
| <ul> | |||
| <li><code>getDefaultBuildFile()</code>: defines which file name is expected if | |||
| none provided</li> | |||
| <li><code>supportsBuildFile(File buildFile)</code>: defines if your parser | |||
| can parse the input file</li> | |||
| </ul> | |||
| </p> | |||
| <p> | |||
| Now that you have your implementation ready, you have to declare it to Ant. Two | |||
| solutions here: | |||
| <ul> | |||
| <li>use the system property <code>org.apache.tools.ant.ProjectHelper</code> | |||
| (see also the <a href="running.html#sysprops">Java System Properties</a>);</li> | |||
| <li>use the service file in META-INF: in the jar you will build with your | |||
| implementation, add a file | |||
| <code>META-INF/services/org.apache.tools.ant.ProjectHelper</code>. | |||
| And then in this file just put the fully qualified name of your | |||
| implementation</li> | |||
| </ul> | |||
| </p> | |||
| </body> | |||
| </html> | |||
| @@ -415,7 +415,6 @@ org.apache.tools.ant.Executor implementation specified here. | |||
| <td>see <a href="sysclasspath.html">its dedicated page</a>, no | |||
| default value</td> | |||
| <td>see <a href="sysclasspath.html">its dedicated page</a></td> | |||
| </td> | |||
| </tr> | |||
| <tr> | |||
| <td><code>file.encoding</code></td> | |||
| @@ -455,18 +454,25 @@ org.apache.tools.ant.Executor implementation specified here. | |||
| </td> | |||
| </tr> | |||
| <tr> | |||
| <td><code>websphere.home | |||
| <td><code>websphere.home</code></td> | |||
| <td>path</td> | |||
| <td>Points to home directory of websphere. | |||
| see <a href="OptionalTasks/ejb.html#ejbjar_websphere">EJB Tasks</a> | |||
| </td> | |||
| </tr> | |||
| <tr> | |||
| <td><code>XmlLogger.file | |||
| <td><code>XmlLogger.file</code></td> | |||
| <td>filename (default 'log.xml')</td> | |||
| <td>Name for the logfile for <a href="listeners.html#MailLogger">MailLogger</a>. | |||
| </td> | |||
| </tr> | |||
| <tr> | |||
| <td><code>ant.project-helper-repo.debug</code></td> | |||
| <td>boolean (default 'false')</td> | |||
| <td>Set it to true to enable debuging with Ant's | |||
| <a href="projecthelper.html#repository">ProjectHelper internal repository</a>. | |||
| </td> | |||
| </tr> | |||
| </table> | |||
| <p> | |||
| @@ -529,7 +535,7 @@ have some documentation inside.</p> | |||
| Unix(-like) systems</a></h2> | |||
| <p>If you start Ant as a background process (like in <code>ant | |||
| &</code>) and the build process creates another process, Ant will | |||
| &</code>) and the build process creates another process, Ant will | |||
| immediately try to read from standard input, which in turn will | |||
| most likely suspend the process. In order to avoid this, you must | |||
| redirect Ant's standard input or explicitly provide input to each | |||
| @@ -20,6 +20,7 @@ package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| @@ -301,6 +302,7 @@ public class Main implements AntMain { | |||
| */ | |||
| private void processArgs(String[] args) { | |||
| String searchForThis = null; | |||
| boolean searchForFile = false; | |||
| PrintStream logTo = null; | |||
| // cycle through given args | |||
| @@ -359,11 +361,10 @@ public class Main implements AntMain { | |||
| // set the flag to display the targets and quit | |||
| projectHelp = true; | |||
| } else if (arg.equals("-find") || arg.equals("-s")) { | |||
| searchForFile = true; | |||
| // eat up next arg if present, default to build.xml | |||
| if (i < args.length - 1) { | |||
| searchForThis = args[++i]; | |||
| } else { | |||
| searchForThis = DEFAULT_BUILD_FILENAME; | |||
| } | |||
| } else if (arg.startsWith("-propertyfile")) { | |||
| i = handleArgPropertyFile(args, i); | |||
| @@ -411,11 +412,37 @@ public class Main implements AntMain { | |||
| // 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); | |||
| if (searchForFile) { | |||
| if (searchForThis != null) { | |||
| buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis); | |||
| if (buildFile == null) { | |||
| throw new BuildException("Could not locate a build file!"); | |||
| } | |||
| } else { | |||
| // no search file specified: so search an existing default file | |||
| Iterator it = ProjectHelperRepository.getInstance().getHelpers(); | |||
| do { | |||
| ProjectHelper helper = (ProjectHelper) it.next(); | |||
| searchForThis = helper.getDefaultBuildFile(); | |||
| if (msgOutputLevel >= Project.MSG_VERBOSE) { | |||
| System.out.println("Searching the default build file: " + searchForThis); | |||
| } | |||
| buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis); | |||
| } while (buildFile == null && it.hasNext()); | |||
| if (buildFile == null) { | |||
| throw new BuildException("Could not locate a build file!"); | |||
| } | |||
| } | |||
| } else { | |||
| buildFile = new File(DEFAULT_BUILD_FILENAME); | |||
| // no build file specified: so search an existing default file | |||
| Iterator it = ProjectHelperRepository.getInstance().getHelpers(); | |||
| do { | |||
| ProjectHelper helper = (ProjectHelper) it.next(); | |||
| buildFile = new File(helper.getDefaultBuildFile()); | |||
| if (msgOutputLevel >= Project.MSG_VERBOSE) { | |||
| System.out.println("Trying the default build file: " + buildFile); | |||
| } | |||
| } while (!buildFile.exists() && it.hasNext()); | |||
| } | |||
| } | |||
| @@ -633,20 +660,17 @@ public class Main implements AntMain { | |||
| * <p> | |||
| * Takes the given target as a suffix to append to each | |||
| * parent directory in search of a build file. Once the | |||
| * root of the file-system has been reached an exception | |||
| * is thrown. | |||
| * root of the file-system has been reached <code>null</code> | |||
| * is returned. | |||
| * | |||
| * @param start Leaf directory of search. | |||
| * Must not be <code>null</code>. | |||
| * @param suffix Suffix filename to look for in parents. | |||
| * Must not be <code>null</code>. | |||
| * | |||
| * @return A handle to the build file if one is found | |||
| * | |||
| * @exception BuildException if no build file is found | |||
| * @return A handle to the build file if one is found, <code>null</code> if not | |||
| */ | |||
| private File findBuildFile(String start, String suffix) | |||
| throws BuildException { | |||
| private File findBuildFile(String start, String suffix) { | |||
| if (msgOutputLevel >= Project.MSG_INFO) { | |||
| System.out.println("Searching for " + suffix + " ..."); | |||
| } | |||
| @@ -662,7 +686,7 @@ public class Main implements AntMain { | |||
| // 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!"); | |||
| return null; | |||
| } | |||
| // refresh our file handle | |||
| @@ -17,37 +17,21 @@ | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.net.URL; | |||
| import java.util.Hashtable; | |||
| import java.util.Locale; | |||
| import java.util.Vector; | |||
| import org.xml.sax.AttributeList; | |||
| import org.apache.tools.ant.helper.ProjectHelper2; | |||
| import org.apache.tools.ant.util.LoaderUtils; | |||
| 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. | |||
| * | |||
| * a build file. It'll rely on a plugin to do the actual processing | |||
| * of the file. | |||
| * <p> | |||
| * This class also provide static wrappers for common introspection. | |||
| * | |||
| * All helper plugins must provide backward compatibility with the | |||
| * original ant patterns, unless a different behavior is explicitly | |||
| * specified. For example, if namespace is used on the <project> 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. | |||
| * | |||
| */ | |||
| public class ProjectHelper { | |||
| /** The URI for ant name space */ | |||
| @@ -89,7 +73,7 @@ public class ProjectHelper { | |||
| * @exception BuildException if the configuration is invalid or cannot be read | |||
| */ | |||
| public static void configureProject(Project project, File buildFile) throws BuildException { | |||
| ProjectHelper helper = ProjectHelper.getProjectHelper(); | |||
| ProjectHelper helper = ProjectHelperRepository.getInstance().getProjectHelper(buildFile); | |||
| project.addReference(PROJECTHELPER_REFERENCE, helper); | |||
| helper.parse(project, buildFile); | |||
| } | |||
| @@ -224,103 +208,13 @@ public class ProjectHelper { | |||
| } | |||
| /** | |||
| * Discovers a project helper instance. Uses the same patterns | |||
| * as JAXP, commons-logging, etc: a system property, a JDK1.3 | |||
| * service discovery, default. | |||
| * | |||
| * @return a ProjectHelper, either a custom implementation | |||
| * if one is available and configured, or the default implementation | |||
| * otherwise. | |||
| * | |||
| * @exception BuildException if a specified helper class cannot | |||
| * be loaded/instantiated. | |||
| */ | |||
| public static ProjectHelper getProjectHelper() throws BuildException { | |||
| // Identify the class loader we will be using. Ant may be | |||
| // in a webapp or embedded in a different app | |||
| ProjectHelper helper = null; | |||
| // First, try the system property | |||
| String helperClass = System.getProperty(HELPER_PROPERTY); | |||
| try { | |||
| if (helperClass != null) { | |||
| helper = newHelper(helperClass); | |||
| } | |||
| } catch (SecurityException e) { | |||
| System.out.println("Unable to load ProjectHelper class \"" | |||
| + helperClass + " specified in system property " | |||
| + HELPER_PROPERTY); | |||
| } | |||
| // 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 { | |||
| ClassLoader classLoader = LoaderUtils.getContextClassLoader(); | |||
| InputStream is = null; | |||
| if (classLoader != null) { | |||
| is = classLoader.getResourceAsStream(SERVICE_ID); | |||
| } | |||
| if (is == null) { | |||
| is = ClassLoader.getSystemResourceAsStream(SERVICE_ID); | |||
| } | |||
| if (is != null) { | |||
| // This code is needed by EBCDIC and other strange systems. | |||
| // It's a fix for bugs reported in xerces | |||
| InputStreamReader isr; | |||
| try { | |||
| isr = new InputStreamReader(is, "UTF-8"); | |||
| } catch (java.io.UnsupportedEncodingException e) { | |||
| isr = new InputStreamReader(is); | |||
| } | |||
| BufferedReader rd = new BufferedReader(isr); | |||
| String helperClassName = rd.readLine(); | |||
| rd.close(); | |||
| if (helperClassName != null && !"".equals(helperClassName)) { | |||
| helper = newHelper(helperClassName); | |||
| } | |||
| } | |||
| } catch (Exception ex) { | |||
| System.out.println("Unable to load ProjectHelper from service " + SERVICE_ID); | |||
| } | |||
| } | |||
| return helper == null ? new ProjectHelper2() : helper; | |||
| } | |||
| /** | |||
| * Creates a new helper instance from the name of the class. | |||
| * It'll first try the thread class loader, then Class.forName() | |||
| * will load from the same loader that loaded this class. | |||
| * | |||
| * @param helperClass The name of the class to create an instance | |||
| * of. Must not be <code>null</code>. | |||
| * | |||
| * @return a new instance of the specified class. | |||
| * | |||
| * @exception BuildException if the class cannot be found or | |||
| * cannot be appropriate instantiated. | |||
| * Get the first project helper found in the classpath | |||
| * | |||
| * @return an project helper, never <code>null</code> | |||
| * @see #getHelpers() | |||
| */ | |||
| private static ProjectHelper newHelper(String helperClass) | |||
| throws BuildException { | |||
| ClassLoader classLoader = LoaderUtils.getContextClassLoader(); | |||
| try { | |||
| Class clazz = null; | |||
| if (classLoader != null) { | |||
| try { | |||
| clazz = classLoader.loadClass(helperClass); | |||
| } catch (ClassNotFoundException ex) { | |||
| // try next method | |||
| } | |||
| } | |||
| if (clazz == null) { | |||
| clazz = Class.forName(helperClass); | |||
| } | |||
| return ((ProjectHelper) clazz.newInstance()); | |||
| } catch (Exception e) { | |||
| throw new BuildException(e); | |||
| } | |||
| public static ProjectHelper getProjectHelper() { | |||
| return (ProjectHelper) ProjectHelperRepository.getInstance().getHelpers().next(); | |||
| } | |||
| /** | |||
| @@ -618,4 +512,27 @@ public class ProjectHelper { | |||
| URL source) { | |||
| throw new BuildException("can't parse antlib descriptors"); | |||
| } | |||
| /** | |||
| * Check if the helper supports the kind of file. Some basic check on the | |||
| * extension's file should be done here. | |||
| * | |||
| * @param buildFile | |||
| * the file expected to be parsed (never <code>null</code>) | |||
| * @return true if the helper supports it | |||
| * @since Ant 1.8.0 | |||
| */ | |||
| public boolean supportsBuildFile(File buildFile) { | |||
| return true; | |||
| } | |||
| /** | |||
| * The file name of the build script to be parsed if none specified on the command line | |||
| * | |||
| * @return the name of the default file (never <code>null</code>) | |||
| * @since Ant 1.8.0 | |||
| */ | |||
| public String getDefaultBuildFile() { | |||
| return Main.DEFAULT_BUILD_FILENAME; | |||
| } | |||
| } | |||
| @@ -0,0 +1,203 @@ | |||
| package org.apache.tools.ant; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.net.URL; | |||
| import java.util.ArrayList; | |||
| import java.util.Enumeration; | |||
| import java.util.Iterator; | |||
| import java.util.List; | |||
| import org.apache.tools.ant.helper.ProjectHelper2; | |||
| import org.apache.tools.ant.util.LoaderUtils; | |||
| /** | |||
| * Repository of {@link ProjectHelper} found in the classpath or via some System | |||
| * properties. | |||
| * <p> | |||
| * See the ProjectHelper documentation in the manual. | |||
| * | |||
| * @since Ant 1.8.0 | |||
| */ | |||
| public class ProjectHelperRepository { | |||
| private static final String DEBUG_PROJECT_HELPER_REPOSITORY = "ant.project-helper-repo.debug"; | |||
| // The message log level is not accessible here because everything is instanciated statically | |||
| private static final boolean DEBUG = "true".equals(System.getProperty(DEBUG_PROJECT_HELPER_REPOSITORY)); | |||
| private static ProjectHelperRepository instance = new ProjectHelperRepository(); | |||
| private List/* <ProjectHelper> */helpers = new ArrayList(); | |||
| public static ProjectHelperRepository getInstance() { | |||
| return instance; | |||
| } | |||
| private ProjectHelperRepository() { | |||
| collectProjectHelpers(); | |||
| } | |||
| private void collectProjectHelpers() { | |||
| // First, try the system property | |||
| ProjectHelper projectHelper = getProjectHelperBySystemProperty(); | |||
| registerProjectHelper(projectHelper); | |||
| // A JDK1.3 'service' ( like in JAXP ). That will plug a helper | |||
| // automatically if in CLASSPATH, with the right META-INF/services. | |||
| try { | |||
| ClassLoader classLoader = LoaderUtils.getContextClassLoader(); | |||
| if (classLoader != null) { | |||
| Enumeration resources = classLoader.getResources(ProjectHelper.SERVICE_ID); | |||
| while (resources.hasMoreElements()) { | |||
| URL resource = (URL) resources.nextElement(); | |||
| projectHelper = getProjectHelperBySerice(resource.openStream()); | |||
| registerProjectHelper(projectHelper); | |||
| } | |||
| } | |||
| InputStream systemResource = ClassLoader.getSystemResourceAsStream(ProjectHelper.SERVICE_ID); | |||
| if (systemResource != null) { | |||
| projectHelper = getProjectHelperBySerice(systemResource); | |||
| registerProjectHelper(projectHelper); | |||
| } | |||
| } catch (Exception e) { | |||
| System.err.println("Unable to load ProjectHelper from service " | |||
| + ProjectHelper.SERVICE_ID + " (" + e.getClass().getName() + ": " | |||
| + e.getMessage() + ")"); | |||
| if (DEBUG) { | |||
| e.printStackTrace(System.err); | |||
| } | |||
| } | |||
| // last but not least, ant default project helper | |||
| projectHelper = new ProjectHelper2(); | |||
| registerProjectHelper(projectHelper); | |||
| } | |||
| private void registerProjectHelper(ProjectHelper projectHelper) { | |||
| if (projectHelper == null) { | |||
| return; | |||
| } | |||
| if (DEBUG) { | |||
| System.out.println("ProjectHelper " + | |||
| projectHelper.getClass().getName() + " registered."); | |||
| } | |||
| helpers.add(projectHelper); | |||
| } | |||
| private ProjectHelper getProjectHelperBySystemProperty() { | |||
| String helperClass = System.getProperty(ProjectHelper.HELPER_PROPERTY); | |||
| try { | |||
| if (helperClass != null) { | |||
| return newHelper(helperClass); | |||
| } | |||
| } catch (SecurityException e) { | |||
| System.err.println("Unable to load ProjectHelper class \"" | |||
| + helperClass + " specified in system property " | |||
| + ProjectHelper.HELPER_PROPERTY + " (" + e.getMessage() + ")"); | |||
| if (DEBUG) { | |||
| e.printStackTrace(System.err); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private ProjectHelper getProjectHelperBySerice(InputStream is) { | |||
| try { | |||
| // This code is needed by EBCDIC and other strange systems. | |||
| // It's a fix for bugs reported in xerces | |||
| InputStreamReader isr; | |||
| try { | |||
| isr = new InputStreamReader(is, "UTF-8"); | |||
| } catch (java.io.UnsupportedEncodingException e) { | |||
| isr = new InputStreamReader(is); | |||
| } | |||
| BufferedReader rd = new BufferedReader(isr); | |||
| String helperClassName = rd.readLine(); | |||
| rd.close(); | |||
| if (helperClassName != null && !"".equals(helperClassName)) { | |||
| return newHelper(helperClassName); | |||
| } | |||
| } catch (Exception e) { | |||
| System.out.println("Unable to load ProjectHelper from service " | |||
| + ProjectHelper.SERVICE_ID + " (" + e.getMessage() + ")"); | |||
| if (DEBUG) { | |||
| e.printStackTrace(System.err); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * Creates a new helper instance from the name of the class. It'll first try | |||
| * the thread class loader, then Class.forName() will load from the same | |||
| * loader that loaded this class. | |||
| * | |||
| * @param helperClass | |||
| * The name of the class to create an instance of. Must not be | |||
| * <code>null</code>. | |||
| * | |||
| * @return a new instance of the specified class. | |||
| * | |||
| * @exception BuildException | |||
| * if the class cannot be found or cannot be appropriate | |||
| * instantiated. | |||
| */ | |||
| private ProjectHelper newHelper(String helperClass) throws BuildException { | |||
| ClassLoader classLoader = LoaderUtils.getContextClassLoader(); | |||
| try { | |||
| Class clazz = null; | |||
| if (classLoader != null) { | |||
| try { | |||
| clazz = classLoader.loadClass(helperClass); | |||
| } catch (ClassNotFoundException ex) { | |||
| // try next method | |||
| } | |||
| } | |||
| if (clazz == null) { | |||
| clazz = Class.forName(helperClass); | |||
| } | |||
| return ((ProjectHelper) clazz.newInstance()); | |||
| } catch (Exception e) { | |||
| throw new BuildException(e); | |||
| } | |||
| } | |||
| /** | |||
| * Get the helper that will be able to parse the specified file. The helper | |||
| * will be chosen among the ones found in the classpath | |||
| * | |||
| * @return the first ProjectHelper that fit the requirement (never <code>null</code>). | |||
| */ | |||
| public ProjectHelper getProjectHelper(File buildFile) throws BuildException { | |||
| Iterator it = helpers.iterator(); | |||
| while (it.hasNext()) { | |||
| ProjectHelper helper = (ProjectHelper) it.next(); | |||
| if (helper.supportsBuildFile(buildFile)) { | |||
| if (DEBUG) { | |||
| System.out.println("ProjectHelper " | |||
| + helper.getClass().getName() + " selected for the file " | |||
| + buildFile); | |||
| } | |||
| return helper; | |||
| } | |||
| } | |||
| throw new RuntimeException("BUG: at least the ProjectHelper2 should have supported the file " + buildFile); | |||
| } | |||
| /** | |||
| * Get an iterator on the list of project helpers configured. The iterator | |||
| * will always return at least one element as there will always be the | |||
| * default project helper configured. | |||
| * | |||
| * @return an iterator of {@link ProjectHelper} | |||
| */ | |||
| public Iterator getHelpers() { | |||
| return helpers.iterator(); | |||
| } | |||
| } | |||
| @@ -359,7 +359,7 @@ public class Ant extends Task { | |||
| overrideProperties(); | |||
| if (antFile == null) { | |||
| antFile = Main.DEFAULT_BUILD_FILENAME; | |||
| antFile = getDefaultBuildFile(); | |||
| } | |||
| File file = FILE_UTILS.resolveFile(dir, antFile); | |||
| @@ -469,6 +469,19 @@ public class Ant extends Task { | |||
| } | |||
| } | |||
| /** | |||
| * Get the default build file name to use when launching the task. | |||
| * <p> | |||
| * This function may be overrided by providers of custom ProjectHelper so they can implement easily their sub | |||
| * launcher. | |||
| * | |||
| * @return the name of the default file | |||
| * @since Ant 1.8.0 | |||
| */ | |||
| protected String getDefaultBuildFile() { | |||
| return Main.DEFAULT_BUILD_FILENAME; | |||
| } | |||
| /** | |||
| * Override the properties in the new project with the one | |||
| * explicitly defined as nested elements here. | |||
| @@ -67,7 +67,7 @@ public class SubAnt extends Task { | |||
| private Ant ant = null; | |||
| private String subTarget = null; | |||
| private String antfile = Main.DEFAULT_BUILD_FILENAME; | |||
| private String antfile = getDefaultBuildFile(); | |||
| private File genericantfile = null; | |||
| private boolean verbose = false; | |||
| private boolean inheritAll = false; | |||
| @@ -82,6 +82,19 @@ public class SubAnt extends Task { | |||
| /** the targets to call on the new project */ | |||
| private Vector/*<TargetElement>*/ targets = new Vector(); | |||
| /** | |||
| * Get the default build file name to use when launching the task. | |||
| * <p> | |||
| * This function may be overrided by providers of custom ProjectHelper so they can implement easily their sub | |||
| * launcher. | |||
| * | |||
| * @return the name of the default file | |||
| * @since Ant 1.8.0 | |||
| */ | |||
| protected String getDefaultBuildFile() { | |||
| return Main.DEFAULT_BUILD_FILENAME; | |||
| } | |||
| /** | |||
| * Pass output sent to System.out to the new project. | |||
| * | |||
| @@ -50,7 +50,7 @@ public class Description extends DataType { | |||
| */ | |||
| public void addText(String text) { | |||
| ProjectHelper ph = ProjectHelper.getProjectHelper(); | |||
| ProjectHelper ph = (ProjectHelper) getProject().getReference(ProjectHelper.PROJECTHELPER_REFERENCE); | |||
| if (!(ph instanceof ProjectHelperImpl)) { | |||
| // New behavior for delayed task creation. Description | |||
| // will be evaluated in Project.getDescription() | |||