Index: src/main/org/apache/tools/ant/PropertyHelper.java =================================================================== --- src/main/org/apache/tools/ant/PropertyHelper.java (revision 426814) +++ src/main/org/apache/tools/ant/PropertyHelper.java (working copy) @@ -44,7 +44,7 @@ * * @since Ant 1.6 */ -public class PropertyHelper { +public class PropertyHelper implements Cloneable { private Project project; private PropertyHelper next; @@ -76,7 +76,35 @@ //override facility for subclasses to put custom hashtables in + /** + * Clones an instance of this class. + *
This method doesn't clone properties. + * They might be added separately through the project.
+ *Hooks are all cloned. + * If one fails to clone the entire cloning fails.
+ */ + public Object clone() throws CloneNotSupportedException { + PropertyHelper clone = (PropertyHelper)super.clone(); + // since properties are set separately + // just reset as if newly constructed + clone.properties = new Hashtable(); + clone.userProperties = new Hashtable(); + clone.inheritedProperties = new Hashtable(); + + // clone hooks + PropertyHelper curCloneHookPrec = clone; + PropertyHelper curHook = getNext(); + while (curHook != null) { + PropertyHelper clonedHook = (PropertyHelper)curHook.clone(); + curCloneHookPrec.setNext(clonedHook); + curCloneHookPrec = clonedHook; + + curHook = curHook.getNext(); + } + return clone; + } + // -------------------- Hook management -------------------- /** @@ -135,6 +163,214 @@ return helper; } + /** + * Clones the property helper of a project (and its hooks) and + * installs the clone (with its clone hooks) into a new project. + * + *Properties of the main property helper are not copied. + * The caller might do it separately. + * The properties of the hooks are copied to their clones + * depending on the inheritAll parameter.
+ * + *If the new project already has a property helper, + * its hooks are attached to the new one (the clone) and + * its properties are passed to the clone as well.
+ * + *If the main property helper (or one of its hooks) + * couldn't be cloned, an exception is thrown.
+ * + * @param fromProject The project the helper of which has + * to be cloned. Must not benull
.
+ * @param newProject The project where the clone is installed.
+ * Must not be null
.
+ * @param inheritAll If true
the properties of the
+ * cloned hooks are copied to their clones.
+ * @throws CloneNotSupportedException
+ */
+ public static synchronized void clonePropertyHelper(
+ Project fromProject, Project newProject, boolean inheritAll)
+ throws CloneNotSupportedException {
+ if (fromProject == newProject) {
+ return;
+ }
+ PropertyHelper srcHelper = getPropertyHelper(fromProject);
+
+ PropertyHelper newHelper = (PropertyHelper)srcHelper.clone();
+
+ if (inheritAll) {
+ PropertyHelper srcHook = srcHelper.getNext();
+ PropertyHelper newHook = newHelper.getNext();
+ while (srcHook != null) {
+ // copy all the properties
+ newHook.getInternalInheritedProperties().putAll(
+ srcHook.getInternalInheritedProperties());
+ newHook.getInternalUserProperties().putAll(
+ srcHook.getInternalUserProperties());
+ newHook.getInternalProperties().putAll(
+ srcHook.getInternalProperties());
+
+ srcHook = srcHook.getNext();
+ newHook = newHook.getNext();
+ }
+ }
+ installPropertyHelper(newProject, newHelper);
+ }
+
+ /**
+ * Installs a property helper into a project.
+ *
+ * If the new project already has a property helper, + * its hooks are attached to the new one + * and its properties are copied to the new helper as well.
+ * + * @param project The project the helper has to + * handle properties for. + * Must not benull
.
+ * @param newHelper The new property helper of the project.
+ * Must not be null
.
+ */
+ public static synchronized void installPropertyHelper(
+ Project project, PropertyHelper newHelper) {
+
+ PropertyHelper oldHelper = getPropertyHelper(project);
+ if (oldHelper == newHelper) {
+ return;
+ }
+ if (!oldHelper.areYouOverridableBy(newHelper)) {
+ project.log(
+ "The current property handler prevented the installation"
+ + " of the new one."
+ , Project.MSG_VERBOSE);
+ return;
+ }
+
+ // sets the project of the property helper and its hooks
+ newHelper.setProject(project);
+ PropertyHelper curHook = newHelper.getNext();
+ while (curHook != null) {
+ curHook.setProject(project);
+ curHook = curHook.getNext();
+ }
+
+ synchronized (oldHelper) {
+ // do not want other threads to
+ // write to the old helper while it is used
+ // to initialize the new one
+ project.addReference(MagicNames.REFID_PROPERTY_HELPER
+ , newHelper);
+
+ // copy all the properties
+ Hashtable props = oldHelper.getInternalInheritedProperties();
+ Enumeration e = props.keys();
+ while (e.hasMoreElements()) {
+ String name = e.nextElement().toString();
+ Object value = props.get(name);
+ if (value == null) {
+ value = "";
+ }
+ project.setInheritedProperty(name, value.toString());
+ }
+ props = oldHelper.getInternalUserProperties();
+ e = props.keys();
+ while (e.hasMoreElements()) {
+ String name = e.nextElement().toString();
+ Object value = props.get(name);
+ if (value == null) {
+ value = "";
+ }
+ project.setUserProperty(name, value.toString());
+ }
+ props = oldHelper.getInternalProperties();
+ e = props.keys();
+ while (e.hasMoreElements()) {
+ String name = e.nextElement().toString();
+ Object value = props.get(name);
+ if (value == null) {
+ value = "";
+ }
+ project.setNewProperty(name, value.toString());
+ }
+
+ // insert old's hooks at the beginning, which
+ // is lowest priority if hooks follow the rule
+ // of "asking the next first"
+ if (oldHelper.getNext() != null) {
+ // get last in list
+ PropertyHelper lastHelper = oldHelper.getNext();
+ while (lastHelper.getNext() != null) {
+ lastHelper = lastHelper.getNext();
+ }
+ lastHelper.setNext(newHelper.getNext());
+ newHelper.setNext(oldHelper.getNext());
+ // reset old helper
+ oldHelper.setNext(null);
+ }
+ }
+ }
+
+ /**
+ * Tells whether this property helper can be overridden
+ * by another property helper.
+ *
+ * The bare PropertyHelper class is always overridable.
+ * Subclasses may return false
if they do
+ * not want to give up control to a particular property helper.
Ex. a PropertyHelper might not want to be displaced + * by another instance of the same class.
+ * + * @param name The new instance that wants to override + * this instance as the main project's PropertyHelper. + * Must not benull
.
+ * @return true
iff this property helper is + * overridable. + */ + protected boolean areYouOverridableBy(PropertyHelper newPH) { + return true; + } + + /** + * Installs a property helper hook into the project. + * + *If the hook is already installed, this method + * has no effect and a message warning is written to the log.
+ * + * @param project The project the hook is installed into. + * Must not benull
.
+ * @param newHook The property helper hook to be installed.
+ * Must not be null
.
+ */
+ public static synchronized void installPropertyHelperHook(
+ Project project, PropertyHelper newHook) {
+
+ PropertyHelper mainHelper = getPropertyHelper(project);
+
+ PropertyHelper curHelper = mainHelper;
+ while (curHelper != null) {
+ if (curHelper == newHook) {
+ project.log(
+ "The property helper hook is already installed"
+ , Project.MSG_WARN);
+ return;
+ }
+ curHelper = curHelper.getNext();
+ }
+ //Check is pointless since there are too many ways
+ //to screw things up (because of public getNext, setNext)
+ if (newHook.getNext() != null) {
+ project.log(
+ "The property helper hook already is in a chain (next not null)."
+ , Project.MSG_WARN);
+ return;
+ }
+
+ newHook.setProject(project);
+
+ // insert in the chain (lowest priority)
+ newHook.setNext(mainHelper.getNext());
+ mainHelper.setNext(newHook);
+ }
+
// -------------------- Methods to override --------------------
/**
Index: src/main/org/apache/tools/ant/taskdefs/SubAnt.java
===================================================================
--- src/main/org/apache/tools/ant/taskdefs/SubAnt.java (revision 426814)
+++ src/main/org/apache/tools/ant/taskdefs/SubAnt.java (working copy)
@@ -71,6 +71,7 @@
private boolean verbose = false;
private boolean inheritAll = false;
private boolean inheritRefs = false;
+ private boolean inheritPH = false;
private boolean failOnError = true;
private String output = null;
@@ -408,6 +409,16 @@
/**
* Corresponds to <ant>
's
+ * inheritph
attribute.
+ *
+ * @param b the new value for this boolean flag.
+ */
+ public void setInheritPH(boolean b) {
+ this.inheritPH = b;
+ }
+
+ /**
+ * Corresponds to <ant>
's
* nested <property>
element.
*
* @param p the property to pass on explicitly to the sub-build.
@@ -570,6 +581,8 @@
antTask.addReference((Ant.Reference) i.nextElement());
}
+ antTask.setInheritPH(inheritPH);
+
return antTask;
}
Index: src/main/org/apache/tools/ant/taskdefs/CallTarget.java
===================================================================
--- src/main/org/apache/tools/ant/taskdefs/CallTarget.java (revision 426814)
+++ src/main/org/apache/tools/ant/taskdefs/CallTarget.java (working copy)
@@ -54,6 +54,8 @@
private boolean inheritAll = true;
// must match the default value of Ant#inheritRefs
private boolean inheritRefs = false;
+ // must match the default value of Ant#inheritPH
+ private boolean inheritPH = false;
private boolean targetSet = false;
@@ -76,6 +78,15 @@
}
/**
+ * If true, pass a clone of the current property helper and its
+ * hooks to the new Ant project. Defaults to false.
+ * @param value if true, pass property helpers to the new Ant project
+ */
+ public void setInheritPH(boolean value) {
+ inheritPH = value;
+ }
+
+ /**
* Initialize this task by creating new instance of the ant task and
* configuring it by calling its own init method.
*/
@@ -101,6 +112,7 @@
callee.setAntfile(getProject().getProperty("ant.file"));
callee.setInheritAll(inheritAll);
callee.setInheritRefs(inheritRefs);
+ callee.setInheritPH(inheritPH);
callee.execute();
}
Index: src/main/org/apache/tools/ant/taskdefs/Ant.java
===================================================================
--- src/main/org/apache/tools/ant/taskdefs/Ant.java (revision 426814)
+++ src/main/org/apache/tools/ant/taskdefs/Ant.java (working copy)
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2005 The Apache Software Foundation
+ * Copyright 2000-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.MagicNames;
@@ -84,6 +85,9 @@
/** should we inherit references from the parent ? */
private boolean inheritRefs = false;
+ /** should we inherit cloned property helpers from the parent ? */
+ private boolean inheritPH = false;
+
/** the properties to pass to the new project */
private Vector properties = new Vector();
@@ -140,6 +144,28 @@
}
/**
+ * If true, pass a clone of the current property helper and its
+ * hooks to the new Ant project. Defaults to false.
+ * @param value if true, pass property helpers to the new Ant project
+ */
+ public void setInheritPH(boolean value) {
+ inheritPH = value;
+ }
+
+ /**
+ * Creates a clone of the main property helper and its hooks
+ * iff inheritPH is true
.
+ */
+ private void clonePropertyHelpers() {
+ try {
+ PropertyHelper.clonePropertyHelper(
+ getProject(), newProject, inheritAll);
+ } catch (CloneNotSupportedException cnse) {
+ log("Couln't clone PropertyHelper(s)", Project.MSG_VERBOSE);
+ }
+ }
+
+ /**
* Creates a Project instance for the project to call.
*/
public void init() {
@@ -286,6 +312,9 @@
if (newProject == null) {
reinit();
}
+ if (inheritPH) {
+ clonePropertyHelpers();
+ }
if ((dir == null) && (inheritAll)) {
dir = getProject().getBaseDir();
Index: src/etc/testcases/taskdefs/calltarget.xml
===================================================================
--- src/etc/testcases/taskdefs/calltarget.xml (revision 426814)
+++ src/etc/testcases/taskdefs/calltarget.xml (working copy)
@@ -80,4 +80,62 @@
A property handler (or helper) is a hidden object that evaluates and stores
+properties. The Ant API allows custom tasks to install custom property handlers.
+If you want custom property handlers to be passed to a child project you have to
+set the inheritPH attribute to true
.
If the build file changes after you've started the build, the behavior of this task is undefined.
@@ -73,6 +78,13 @@ new Ant project. Defaults tofalse
.
true
, pass a copy of the current
+ property handler and its hooks to the new Ant project.
+ Defaults to false
.inheritRefs
A property handler (or helper) is a hidden object that evaluates and stores
+properties. The Ant API allows custom tasks to install custom property handlers.
+If you want custom property handlers to be passed to a child project you have to
+set the inheritPH attribute to true
.
No | ||
inheritPH | +If true , pass a copy of the current
+ property handler and its hooks to the new Ant project.
+ Defaults to false . |
+ No | +
<ant>
's inheritph
attribute.
+