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() | |||