Author: mbenson
Date: Sun Jul 8 10:23:25 2007
New Revision: 554394
URL: http://svn.apache.org/viewvc?view=rev&rev=554394
Log:
BZ 42736: PropertyHelper API changes
Added:
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
(with props)
Modified:
ant/core/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java
ant/core/trunk/src/main/org/apache/tools/ant/Project.java
ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
ant/core/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties
Modified: ant/core/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java?view=diff&rev=554394&r1=554393&r2=554394
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java
(original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java Sun
Jul 8 10:23:25 2007
@@ -352,32 +352,32 @@
* <code>null</code>.
* @param value The value to set the attribute to. This may be interpreted
* or converted to the necessary type if the setter method
- * doesn't just take a string. Must not be <code>null</code>.
+ * doesn't accept an object of the supplied type.
*
* @exception BuildException if the introspected class doesn't support
* the given attribute, or if the setting
* method fails.
*/
public void setAttribute(Project p, Object element, String attributeName,
- String value) throws BuildException {
+ Object value) throws BuildException {
AttributeSetter as = (AttributeSetter) attributeSetters.get(
attributeName.toLowerCase(Locale.US));
- if (as == null) {
+ if (as == null && value != null) {
if (element instanceof DynamicAttributeNS) {
DynamicAttributeNS dc = (DynamicAttributeNS) element;
String uriPlusPrefix =
ProjectHelper.extractUriFromComponentName(attributeName);
String uri =
ProjectHelper.extractUriFromComponentName(uriPlusPrefix);
String localName =
ProjectHelper.extractNameFromComponentName(attributeName);
String qName = "".equals(uri) ? localName : uri + ":" +
localName;
- dc.setDynamicAttribute(uri, localName, qName, value);
+ dc.setDynamicAttribute(uri, localName, qName,
value.toString());
return;
}
if (element instanceof DynamicAttribute) {
DynamicAttribute dc = (DynamicAttribute) element;
- dc.setDynamicAttribute(attributeName.toLowerCase(Locale.US),
value);
+ dc.setDynamicAttribute(attributeName.toLowerCase(Locale.US),
value.toString());
return;
}
- if (attributeName.indexOf(':') != -1) {
+ if (attributeName.indexOf(':') >= 0) {
return; // Ignore attribute from unknown uri's
}
String msg = getElementName(p, element)
@@ -385,7 +385,7 @@
throw new UnsupportedAttributeException(msg, attributeName);
}
try {
- as.set(p, element, value);
+ as.setObject(p, element, value);
} catch (IllegalAccessException ie) {
// impossible as getMethods should only return public methods
throw new BuildException(ie);
@@ -395,6 +395,29 @@
}
/**
+ * Sets the named attribute in the given element, which is part of the
+ * given project.
+ *
+ * @param p The project containing the element. This is used when files
+ * need to be resolved. Must not be <code>null</code>.
+ * @param element The element to set the attribute in. Must not be
+ * <code>null</code>.
+ * @param attributeName The name of the attribute to set. Must not be
+ * <code>null</code>.
+ * @param value The value to set the attribute to. This may be interpreted
+ * or converted to the necessary type if the setter method
+ * doesn't just take a string. Must not be <code>null</code>.
+ *
+ * @exception BuildException if the introspected class doesn't support
+ * the given attribute, or if the setting
+ * method fails.
+ */
+ public void setAttribute(Project p, Object element, String attributeName,
+ String value) throws BuildException {
+ setAttribute(p, element, attributeName, (Object) value);
+ }
+
+ /**
* Adds PCDATA to an element, using the element's
* <code>void addText(String)</code> method, if it has one. If no
* such method is present, a BuildException is thrown if the
@@ -921,7 +944,7 @@
// simplest case - setAttribute expects String
if (java.lang.String.class.equals(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException {
m.invoke(parent, (Object[]) new String[] { value });
@@ -930,7 +953,7 @@
}
// char and Character get special treatment - take the first character
if (java.lang.Character.class.equals(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException {
if (value.length() == 0) {
@@ -943,7 +966,7 @@
}
// boolean and Boolean get special treatment because we have a nice
method in Project
if (java.lang.Boolean.class.equals(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException {
m.invoke(parent, (Object[]) new Boolean[] {
@@ -953,7 +976,7 @@
}
// Class doesn't have a String constructor but a decent factory method
if (java.lang.Class.class.equals(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException, BuildException {
try {
@@ -966,7 +989,7 @@
}
// resolve relative paths through Project
if (java.io.File.class.equals(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException {
m.invoke(parent, new Object[] { p.resolveFile(value) });
@@ -975,7 +998,7 @@
}
// EnumeratedAttributes have their own helper class
if (EnumeratedAttribute.class.isAssignableFrom(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException, BuildException {
try {
@@ -995,7 +1018,7 @@
//ignore
}
if (enumClass != null && enumClass.isAssignableFrom(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException, BuildException {
try {
@@ -1020,7 +1043,7 @@
};
}
if (java.lang.Long.class.equals(reflectedArg)) {
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException,
IllegalAccessException, BuildException {
try {
@@ -1059,7 +1082,7 @@
final boolean finalIncludeProject = includeProject;
final Constructor finalConstructor = c;
- return new AttributeSetter(m) {
+ return new AttributeSetter(m, arg) {
public void set(Project p, Object parent, String value)
throws InvocationTargetException, IllegalAccessException,
BuildException {
try {
@@ -1307,9 +1330,28 @@
*/
private abstract static class AttributeSetter {
private Method method; // the method called to set the attribute
-
- protected AttributeSetter(Method m) {
+ private Class type;
+ protected AttributeSetter(Method m, Class type) {
method = m;
+ this.type = type;
+ }
+ void setObject(Project p, Object parent, Object value)
+ throws InvocationTargetException, IllegalAccessException,
BuildException {
+ if (type != null) {
+ Class useType = type;
+ if (type.isPrimitive()) {
+ if (value == null) {
+ throw new BuildException("Attempt to set primitive "
+ + method.getName().substring(4) + " to null on
" + parent);
+ }
+ useType = (Class) PRIMITIVE_TYPE_MAP.get(type);
+ }
+ if (value == null || useType.isInstance(value)) {
+ method.invoke(parent, new Object[] { value });
+ return;
+ }
+ }
+ set(p, parent, value.toString());
}
abstract void set(Project p, Object parent, String value)
throws InvocationTargetException, IllegalAccessException,
BuildException;
Modified: ant/core/trunk/src/main/org/apache/tools/ant/Project.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/Project.java?view=diff&rev=554394&r1=554393&r2=554394
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/Project.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/Project.java Sun Jul 8
10:23:25 2007
@@ -526,8 +526,7 @@
* @since 1.5
*/
public void setNewProperty(String name, String value) {
- PropertyHelper.getPropertyHelper(this).setNewProperty(null, name,
- value);
+ PropertyHelper.getPropertyHelper(this).setNewProperty(name, value);
}
/**
@@ -540,8 +539,7 @@
* @see #setProperty(String,String)
*/
public void setUserProperty(String name, String value) {
- PropertyHelper.getPropertyHelper(this).setUserProperty(null, name,
- value);
+ PropertyHelper.getPropertyHelper(this).setUserProperty(name, value);
}
/**
@@ -557,8 +555,7 @@
* @see #setProperty(String,String)
*/
public void setInheritedProperty(String name, String value) {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- ph.setInheritedProperty(null, name, value);
+ PropertyHelper.getPropertyHelper(this).setInheritedProperty(name,
value);
}
/**
@@ -570,8 +567,7 @@
* @param value The property value. Must not be <code>null</code>.
*/
private void setPropertyInternal(String name, String value) {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- ph.setProperty(null, name, value, false);
+ PropertyHelper.getPropertyHelper(this).setProperty(name, value, false);
}
/**
@@ -584,8 +580,7 @@
* or if a <code>null</code> name is provided.
*/
public String getProperty(String propertyName) {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- return (String) ph.getProperty(null, propertyName);
+ return (String)
PropertyHelper.getPropertyHelper(this).getProperty(propertyName);
}
/**
@@ -602,10 +597,8 @@
* @exception BuildException if the given value has an unclosed
* property name, e.g. <code>${xxx</code>.
*/
- public String replaceProperties(String value)
- throws BuildException {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- return ph.replaceProperties(null, value, null);
+ public String replaceProperties(String value) throws BuildException {
+ return PropertyHelper.getPropertyHelper(this).replaceProperties(null,
value, null);
}
/**
@@ -618,8 +611,7 @@
* or if a <code>null</code> name is provided.
*/
public String getUserProperty(String propertyName) {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- return (String) ph.getUserProperty(null, propertyName);
+ return (String)
PropertyHelper.getPropertyHelper(this).getUserProperty(propertyName);
}
/**
@@ -628,8 +620,7 @@
* (including user properties).
*/
public Hashtable getProperties() {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- return ph.getProperties();
+ return PropertyHelper.getPropertyHelper(this).getProperties();
}
/**
@@ -637,8 +628,7 @@
* @return a hashtable containing just the user properties.
*/
public Hashtable getUserProperties() {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- return ph.getUserProperties();
+ return PropertyHelper.getPropertyHelper(this).getUserProperties();
}
/**
@@ -654,8 +644,7 @@
* @since Ant 1.5
*/
public void copyUserProperties(Project other) {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- ph.copyUserProperties(other);
+ PropertyHelper.getPropertyHelper(this).copyUserProperties(other);
}
/**
@@ -671,8 +660,7 @@
* @since Ant 1.5
*/
public void copyInheritedProperties(Project other) {
- PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
- ph.copyInheritedProperties(other);
+ PropertyHelper.getPropertyHelper(this).copyInheritedProperties(other);
}
/**
@@ -1978,13 +1966,13 @@
// Check for old id behaviour
ret = resolveIdReference(key, this);
if (ret == null && !key.equals(MagicNames.REFID_PROPERTY_HELPER)) {
- Vector p = new Vector();
- PropertyHelper.getPropertyHelper(this).parsePropertyString(
- key, new Vector(), p);
- if (p.size() == 1) {
- log("Unresolvable reference " + key
- + " might be a misuse of property expansion syntax.",
- MSG_WARN);
+ try {
+ if
(PropertyHelper.getPropertyHelper(this).containsProperties(key)) {
+ log("Unresolvable reference " + key
+ + " might be a misuse of property expansion
syntax.", MSG_WARN);
+ }
+ } catch (Exception e) {
+ //ignore
}
}
return ret;
Modified: ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java?view=diff&rev=554394&r1=554393&r2=554394
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java Sun Jul 8
10:23:25 2007
@@ -17,7 +17,13 @@
*/
package org.apache.tools.ant;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
import java.util.Vector;
import java.util.Enumeration;
@@ -34,6 +40,14 @@
Need to discuss this and find if we need more.
*/
+/* update for impending Ant 1.8:
+
+ - I can't see any reason for ns and would like to deprecate it.
+ - Replacing chaining with delegates for certain behavioral aspects.
+ - Object value seems valuable as outlined.
+
+ */
+
/** NOT FINAL. API MAY CHANGE
*
* Deals with properties - substitution, dynamic properties, etc.
@@ -45,8 +59,87 @@
*/
public class PropertyHelper {
+ /**
+ * Marker interface for a PropertyHelper delegate.
+ * @since Ant 1.8
+ */
+ public interface Delegate {
+ }
+
+ /**
+ * Describes an entity capable of evaluating a property name for value.
+ * @since Ant 1.8
+ */
+ public interface PropertyEvaluator extends Delegate {
+ /**
+ * Evaluate a property.
+ * @param property the property's String "identifier".
+ * @param propertyHelper the invoking PropertyHelper.
+ * @return Object value.
+ */
+ Object evaluate(String property, PropertyHelper propertyHelper);
+ }
+
+ /**
+ * Describes an entity capable of expanding properties embedded in a
string.
+ * @since Ant 1.8
+ */
+ public interface PropertyExpander extends Delegate {
+ /**
+ * Parse the next property name.
+ * @param s the String to parse.
+ * @param pos the ParsePosition in use.
+ * @param propertyHelper the invoking PropertyHelper.
+ * @return parsed String if any, else <code>null</code>.
+ */
+ String parsePropertyName(String s, ParsePosition pos, PropertyHelper
propertyHelper);
+ }
+
+ private static final PropertyEvaluator TO_STRING = new PropertyEvaluator()
{
+ private String prefix = "toString:";
+ public Object evaluate(String property, PropertyHelper propertyHelper)
{
+ Object o = null;
+ if (property.startsWith(prefix) && propertyHelper.getProject() !=
null) {
+ o =
propertyHelper.getProject().getReference(property.substring(prefix.length()));
+ }
+ return o == null ? null : o.toString();
+ }
+ };
+
+ private static final PropertyExpander DEFAULT_EXPANDER = new
PropertyExpander() {
+ public String parsePropertyName(String s, ParsePosition pos,
PropertyHelper propertyHelper) {
+ int index = pos.getIndex();
+ if (s.indexOf("${", index) == index) {
+ int end = s.indexOf('}', index);
+ if (end < 0) {
+ throw new BuildException("Syntax error in property: " + s);
+ }
+ int start = index + 2;
+ pos.setIndex(end + 1);
+ return s.substring(start, end);
+ }
+ return null;
+ }
+ };
+
+ /** dummy */
+ private static final PropertyExpander SKIP_$$ = new PropertyExpander() {
+ /**
+ * [EMAIL PROTECTED]
+ * @see
org.apache.tools.ant.PropertyHelper.PropertyExpander#parsePropertyName(java.lang.String,
java.text.ParsePosition, org.apache.tools.ant.PropertyHelper)
+ */
+ public String parsePropertyName(String s, ParsePosition pos,
PropertyHelper propertyHelper) {
+ int index = pos.getIndex();
+ if (s.indexOf("$$", index) == index) {
+ pos.setIndex(++index);
+ }
+ return null;
+ }
+ };
+
private Project project;
private PropertyHelper next;
+ private Hashtable delegates = new Hashtable();
/** Project properties map (usually String to String). */
private Hashtable properties = new Hashtable();
@@ -55,7 +148,6 @@
* Map of "user" properties (as created in the Ant task, for example).
* Note that these key/value pairs are also always put into the
* project properties, so only the project properties need to be queried.
- * Mapping is String to String.
*/
private Hashtable userProperties = new Hashtable();
@@ -63,7 +155,6 @@
* Map of inherited "user" properties - that are those "user"
* properties that have been created by tasks and not been set
* from the command line or a GUI tool.
- * Mapping is String to String.
*/
private Hashtable inheritedProperties = new Hashtable();
@@ -71,6 +162,9 @@
* Default constructor.
*/
protected PropertyHelper() {
+ add(TO_STRING);
+ add(SKIP_$$);
+ add(DEFAULT_EXPANDER);
}
//override facility for subclasses to put custom hashtables in
@@ -94,7 +188,8 @@
return project;
}
- /** There are 2 ways to hook into property handling:
+ /**
+ * There are 2 ways to hook into property handling:
* - you can replace the main PropertyHelper. The replacement is required
* to support the same semantics (of course :-)
*
@@ -162,6 +257,7 @@
* @return true if this helper has stored the property, false if it
* couldn't. Each helper should delegate to the next one (unless it
* has a good reason not to).
+ * @deprecated PropertyHelper chaining is deprecated.
*/
public boolean setPropertyHook(String ns, String name,
Object value,
@@ -177,13 +273,15 @@
return false;
}
- /** Get a property. If all hooks return null, the default
+ /**
+ * Get a property. If all hooks return null, the default
* tables will be used.
*
* @param ns namespace of the sought property.
* @param name name of the sought property.
* @param user True if this is a user property.
* @return The property, if returned by a hook, or null if none.
+ * @deprecated PropertyHelper chaining is deprecated.
*/
public Object getPropertyHook(String ns, String name, boolean user) {
if (getNext() != null) {
@@ -225,6 +323,7 @@
* @exception BuildException if the string contains an opening
* <code>${</code> without a closing
* <code>}</code>
+ * @deprecated We can do better than this.
*/
public void parsePropertyString(String value, Vector fragments,
Vector propertyRefs) throws BuildException
{
@@ -250,58 +349,150 @@
* <code>null</code> if the original string is <code>null</code>.
*/
public String replaceProperties(String ns, String value, Hashtable keys)
throws BuildException {
- if (value == null || value.indexOf('$') == -1) {
+ return replaceProperties(value);
+ }
+
+ /**
+ * Replaces <code>${xxx}</code> style constructions in the given value
+ * with the string value of the corresponding data types.
+ *
+ * @param value The string to be scanned for property references.
+ * May be <code>null</code>, in which case this
+ * method returns immediately with no effect.
+ *
+ * @exception BuildException if the string contains an opening
+ * <code>${</code> without a closing
+ * <code>}</code>
+ * @return the original string with the properties replaced, or
+ * <code>null</code> if the original string is <code>null</code>.
+ */
+ public String replaceProperties(String value) throws BuildException {
+ Object o = parseProperties(value);
+ return o == null || o instanceof String ? (String) o : o.toString();
+ }
+
+ /**
+ * Decode properties from a String representation. If the entire
+ * contents of the String resolve to a single property, that value
+ * is returned. Otherwise a String is returned.
+ *
+ * @param value The string to be scanned for property references.
+ * May be <code>null</code>, in which case this
+ * method returns immediately with no effect.
+ *
+ * @exception BuildException if the string contains an opening
+ * <code>${</code> without a closing
+ * <code>}</code>
+ * @return the original string with the properties replaced, or
+ * <code>null</code> if the original string is <code>null</code>.
+ */
+ public Object parseProperties(String value) throws BuildException {
+ if (value == null || "".equals(value)) {
return value;
}
- Vector fragments = new Vector();
- Vector propertyRefs = new Vector();
- parsePropertyString(value, fragments, propertyRefs);
-
- StringBuffer sb = new StringBuffer();
- Enumeration i = fragments.elements();
- Enumeration j = propertyRefs.elements();
-
- while (i.hasMoreElements()) {
- String fragment = (String) i.nextElement();
- if (fragment == null) {
- String propertyName = (String) j.nextElement();
- Object replacement = null;
-
- // try to get it from the project or keys
- // Backward compatibility
- if (keys != null) {
- replacement = keys.get(propertyName);
- }
- if (replacement == null) {
- replacement = getProperty(ns, propertyName);
- }
- if (replacement == null) {
- project.log("Property \"" + propertyName
- + "\" has not been set", Project.MSG_VERBOSE);
- }
- fragment = (replacement != null)
- ? replacement.toString() : "${" + propertyName + "}";
+ ParsePosition pos = new ParsePosition(0);
+ Object o = parseNextProperty(value, pos);
+ if (o != null && pos.getIndex() == value.length()) {
+ return o;
+ }
+ StringBuffer sb = new StringBuffer(value.length() * 2);
+ if (o == null) {
+ sb.append(value.charAt(pos.getIndex()));
+ pos.setIndex(pos.getIndex() + 1);
+ } else {
+ sb.append(o);
+ }
+ while (pos.getIndex() < value.length()) {
+ o = parseNextProperty(value, pos);
+ if (o == null) {
+ sb.append(value.charAt(pos.getIndex()));
+ pos.setIndex(pos.getIndex() + 1);
+ } else {
+ sb.append(o);
}
- sb.append(fragment);
}
return sb.toString();
}
+ /**
+ * Learn whether a String contains replaceable properties.
+ * @param value the String to check.
+ * @return <code>true</code> if <code>value</code> contains property
notation.
+ */
+ public boolean containsProperties(String value) {
+ if (value == null) {
+ return false;
+ }
+ for (ParsePosition pos = new ParsePosition(0); pos.getIndex() <
value.length();) {
+ if (parsePropertyName(value, pos) != null) {
+ return true;
+ }
+ pos.setIndex(pos.getIndex() + 1);
+ }
+ return false;
+ }
+
+ /**
+ * Return any property that can be parsed from the specified position in
the specified String.
+ * @param value String to parse
+ * @param pos ParsePosition
+ * @return Object or null if no property is at the current location.
+ */
+ public Object parseNextProperty(String value, ParsePosition pos) {
+ int start = pos.getIndex();
+ String propertyName = parsePropertyName(value, pos);
+ if (propertyName != null) {
+ Object result = getProperty(propertyName);
+ if (result != null) {
+ return result;
+ }
+ getProject().log("Property \"" + propertyName
+ + "\" has not been set", Project.MSG_VERBOSE);
+ return value.substring(start, pos.getIndex());
+ }
+ return null;
+ }
+
+ private String parsePropertyName(String value, ParsePosition pos) {
+ for (Iterator iter = getDelegates(PropertyExpander.class).iterator();
iter.hasNext();) {
+ String propertyName = ((PropertyExpander)
iter.next()).parsePropertyName(value, pos, this);
+ if (propertyName == null) {
+ continue;
+ }
+ return propertyName;
+ }
+ return null;
+ }
+
// -------------------- Default implementation --------------------
// Methods used to support the default behavior and provide backward
// compatibility. Some will be deprecated, you should avoid calling them.
- /** Default implementation of setProperty. Will be called from Project.
+ /**
+ * Default implementation of setProperty. Will be called from Project.
+ * This is the original 1.5 implementation, with calls to the hook
+ * added.
+ * @param ns The namespace for the property (currently not used).
+ * @param name The name of the property.
+ * @param value The value to set the property to.
+ * @param verbose If this is true output extra log messages.
+ * @return true if the property is set.
+ * @deprecated namespaces are unnecessary.
+ */
+ public boolean setProperty(String ns, String name, Object value, boolean
verbose) {
+ return setProperty(name, value, verbose);
+ }
+
+ /**
+ * Default implementation of setProperty. Will be called from Project.
* This is the original 1.5 implementation, with calls to the hook
* added.
- * @param ns The namespace for the property (currently not used).
* @param name The name of the property.
* @param value The value to set the property to.
* @param verbose If this is true output extra log messages.
* @return true if the property is set.
*/
- public synchronized boolean setProperty(String ns, String name,
- Object value, boolean verbose) {
+ public synchronized boolean setProperty(String name, Object value, boolean
verbose) {
// user (CLI) properties take precedence
if (null != userProperties.get(name)) {
if (verbose) {
@@ -311,10 +502,10 @@
return false;
}
- boolean done = setPropertyHook(ns, name, value, false, false, false);
- if (done) {
- return true;
- }
+// boolean done = setPropertyHook(ns, name, value, false, false, false);
+// if (done) {
+// return true;
+// }
if (null != properties.get(name) && verbose) {
project.log("Overriding previous definition of property \"" + name
@@ -342,20 +533,33 @@
* @param value The new value of the property.
* Must not be <code>null</code>.
* @since Ant 1.6
+ * @deprecated namespaces are unnecessary.
*/
- public synchronized void setNewProperty(String ns, String name,
- Object value) {
+ public void setNewProperty(String ns, String name, Object value) {
+ setNewProperty(name, value);
+ }
+
+ /**
+ * Sets a property if no value currently exists. If the property
+ * exists already, a message is logged and the method returns with
+ * no other effect.
+ *
+ * @param name The name of property to set.
+ * Must not be <code>null</code>.
+ * @param value The new value of the property.
+ * Must not be <code>null</code>.
+ * @since Ant 1.8
+ */
+ public synchronized void setNewProperty(String name, Object value) {
if (null != properties.get(name)) {
- project.log("Override ignored for property \"" + name
- + "\"", Project.MSG_VERBOSE);
- return;
- }
- boolean done = setPropertyHook(ns, name, value, false, false, true);
- if (done) {
+ project.log("Override ignored for property \"" + name + "\"",
Project.MSG_VERBOSE);
return;
}
- project.log("Setting project property: " + name + " -> "
- + value, Project.MSG_DEBUG);
+// boolean done = setPropertyHook(ns, name, value, false, false, true);
+// if (done) {
+// return;
+// }
+ project.log("Setting project property: " + name + " -> " + value,
Project.MSG_DEBUG);
if (name != null && value != null) {
properties.put(name, value);
}
@@ -369,17 +573,28 @@
* Must not be <code>null</code>.
* @param value The new value of the property.
* Must not be <code>null</code>.
+ * @deprecated namespaces are unnecessary.
*/
- public synchronized void setUserProperty(String ns, String name,
- Object value) {
- project.log("Setting ro project property: " + name + " -> "
- + value, Project.MSG_DEBUG);
+ public void setUserProperty(String ns, String name, Object value) {
+ setUserProperty(name, value);
+ }
+
+ /**
+ * Sets a user property, which cannot be overwritten by
+ * set/unset property calls. Any previous value is overwritten.
+ * @param name The name of property to set.
+ * Must not be <code>null</code>.
+ * @param value The new value of the property.
+ * Must not be <code>null</code>.
+ */
+ public synchronized void setUserProperty(String name, Object value) {
+ project.log("Setting ro project property: " + name + " -> " + value,
Project.MSG_DEBUG);
userProperties.put(name, value);
- boolean done = setPropertyHook(ns, name, value, false, true, false);
- if (done) {
- return;
- }
+// boolean done = setPropertyHook(ns, name, value, false, true, false);
+// if (done) {
+// return;
+// }
properties.put(name, value);
}
@@ -394,19 +609,33 @@
* Must not be <code>null</code>.
* @param value The new value of the property.
* Must not be <code>null</code>.
+ * @deprecated namespaces are unnecessary.
+ */
+ public void setInheritedProperty(String ns, String name, Object value) {
+ setInheritedProperty(name, value);
+ }
+
+ /**
+ * Sets an inherited user property, which cannot be overwritten by
set/unset
+ * property calls. Any previous value is overwritten. Also marks
+ * these properties as properties that have not come from the
+ * command line.
+ *
+ * @param name The name of property to set.
+ * Must not be <code>null</code>.
+ * @param value The new value of the property.
+ * Must not be <code>null</code>.
*/
- public synchronized void setInheritedProperty(String ns, String name,
- Object value) {
+ public synchronized void setInheritedProperty(String name, Object value) {
inheritedProperties.put(name, value);
- project.log("Setting ro project property: " + name + " -> "
- + value, Project.MSG_DEBUG);
+ project.log("Setting ro project property: " + name + " -> " + value,
Project.MSG_DEBUG);
userProperties.put(name, value);
- boolean done = setPropertyHook(ns, name, value, true, false, false);
- if (done) {
- return;
- }
+// boolean done = setPropertyHook(ns, name, value, true, false, false);
+// if (done) {
+// return;
+// }
properties.put(name, value);
}
@@ -422,17 +651,39 @@
* the return value is also <code>null</code>.
* @return the property value, or <code>null</code> for no match
* or if a <code>null</code> name is provided.
+ * @deprecated namespaces are unnecessary.
*/
public synchronized Object getProperty(String ns, String name) {
+ return getProperty(name);
+ }
+
+ /**
+ * Returns the value of a property, if it is set. You can override
+ * this method in order to plug your own storage.
+ *
+ * @param name The name of the property.
+ * May be <code>null</code>, in which case
+ * the return value is also <code>null</code>.
+ * @return the property value, or <code>null</code> for no match
+ * or if a <code>null</code> name is provided.
+ */
+ public synchronized Object getProperty(String name) {
if (name == null) {
return null;
}
- Object o = getPropertyHook(ns, name, false);
- if (o != null) {
- return o;
+ for (Iterator iter = getDelegates(PropertyEvaluator.class).iterator();
iter.hasNext();) {
+ Object o = ((PropertyEvaluator) iter.next()).evaluate(name, this);
+ if (o != null) {
+ return o;
+ }
}
+// Object o = getPropertyHook(ns, name, false);
+// if (o != null) {
+// return o;
+// }
return properties.get(name);
}
+
/**
* Returns the value of a user property, if it is set.
*
@@ -442,15 +693,32 @@
* the return value is also <code>null</code>.
* @return the property value, or <code>null</code> for no match
* or if a <code>null</code> name is provided.
+ * @deprecated namespaces are unnecessary.
+ */
+ public Object getUserProperty(String ns, String name) {
+ return getUserProperty(name);
+ }
+
+ /**
+ * Returns the value of a user property, if it is set.
+ *
+ * @param name The name of the property.
+ * May be <code>null</code>, in which case
+ * the return value is also <code>null</code>.
+ * @return the property value, or <code>null</code> for no match
+ * or if a <code>null</code> name is provided.
+ * @deprecated namespaces are unnecessary.
*/
- public synchronized Object getUserProperty(String ns, String name) {
+ public synchronized Object getUserProperty(String name) {
if (name == null) {
return null;
}
+/*
Object o = getPropertyHook(ns, name, true);
if (o != null) {
return o;
}
+*/
return userProperties.get(name);
}
@@ -568,7 +836,8 @@
// this is used for backward compatibility (for code that calls
// the parse method in ProjectHelper).
- /** Default parsing method. It is here only to support backward
compatibility
+ /**
+ * Default parsing method. It is here only to support backward
compatibility
* for the static ProjectHelper.parsePropertyString().
*/
static void parsePropertyStringDefault(String value, Vector fragments,
Vector propertyRefs)
@@ -623,5 +892,54 @@
if (prev < value.length()) {
fragments.addElement(value.substring(prev));
}
+ }
+
+ /**
+ * Add the specified delegate object to this PropertyHelper.
+ * Delegates are processed in LIFO order.
+ * @param delegate the delegate to add.
+ * @since Ant 1.8
+ */
+ public synchronized void add(Delegate delegate) {
+ List d = getDelegateInterfaces(delegate);
+ for (Iterator iter = d.iterator(); iter.hasNext();) {
+ Object key = iter.next();
+ List list = (List) delegates.get(key);
+ if (list == null) {
+ list = new ArrayList();
+ delegates.put(key, list);
+ }
+ if (!list.contains(delegate)) {
+ list.add(0, delegate);
+ }
+ }
+ }
+
+ /**
+ * Get the Collection of delegates of the specified type.
+ * @param type delegate type.
+ * @return Collection.
+ * @since Ant 1.8
+ */
+ protected synchronized List getDelegates(Class type) {
+ return delegates.containsKey(type)
+ ? (List) new ArrayList((Collection) delegates.get(type)) :
Collections.EMPTY_LIST;
+ }
+
+ /**
+ * Get all Delegate interfaces (excluding Delegate itself) from the
specified Delegate.
+ * @param d the Delegate to inspect.
+ * @return List<Class>
+ * @since Ant 1.8
+ */
+ protected List getDelegateInterfaces(Delegate d) {
+ Class[] c = d.getClass().getInterfaces();
+ ArrayList result = new ArrayList();
+ for (int i = 0; i < c.length; i++) {
+ if (Delegate.class.isAssignableFrom(c[i]) &&
!Delegate.class.equals(c[i])) {
+ result.add(c[i]);
+ }
+ }
+ return result;
}
}
Modified: ant/core/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java?view=diff&rev=554394&r1=554393&r2=554394
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java
(original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java Sun
Jul 8 10:23:25 2007
@@ -387,9 +387,9 @@
String value = (String) attributeMap.get(name);
// reflect these into the target
- value = p.replaceProperties(value);
+ Object attrValue =
PropertyHelper.getPropertyHelper(p).parseProperties(value);
try {
- ih.setAttribute(p, target, name, value);
+ ih.setAttribute(p, target, name, attrValue);
} catch (UnsupportedAttributeException be) {
// id attribute must be set externally
if (name.equals("id")) {
Added:
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java?view=auto&rev=554394
==============================================================================
---
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
(added)
+++
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
Sun Jul 8 10:23:25 2007
@@ -0,0 +1,105 @@
+/*
+ * 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.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.Task;
+
+/**
+ * This task is designed to allow the user to install a different
+ * PropertyHelper on the current Project. This task also allows the
+ * installation of PropertyHelper delegates on either the newly installed
+ * or existing PropertyHelper.
+ * @since Ant 1.8
+ */
+public class PropertyHelperTask extends Task {
+ private PropertyHelper propertyHelper;
+ private List delegates;
+
+ /**
+ * Construct the PropertyHelperTask, which is useless without a Project
instance.
+ * @param Project the associated Ant project instance.
+ */
+ public PropertyHelperTask(Project project) {
+ if (project == null) {
+ throw new IllegalArgumentException();
+ }
+ setProject(project);
+ }
+
+ /**
+ * Add a new PropertyHelper to be set on the Project.
+ * @param propertyHelper the PropertyHelper to set.
+ */
+ public synchronized void addConfigured(PropertyHelper propertyHelper) {
+ if (this.propertyHelper != null) {
+ throw new BuildException("Only one PropertyHelper can be
installed");
+ }
+ this.propertyHelper = propertyHelper;
+ }
+
+ /**
+ * Add a PropertyHelper delegate to the existing or new PropertyHelper.
+ * @param delegate the delegate to add.
+ */
+ public synchronized void addConfigured(PropertyHelper.Delegate delegate) {
+ if (delegates == null) {
+ delegates = new ArrayList();
+ }
+ delegates.add(delegate);
+ }
+
+ /**
+ * Execute the task.
+ * @throws BuildException on error.
+ */
+ public void execute() throws BuildException {
+ if (propertyHelper == null && delegates == null) {
+ throw new BuildException("Either a new PropertyHelper"
+ + " or one or more PropertyHelper delegates are required");
+ }
+ PropertyHelper ph = propertyHelper;
+ if (ph == null) {
+ ph = (PropertyHelper)
getProject().getReference(MagicNames.REFID_PROPERTY_HELPER);
+ } else {
+ ph = propertyHelper;
+ }
+ synchronized (ph) {
+ if (delegates != null) {
+ for (Iterator iter = delegates.iterator(); iter.hasNext();) {
+ PropertyHelper.Delegate delegate =
(PropertyHelper.Delegate) iter.next();
+ log("Adding PropertyHelper delegate " + delegate,
Project.MSG_DEBUG);
+ ph.add(delegate);
+ }
+ }
+ }
+ if (propertyHelper != null) {
+ log("Installing PropertyHelper " + propertyHelper,
Project.MSG_DEBUG);
+ //TODO copy existing properties to new PH?
+ getProject().addReference(MagicNames.REFID_PROPERTY_HELPER,
propertyHelper);
+ }
+ }
+
+}
Propchange:
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties?view=diff&rev=554394&r1=554393&r2=554394
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties
(original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties
Sun Jul 8 10:23:25 2007
@@ -57,6 +57,7 @@
pathconvert=org.apache.tools.ant.taskdefs.PathConvert
presetdef=org.apache.tools.ant.taskdefs.PreSetDef
property=org.apache.tools.ant.taskdefs.Property
+propertyhelper=org.apache.tools.ant.taskdefs.PropertyHelperTask
record=org.apache.tools.ant.taskdefs.Recorder
replace=org.apache.tools.ant.taskdefs.Replace
retry=org.apache.tools.ant.taskdefs.Retry
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]