From fdc711e2e2805a41b766e9d1e07d83512d97f658 Mon Sep 17 00:00:00 2001
From: Nicolas Lalevee
- Note this task heavily relies on the ProjectHelper + On execution it will select the proper ProjectHelper to parse the imported + file, using the same algorithm as the one executed at + startup. The selected ProjectHelper + instance will then be responsible to actually parse the imported file. +
+ ++ Note as seen above, this task heavily relies on the ProjectHelper implementation and doesn't really perform any work of its own. If you have configured Ant to use a ProjectHelper other than Ant's default, this task may or may not work.
- On execution it will read another Ant file into
- the same Project. This means that it basically works like the
+ In the common use case where only Ant's default project helper is
+ used, it basically works like the
Entity
Includes as explained in the Ant FAQ, as if the imported file was
contained in the importing file, minus the top <project>
tag.
The import task may only be used as a top-level task. This means that it may not be used in a target. diff --git a/docs/manual/Tasks/projecthelper.html b/docs/manual/Tasks/projecthelper.html new file mode 100644 index 000000000..4564d3e7a --- /dev/null +++ b/docs/manual/Tasks/projecthelper.html @@ -0,0 +1,59 @@ + + + +
+ + +This task is provided for the purpose of allowing the user to install a different +ProjectHelper at runtime. +
+The helpers will be added after all the already registered helpers, but before +the default one (ProjectHelper2) +
+See the description of Ant's +Project Helper for more information. +
+Since Ant 1.8.2
+ +org.apache.tools.ant.ProjectHelper
instances.
+
+Install a custom ProjectHelper implementation
+ (assuming MyProjectHelper extends ProjectHelper
):
+<typedef classname="org.example.MyProjectHelper" + name="myprojecthelper"/> +<projecthelper> + <myprojecthelper/> +</projecthelper> ++ + + + diff --git a/docs/manual/projecthelper.html b/docs/manual/projecthelper.html index 4e0c9dccb..be838c843 100644 --- a/docs/manual/projecthelper.html +++ b/docs/manual/projecthelper.html @@ -47,6 +47,12 @@ been done around a pure java frontend, and a groovy one too (ask the dev mailing list for further info about these). +
Since Ant 1.8.2, the import task will also +try to use the proper helper to parse the imported file. So it is possible to +write different build files in different languages and have them import each +other. +
+@@ -122,7 +128,7 @@ capable of and what is is expecting:
-Now that you have your implementation ready, you have to declare it to Ant. Two +Now that you have your implementation ready, you have to declare it to Ant. Three solutions here:
org.apache.tools.ant.ProjectHelper
@@ -132,6 +138,10 @@ solutions here:
META-INF/services/org.apache.tools.ant.ProjectHelper
.
And then in this file just put the fully qualified name of your
implementationSee the ProjectHelper documentation in the manual.
* * @since Ant 1.8.0 @@ -57,6 +57,18 @@ public class ProjectHelperRepository { private static final Class[] NO_CLASS = new Class[0]; private static final Object[] NO_OBJECT = new Object[0]; + private static Constructor PROJECTHELPER2_CONSTRUCTOR; + + static { + try { + PROJECTHELPER2_CONSTRUCTOR = ProjectHelper2.class + .getConstructor(NO_CLASS); + } catch (Exception e) { + // ProjectHelper2 must be available + throw new RuntimeException(e); + } + } + public static ProjectHelperRepository getInstance() { return instance; } @@ -67,7 +79,7 @@ public class ProjectHelperRepository { private void collectProjectHelpers() { // First, try the system property - ProjectHelper projectHelper = getProjectHelperBySystemProperty(); + Constructor projectHelper = getProjectHelperBySystemProperty(); registerProjectHelper(projectHelper); // A JDK1.3 'service' ( like in JAXP ). That will plug a helper @@ -100,35 +112,63 @@ public class ProjectHelperRepository { e.printStackTrace(System.err); } } + } - // last but not least, ant default project helper - projectHelper = new ProjectHelper2(); - registerProjectHelper(projectHelper); + /** + * Register the specified project helper into the repository. + *+ * The helper will be added after all the already registered helpers, but + * before the default one (ProjectHelper2) + * + * @param helperClassName + * the fully qualified name of the helper + * @throws BuildException + * if the class cannot be loaded or if there is no constructor + * with no argument + * @since Ant 1.8.2 + */ + public void registerProjectHelper(String helperClassName) + throws BuildException { + registerProjectHelper(getHelperConstructor(helperClassName)); } - private void registerProjectHelper(ProjectHelper projectHelper) { - if (projectHelper == null) { + /** + * Register the specified project helper into the repository. + *
+ * The helper will be added after all the already registered helpers, but
+ * before the default one (ProjectHelper2)
+ *
+ * @param helperClass
+ * the class of the helper
+ * @throws BuildException
+ * if there is no constructor with no argument
+ * @since Ant 1.8.2
+ */
+ public void registerProjectHelper(Class helperClass) throws BuildException {
+ try {
+ registerProjectHelper(helperClass.getConstructor(NO_CLASS));
+ } catch (NoSuchMethodException e) {
+ throw new BuildException("Couldn't find no-arg constructor in "
+ + helperClass.getName());
+ }
+ }
+
+ private void registerProjectHelper(Constructor helperConstructor) {
+ if (helperConstructor == null) {
return;
}
if (DEBUG) {
- System.out.println("ProjectHelper " +
- projectHelper.getClass().getName()
- + " registered.");
- }
- try {
- helpers.add(projectHelper.getClass().getConstructor(NO_CLASS));
- } catch (NoSuchMethodException nse) {
- // impossible to get here
- throw new BuildException("Couldn't find no-arg constructor in "
- + projectHelper.getClass().getName());
+ System.out.println("ProjectHelper "
+ + helperConstructor.getClass().getName() + " registered.");
}
+ helpers.add(helperConstructor);
}
- private ProjectHelper getProjectHelperBySystemProperty() {
+ private Constructor getProjectHelperBySystemProperty() {
String helperClass = System.getProperty(ProjectHelper.HELPER_PROPERTY);
try {
if (helperClass != null) {
- return newHelper(helperClass);
+ return getHelperConstructor(helperClass);
}
} catch (SecurityException e) {
System.err.println("Unable to load ProjectHelper class \""
@@ -142,7 +182,7 @@ public class ProjectHelperRepository {
return null;
}
- private ProjectHelper getProjectHelperByService(InputStream is) {
+ private Constructor getProjectHelperByService(InputStream is) {
try {
// This code is needed by EBCDIC and other strange systems.
// It's a fix for bugs reported in xerces
@@ -158,7 +198,7 @@ public class ProjectHelperRepository {
rd.close();
if (helperClassName != null && !"".equals(helperClassName)) {
- return newHelper(helperClassName);
+ return getHelperConstructor(helperClassName);
}
} catch (Exception e) {
System.out.println("Unable to load ProjectHelper from service "
@@ -171,21 +211,21 @@ public class ProjectHelperRepository {
}
/**
- * 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.
+ * Get the constructor with not argument of an helper from its class name.
+ * 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
* null
.
*
- * @return a new instance of the specified class.
+ * @return the constructor of the specified class.
*
* @exception BuildException
- * if the class cannot be found or cannot be appropriate
- * instantiated.
+ * if the class cannot be found or if a constructor with no
+ * argument cannot be found.
*/
- private ProjectHelper newHelper(String helperClass) throws BuildException {
+ private Constructor getHelperConstructor(String helperClass) throws BuildException {
ClassLoader classLoader = LoaderUtils.getContextClassLoader();
try {
Class clazz = null;
@@ -199,7 +239,7 @@ public class ProjectHelperRepository {
if (clazz == null) {
clazz = Class.forName(helperClass);
}
- return ((ProjectHelper) clazz.newInstance());
+ return clazz.getConstructor(NO_CLASS);
} catch (Exception e) {
throw new BuildException(e);
}
@@ -266,17 +306,25 @@ public class ProjectHelperRepository {
private static class ConstructingIterator implements Iterator {
private final Iterator nested;
+ private boolean empty = false;
ConstructingIterator(Iterator nested) {
this.nested = nested;
}
public boolean hasNext() {
- return nested.hasNext();
+ return nested.hasNext() || !empty;
}
public Object next() {
- Constructor c = (Constructor) nested.next();
+ Constructor c;
+ if (nested.hasNext()) {
+ c = (Constructor) nested.next();
+ } else {
+ // last but not least, ant default project helper
+ empty = true;
+ c = PROJECTHELPER2_CONSTRUCTOR;
+ }
try {
return c.newInstance(NO_OBJECT);
} catch (Exception e) {
diff --git a/src/main/org/apache/tools/ant/taskdefs/ImportTask.java b/src/main/org/apache/tools/ant/taskdefs/ImportTask.java
index a3abc2a36..26d7a43ac 100644
--- a/src/main/org/apache/tools/ant/taskdefs/ImportTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/ImportTask.java
@@ -21,6 +21,7 @@ package org.apache.tools.ant.taskdefs;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelperRepository;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
@@ -213,7 +214,22 @@ public class ImportTask extends Task {
setProjectHelperProps(prefix, prefixSeparator,
isInIncludeMode());
- helper.parse(getProject(), importedResource);
+ ProjectHelper subHelper = ProjectHelperRepository.getInstance().getProjectHelperForBuildFile(
+ importedResource);
+
+ // push current stacks into the sub helper
+ subHelper.getImportStack().addAll(helper.getImportStack());
+ subHelper.getExtensionStack().addAll(helper.getExtensionStack());
+ getProject().addReference(ProjectHelper.PROJECTHELPER_REFERENCE, subHelper);
+
+ subHelper.parse(getProject(), importedResource);
+
+ // push back the stack from the sub helper to the main one
+ getProject().addReference(ProjectHelper.PROJECTHELPER_REFERENCE, helper);
+ helper.getImportStack().clear();
+ helper.getImportStack().addAll(subHelper.getImportStack());
+ helper.getExtensionStack().clear();
+ helper.getExtensionStack().addAll(subHelper.getExtensionStack());
} catch (BuildException ex) {
throw ProjectHelper.addLocationToBuildException(
ex, getLocation());
diff --git a/src/main/org/apache/tools/ant/taskdefs/ProjectHelperTask.java b/src/main/org/apache/tools/ant/taskdefs/ProjectHelperTask.java
new file mode 100644
index 000000000..6d222efd3
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/ProjectHelperTask.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.ProjectHelperRepository;
+import org.apache.tools.ant.Task;
+
+/**
+ * Task to install project helper into Ant's runtime
+ *
+ * @since Ant 1.8.2
+ */
+public class ProjectHelperTask extends Task {
+
+ private List projectHelpers = new ArrayList();
+
+ public synchronized void addConfigured(ProjectHelper projectHelper) {
+ this.projectHelpers.add(projectHelper);
+ }
+
+ public void execute() throws BuildException {
+ ProjectHelperRepository repo = ProjectHelperRepository.getInstance();
+ for (Iterator it = projectHelpers.iterator(); it.hasNext();) {
+ ProjectHelper helper = (ProjectHelper) it.next();
+ repo.registerProjectHelper(helper.getClass());
+ }
+ }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties
index b99d44cf7..533f6c23c 100644
--- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties
+++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties
@@ -81,6 +81,7 @@ parallel=org.apache.tools.ant.taskdefs.Parallel
patch=org.apache.tools.ant.taskdefs.Patch
pathconvert=org.apache.tools.ant.taskdefs.PathConvert
presetdef=org.apache.tools.ant.taskdefs.PreSetDef
+projecthelper=org.apache.tools.ant.taskdefs.ProjectHelperTask
property=org.apache.tools.ant.taskdefs.Property
propertyhelper=org.apache.tools.ant.taskdefs.PropertyHelperTask
record=org.apache.tools.ant.taskdefs.Recorder
diff --git a/src/tests/antunit/core/projecthelpers-test.xml b/src/tests/antunit/core/projecthelpers-test.xml
new file mode 100644
index 000000000..cc293765c
--- /dev/null
+++ b/src/tests/antunit/core/projecthelpers-test.xml
@@ -0,0 +1,90 @@
+
+
+