peterreilly 2005/01/13 06:05:11
Modified: src/main/org/apache/tools/ant PropertyHelper.java
src/main/org/apache/tools/ant/taskdefs Ant.java
MacroDef.java MacroInstance.java
Log:
**** EXPERMINTAL ************
add in local properties
these can be activated by <localproperty/> nested element to macrodef
Revision Changes Path
1.19 +327 -8 ant/src/main/org/apache/tools/ant/PropertyHelper.java
Index: PropertyHelper.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/PropertyHelper.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- PropertyHelper.java 15 Dec 2004 16:40:22 -0000 1.18
+++ PropertyHelper.java 13 Jan 2005 14:05:11 -0000 1.19
@@ -18,8 +18,13 @@
package org.apache.tools.ant;
import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
import java.util.Vector;
import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
/* ISSUES:
@@ -35,7 +40,7 @@
Need to discuss this and find if we need more.
*/
-/** NOT FINAL. API MAY CHANGE
+/**
*
* Deals with properties - substitution, dynamic properties, etc.
*
@@ -46,11 +51,30 @@
*/
public class PropertyHelper {
+ /**
+ * Opaque interface for localproperties
+ * Allows a user to retrive, copy and replace
+ * the localproperties - currently used by the
+ * parallel task.
+ */
+ public interface LocalProperties {
+ /**
+ * @return a copy of the local properties
+ */
+ LocalProperties copy();
+ }
+
+
+ /** Local Properties */
+ private ThreadLocalProperties threadLocalProperties
+ = new ThreadLocalProperties();
+
+
private Project project;
private PropertyHelper next;
/** Project properties map (usually String to String). */
- private Hashtable properties = new Hashtable();
+ private HashMap properties = new HashMap(); // Contains normal and user
properties
/**
* Map of "user" properties (as created in the Ant task, for example).
@@ -167,6 +191,14 @@
return true;
}
}
+
+ // Check if this is a local property
+ LocalProperty l = threadLocalProperties.getLocalProperty(name);
+ if (l != null) {
+ l.setValue(value);
+ return true;
+ }
+
return false;
}
@@ -185,6 +217,11 @@
return o;
}
}
+ LocalProperty l = threadLocalProperties.getLocalProperty(name);
+ if (l != null) {
+ return l.getValue();
+ }
+
// Experimental/Testing, will be removed
if (name.startsWith("toString:")) {
name = name.substring("toString:".length());
@@ -194,6 +231,72 @@
return null;
}
+ /**
+ * @return the local properties
+ */
+ public LocalProperties getLocalProperties() {
+ return (LocalProperties) threadLocalProperties.get();
+ }
+
+ /**
+ * Set the local properties
+ * @param localProperties the new local properties, may be null.
+ */
+ public void setLocalProperties(LocalProperties localProperties) {
+ if (localProperties == null) {
+ localProperties = new LocalPropertyStack();
+ }
+ threadLocalProperties.set(localProperties);
+ }
+
+ /**
+ * Set the local properties without overriding the user props
+ * Used by ant.java to set the local properties, without
+ * modifing the user properties set in the param elements.
+ * @param localProperties the new local properties, may be null.
+ */
+ public void setNotOverrideLocalProperties(
+ LocalProperties localProperties) {
+ if (localProperties == null) {
+ localProperties = new LocalPropertyStack();
+ }
+ LocalPropertyStack s = (LocalPropertyStack) localProperties;
+ for (Iterator i = s.props.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ if (userProperties.get(entry.getKey()) != null) {
+ i.remove();
+ }
+ }
+ threadLocalProperties.set(localProperties);
+ }
+
+ /**
+ * Add a local property, with an optional initial value
+ *
+ * @param name the name of the local property
+ * @param value the initial value of the localproperty, may be null
+ */
+ public void addLocalProperty(String name, Object value) {
+ threadLocalProperties.addProperty(name, value);
+ }
+
+ /**
+ * A new scope for local properties.
+ *
+ */
+ public void enterLocalPropertyScope() {
+ threadLocalProperties.enterLocalPropertyScope();
+ }
+
+ /**
+ * Exit a scope of local properties, removing the
+ * local properties in the scope.
+ *
+ */
+ public void exitLocalPropertyScope() {
+ threadLocalProperties.exitLocalPropertyScope();
+ }
+
// -------------------- Optional methods --------------------
// You can override those methods if you want to optimize or
// do advanced things (like support a special syntax).
@@ -341,9 +444,15 @@
*/
public synchronized void setNewProperty(String ns, String name,
Object value) {
- if (null != properties.get(name)) {
+ LocalProperty local = threadLocalProperties.getLocalProperty(name);
+ boolean localPropertySet =
+ local != null && local.getValue() != null;
+ boolean localProperty = local != null;
+
+ if ((properties.get(name) != null && !localProperty)
+ || localPropertySet) {
project.log("Override ignored for property \"" + name
- + "\"", Project.MSG_VERBOSE);
+ + "\"", Project.MSG_VERBOSE);
return;
}
@@ -427,7 +536,7 @@
}
Object o = getPropertyHook(ns, name, false);
- if (o != null) {
+ if (o != null || threadLocalProperties.getLocalProperty(name) !=
null) {
return o;
}
@@ -451,6 +560,11 @@
if (o != null) {
return o;
}
+ // check if null local property
+ if (threadLocalProperties.getLocalProperty(name) != null) {
+ return null;
+ }
+
return userProperties.get(name);
}
@@ -460,15 +574,32 @@
// deprecated, it is possible to use a better (more efficient)
// mechanism to preserve the context.
- // TODO: do we need to delegate ?
/**
* Returns a copy of the properties table.
* @return a hashtable containing all properties
- * (including user properties).
+ * (including user properties and local properties).
*/
public Hashtable getProperties() {
- return new Hashtable(properties);
+ System.out.println("GetProperties called");
+ Hashtable ret = new Hashtable(properties);
+ Map locals = threadLocalProperties.getProps();
+ for (Iterator i = locals.entrySet().iterator(); i.hasNext();) {
+ Map.Entry e = (Map.Entry) i.next();
+ List l = (List) e.getValue();
+ if (l != null && l.size() > 0) {
+ LocalProperty p = (LocalProperty) l.get(l.size() - 1);
+ if (p.getValue() == null) {
+ if (ret.get(e.getKey()) != null) {
+ ret.remove(e.getKey());
+ }
+ } else {
+ ret.put(e.getKey(), p.getValue());
+ }
+ }
+ }
+ return ret;
+
// There is a better way to save the context. This shouldn't
// delegate to next, it's for backward compatibility only.
}
@@ -482,6 +613,24 @@
}
/**
+ * Returns a copy of the local properties
+ * @return a map containing the local properties as string->string
+ */
+ public Map getLocalPropertiesCopy() {
+ Map copy = new HashMap();
+ Map locals = threadLocalProperties.getProps();
+ for (Iterator i = locals.entrySet().iterator(); i.hasNext();) {
+ Map.Entry e = (Map.Entry) i.next();
+ List l = (List) e.getValue();
+ if (l != null && l.size() > 0) {
+ LocalProperty p = (LocalProperty) l.get(l.size() - 1);
+ copy.put(e.getKey(), p.getValue());
+ }
+ }
+ return copy;
+ }
+
+ /**
* Copies all user properties that have not been set on the
* command line or a GUI tool from this instance to the Project
* instance given as the argument.
@@ -591,6 +740,176 @@
//if there is any tail to the file, append it
if (prev < value.length()) {
fragments.addElement(value.substring(prev));
+ }
+ }
+
+ /**
+ * A holder class for a local property value
+ */
+ private class LocalProperty {
+ private int level;
+ private Object value;
+ public LocalProperty(int level, Object value) {
+ this.level = level;
+ this.value = value;
+ }
+
+ public LocalProperty copy() {
+ return new LocalProperty(level, value);
+ }
+
+ public int getLevel() {
+ return level;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ void setValue(Object value) {
+ this.value = value;
+ }
+ }
+
+ /**
+ * A class implementing a local property stack.
+ */
+ private class LocalPropertyStack
+ implements LocalProperties {
+ private int level = 0;
+ // HashMap<String, ListArray<LocalPropertyValue>>
+ private HashMap props = new HashMap();
+
+ // ArrayList<ArrayList<String>>
+ private List stack = new ArrayList();
+
+ public LocalProperties copy() {
+ LocalPropertyStack copy = new LocalPropertyStack();
+ copy.stack = new ArrayList();
+ copy.level = level;
+ for (int i = 0; i < stack.size(); ++i) {
+ copy.stack.add(((ArrayList) stack.get(i)).clone());
+ }
+ copy.props = new HashMap();
+ for (Iterator i = props.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ ArrayList from = (ArrayList) entry.getValue();
+ List l2 = new ArrayList();
+ for (Iterator l = from.iterator(); l.hasNext();) {
+ LocalProperty v = (LocalProperty) l.next();
+ l2.add(v.copy());
+ }
+ copy.props.put(entry.getKey(), l2);
+ }
+ return copy;
+ }
+
+ public LocalProperties shallowCopy() {
+ LocalPropertyStack copy = new LocalPropertyStack();
+ copy.stack = new ArrayList();
+ copy.level = level;
+ for (int i = 0; i < stack.size(); ++i) {
+ copy.stack.add(((ArrayList) stack.get(i)).clone());
+ }
+ copy.props = new HashMap();
+ for (Iterator i = props.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ ArrayList from = (ArrayList) entry.getValue();
+ List l2 = new ArrayList();
+ for (Iterator l = from.iterator(); l.hasNext();) {
+ LocalProperty v = (LocalProperty) l.next();
+ l2.add(v);
+ }
+ copy.props.put(entry.getKey(), l2);
+ }
+ return copy;
+ }
+
+ public void enterLocalPropertyScope() {
+ stack.add(new ArrayList());
+ level++;
+ }
+
+ public void addProperty(String name, Object value) {
+ if (stack.size() == 0) {
+ return;
+ }
+ List list = (List) stack.get(stack.size() - 1);
+ list.add(name);
+ List local = (List) props.get(name);
+ if (local == null) {
+ local = new ArrayList();
+ props.put(name, local);
+ } else {
+ LocalProperty l = (LocalProperty) local.get(local.size() -
1);
+ if (l.getLevel() == level) {
+ throw new BuildException(
+ "Attempt to add another local of the same name");
+ }
+ }
+ LocalProperty l = new LocalProperty(level, value);
+ local.add(l);
+ }
+
+ public void exitLocalPropertyScope() {
+ if (stack.size() == 0) {
+ return;
+ }
+ level--;
+ List list = (List) stack.remove(stack.size() - 1);
+ for (Iterator i = list.iterator(); i.hasNext();) {
+ String name = (String) i.next();
+ List local = (List) props.get(name);
+ if (local != null && local.size() != 0) {
+ local.remove(local.size() - 1);
+ if (local.size() == 0) {
+ props.remove(name);
+ }
+ }
+ }
+ }
+
+ public LocalProperty getLocalProperty(String name) {
+ List l = (List) props.get(name);
+ if (l != null && l.size() != 0) {
+ return (LocalProperty) l.get(l.size() - 1);
+ }
+ return null;
+ }
+
+ public Map getProps() {
+ return props;
+ }
+ }
+
+ /**
+ * A set of local properties stack for each thread
+ */
+
+ private class ThreadLocalProperties extends InheritableThreadLocal {
+ protected synchronized Object initialValue() {
+ return new LocalPropertyStack();
+ }
+ protected synchronized Object childValue(Object obj) {
+ return ((LocalPropertyStack) obj).shallowCopy();
+ }
+ public LocalProperty getLocalProperty(String name) {
+ return ((LocalPropertyStack) get()).getLocalProperty(name);
+ }
+
+ public void enterLocalPropertyScope() {
+ ((LocalPropertyStack) get()).enterLocalPropertyScope();
+ }
+
+ public void addProperty(String name, Object value) {
+ ((LocalPropertyStack) get()).addProperty(name, value);
+ }
+
+ public void exitLocalPropertyScope() {
+ ((LocalPropertyStack) get()).exitLocalPropertyScope();
+ }
+ public Map getProps() {
+ return ((LocalPropertyStack) get()).getProps();
}
}
1.114 +11 -0 ant/src/main/org/apache/tools/ant/taskdefs/Ant.java
Index: Ant.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Ant.java,v
retrieving revision 1.113
retrieving revision 1.114
diff -u -r1.113 -r1.114
--- Ant.java 6 Jan 2005 12:05:05 -0000 1.113
+++ Ant.java 13 Jan 2005 14:05:11 -0000 1.114
@@ -35,6 +35,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.helper.SingleCheckExecutor;
@@ -441,6 +442,16 @@
Property p = (Property) e.nextElement();
p.setProject(newProject);
p.execute();
+ }
+ // Do local properties second
+ if (inheritAll) {
+ // Only copy them if they have not been set
+ PropertyHelper newHelper =
+ PropertyHelper.getPropertyHelper(newProject);
+ PropertyHelper oldHelper =
+ PropertyHelper.getPropertyHelper(getProject());
+ newHelper.setNotOverrideLocalProperties(
+ oldHelper.getLocalProperties().copy());
}
getProject().copyInheritedProperties(newProject);
}
1.28 +53 -0 ant/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
Index: MacroDef.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/MacroDef.java,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -r1.27 -r1.28
--- MacroDef.java 13 Jan 2005 13:53:19 -0000 1.27
+++ MacroDef.java 13 Jan 2005 14:05:11 -0000 1.28
@@ -44,6 +44,7 @@
private String name;
private List attributes = new ArrayList();
private Map elements = new HashMap();
+ private Map localProperties = new HashMap();
private String textName = null;
private Text text = null;
private boolean hasImplicitElement = false;
@@ -293,6 +294,58 @@
hasImplicitElement = element.isImplicit();
elements.put(element.getName(), element);
}
+
+ /**
+ * A localproperty nested element.
+ * @param el a localproperty nested element
+ * @throws BuildException if the name of the element is not set or if a
+ * duplicate name is used
+ */
+ public void addConfiguredLocalProperty(LocalPropertyElement el) {
+ if (el.getName() == null) {
+ throw new BuildException(
+ "the 'localproperty' nested element needed a \"name\"
attribute");
+ }
+ if (localProperties.get(el.getName()) != null) {
+ throw new BuildException(
+ "the localproperty " + el.getName()
+ + " has already been specified");
+ }
+ localProperties.put(el.getName(), el);
+ }
+
+ /**
+ * Get the map of local properties specified by this macrodef.
+ * @return the localproperties map
+ */
+ public Map getLocalProperties() {
+ return localProperties;
+ }
+
+ /**
+ * A class to represent a local property nested element.
+ */
+ public static class LocalPropertyElement {
+
+ private String name;
+
+ /**
+ * An attribute called "name".
+ * @param name the name value.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the value of the "name" attribute.
+ * @return the name value
+ */
+ public String getName() {
+ return name;
+ }
+ }
+
/**
* Create a new ant type based on the embedded tasks and types.
1.31 +21 -9
ant/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
Index: MacroInstance.java
===================================================================
RCS file:
/home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- MacroInstance.java 13 Jan 2005 13:53:19 -0000 1.30
+++ MacroInstance.java 13 Jan 2005 14:05:11 -0000 1.31
@@ -31,6 +31,7 @@
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DynamicAttribute;
import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.RuntimeConfigurable;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
@@ -49,7 +50,7 @@
private Map map = new HashMap();
private Map nsElements = null;
private Map presentElements;
- private Hashtable localProperties;
+ private Hashtable localAttributes;
private String text = null;
private String implicitTag = null;
private List unknownElements = new ArrayList();
@@ -262,10 +263,10 @@
Map.Entry entry = (Map.Entry) i.next();
rc.setAttribute(
(String) entry.getKey(),
- macroSubs((String) entry.getValue(), localProperties));
+ macroSubs((String) entry.getValue(), localAttributes));
}
rc.addText(macroSubs(ue.getWrapper().getText().toString(),
- localProperties));
+ localAttributes));
Enumeration e = ue.getWrapper().getChildren();
while (e.hasMoreElements()) {
@@ -321,10 +322,19 @@
*
*/
public void execute() {
+ PropertyHelper propertyHelper =
+ PropertyHelper.getPropertyHelper(getProject());
+ propertyHelper.enterLocalPropertyScope();
+ for (Iterator i = macroDef.getLocalProperties().values().iterator();
+ i.hasNext();) {
+ MacroDef.LocalPropertyElement el =
(MacroDef.LocalPropertyElement) i.next();
+ propertyHelper.addLocalProperty(el.getName(), null);
+ }
+
presentElements = new HashMap();
getNsElements();
processTasks();
- localProperties = new Hashtable();
+ localAttributes = new Hashtable();
Set copyKeys = new HashSet(map.keySet());
for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();)
{
MacroDef.Attribute attribute = (MacroDef.Attribute) i.next();
@@ -334,7 +344,7 @@
}
if (value == null) {
value = attribute.getDefault();
- value = macroSubs(value, localProperties);
+ value = macroSubs(value, localAttributes);
} else if (attribute instanceof MacroDef.DefineAttribute) {
// Do not process given value, will fail as unknown attribute
continue;
@@ -343,7 +353,7 @@
throw new BuildException(
"required attribute " + attribute.getName() + " not
set");
}
- localProperties.put(attribute.getName(), value);
+ localAttributes.put(attribute.getName(), value);
copyKeys.remove(attribute.getName());
}
if (copyKeys.contains("id")) {
@@ -360,7 +370,7 @@
if (macroDef.getText().getTrim()) {
text = text.trim();
}
- localProperties.put(macroDef.getText().getName(), text);
+ localAttributes.put(macroDef.getText().getName(), text);
} else {
if (text != null && !text.trim().equals("")) {
throw new BuildException(
@@ -382,8 +392,10 @@
} catch (BuildException ex) {
throw ProjectHelper.addLocationToBuildException(
ex, getLocation());
+ } finally {
+ presentElements = null;
+ localAttributes = null;
+ propertyHelper.exitLocalPropertyScope();
}
- presentElements = null;
- localProperties = null;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]