===================================================================
RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/PropertyHelper.java,v
retrieving revision 1.15
diff -c -r1.15 PropertyHelper.java
*** src/main/org/apache/tools/ant/PropertyHelper.java 14 Apr 2004 15:42:06 -0000 1.15
--- src/main/org/apache/tools/ant/PropertyHelper.java 3 Jun 2004 17:40:32 -0000
***************
*** 20,25 ****
--- 20,26 ----
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
+ import org.apache.tools.ant.util.RecursivePropertyParser;
/* ISSUES:
***************
*** 45,57 ****
* @since Ant 1.6
*/
public class PropertyHelper {
!
private Project project;
private PropertyHelper next;
!
/** Project properties map (usually String to String). */
private Hashtable properties = new Hashtable();
!
/**
* Map of "user" properties (as created in the Ant task, for example).
* Note that these key/value pairs are also always put into the
--- 46,58 ----
* @since Ant 1.6
*/
public class PropertyHelper {
!
private Project project;
private PropertyHelper next;
!
/** Project properties map (usually String to String). */
private Hashtable properties = new Hashtable();
!
/**
* Map of "user" properties (as created in the Ant task, for example).
* Note that these key/value pairs are also always put into the
***************
*** 59,65 ****
* Mapping is String to String.
*/
private Hashtable userProperties = new Hashtable();
!
/**
* Map of inherited "user" properties - that are those "user"
* properties that have been created by tasks and not been set
--- 60,66 ----
* Mapping is String to String.
*/
private Hashtable userProperties = new Hashtable();
!
/**
* Map of inherited "user" properties - that are those "user"
* properties that have been created by tasks and not been set
***************
*** 67,81 ****
* Mapping is String to String.
*/
private Hashtable inheritedProperties = new Hashtable();
!
/**
* Default constructor.
*/
protected PropertyHelper() {
}
!
// -------------------- Hook management --------------------
!
/**
* Set the project for which this helper is performing property resolution
*
--- 68,82 ----
* Mapping is String to String.
*/
private Hashtable inheritedProperties = new Hashtable();
!
/**
* Default constructor.
*/
protected PropertyHelper() {
}
!
// -------------------- Hook management --------------------
!
/**
* Set the project for which this helper is performing property resolution
*
***************
*** 84,90 ****
public void setProject(Project p) {
this.project = p;
}
!
/** 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 :-)
--- 85,91 ----
public void setProject(Project p) {
this.project = p;
}
!
/** 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 :-)
***************
*** 98,104 ****
public void setNext(PropertyHelper next) {
this.next = next;
}
!
/**
* Get the next property helper in the chain.
*
--- 99,105 ----
public void setNext(PropertyHelper next) {
this.next = next;
}
!
/**
* Get the next property helper in the chain.
*
***************
*** 107,113 ****
public PropertyHelper getNext() {
return next;
}
!
/**
* Factory method to create a property processor.
* Users can provide their own or replace it using "ant.PropertyHelper"
--- 108,114 ----
public PropertyHelper getNext() {
return next;
}
!
/**
* Factory method to create a property processor.
* Users can provide their own or replace it using "ant.PropertyHelper"
***************
*** 119,139 ****
* @return the project's property helper.
*/
public static synchronized
! PropertyHelper getPropertyHelper(Project project) {
PropertyHelper helper
! = (PropertyHelper) project.getReference("ant.PropertyHelper");
if (helper != null) {
return helper;
}
helper = new PropertyHelper();
helper.setProject(project);
!
project.addReference("ant.PropertyHelper", helper);
return helper;
}
!
// -------------------- Methods to override --------------------
!
/**
* Sets a property. Any existing property of the same name
* is overwritten, unless it is a user property. Will be called
--- 120,140 ----
* @return the project's property helper.
*/
public static synchronized
! PropertyHelper getPropertyHelper(Project project) {
PropertyHelper helper
! = (PropertyHelper) project.getReference("ant.PropertyHelper");
if (helper != null) {
return helper;
}
helper = new PropertyHelper();
helper.setProject(project);
!
project.addReference("ant.PropertyHelper", helper);
return helper;
}
!
// -------------------- Methods to override --------------------
!
/**
* Sets a property. Any existing property of the same name
* is overwritten, unless it is a user property. Will be called
***************
*** 151,171 ****
* has a good reason not to).
*/
public boolean setPropertyHook(String ns, String name,
! Object value,
! boolean inherited, boolean user,
! boolean isNew) {
if (getNext() != null) {
boolean subst = getNext().setPropertyHook(ns, name, value,
! inherited, user, isNew);
// If next has handled the property
if (subst) {
return true;
}
}
!
return false;
}
!
/** Get a property. If all hooks return null, the default
* tables will be used.
*
--- 152,172 ----
* has a good reason not to).
*/
public boolean setPropertyHook(String ns, String name,
! Object value,
! boolean inherited, boolean user,
! boolean isNew) {
if (getNext() != null) {
boolean subst = getNext().setPropertyHook(ns, name, value,
! inherited, user, isNew);
// If next has handled the property
if (subst) {
return true;
}
}
!
return false;
}
!
/** Get a property. If all hooks return null, the default
* tables will be used.
*
***************
*** 189,205 ****
}
return v.toString();
}
!
!
return null;
}
!
// -------------------- Optional methods --------------------
// You can override those methods if you want to optimize or
// do advanced things (like support a special syntax).
// The methods do not chain - you should use them when embedding ant
// (by replacing the main helper)
!
/**
* Parses a string containing ${xxx}
style property
* references into two lists. The first list is a collection
--- 190,206 ----
}
return v.toString();
}
!
!
return null;
}
!
// -------------------- Optional methods --------------------
// You can override those methods if you want to optimize or
// do advanced things (like support a special syntax).
// The methods do not chain - you should use them when embedding ant
// (by replacing the main helper)
!
/**
* Parses a string containing ${xxx}
style property
* references into two lists. The first list is a collection
***************
*** 220,230 ****
* }
*/
public void parsePropertyString(String value, Vector fragments,
! Vector propertyRefs)
! throws BuildException {
parsePropertyStringDefault(value, fragments, propertyRefs);
}
!
/**
* Replaces ${xxx}
style constructions in the given value
* with the string value of the corresponding data types.
--- 221,237 ----
* }
*/
public void parsePropertyString(String value, Vector fragments,
! Vector propertyRefs)
! throws BuildException {
parsePropertyStringDefault(value, fragments, propertyRefs);
}
!
! public String replaceProperties(String ns, String value,
! Hashtable keys)
! throws BuildException {
! return replacePropertiesRecursively(ns, value, keys);
! }
!
/**
* Replaces ${xxx}
style constructions in the given value
* with the string value of the corresponding data types.
***************
*** 242,268 ****
* @return the original string with the properties replaced, or
* null
if the original string is null
.
*/
! public String replaceProperties(String ns, String value,
! Hashtable keys)
! throws BuildException {
if (value == null) {
return null;
}
!
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) {
--- 249,275 ----
* @return the original string with the properties replaced, or
* null
if the original string is null
.
*/
! public String replacePropertiesBC(String ns, String value,
! Hashtable keys)
! throws BuildException {
if (value == null) {
return null;
}
!
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) {
***************
*** 271,329 ****
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 + "}";
}
sb.append(fragment);
}
!
return sb.toString();
}
!
// -------------------- 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.
* This is the original 1.5 implementation, with calls to the hook
* added.
*/
public synchronized boolean setProperty(String ns, String name,
! Object value, boolean verbose) {
// user (CLI) properties take precedence
if (null != userProperties.get(name)) {
if (verbose) {
project.log("Override ignored for user property " + name,
! Project.MSG_VERBOSE);
}
return false;
}
!
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,
! Project.MSG_VERBOSE);
}
!
if (verbose) {
project.log("Setting project property: " + name + " -> "
! + value, Project.MSG_DEBUG);
}
properties.put(name, value);
return true;
}
!
/**
* Sets a property if no value currently exists. If the property
* exists already, a message is logged and the method returns with
--- 278,403 ----
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 + "}";
}
sb.append(fragment);
}
!
return sb.toString();
}
!
! /**
! * Replaces ${xxx}
style constructions RECURSIVELY in the given value
! * with the string value of the corresponding data types. That is, this function
! * keeps finding the next leftmost outermost expression and expands it recursively until no
! * instantiable expressions remain.
! *
! *
! * @param value The string to be scanned for property references.
! * May be null
, in which case this
! * method returns immediately with no effect.
! * @param keys Mapping (String to String) of property names to their
! * values. If null
, only project properties will
! * be used.
! *
! * @exception BuildException if the string contains an opening
! * ${
without a closing
! * }
! * @return the original string with the properties replaced, or
! * null
if the original string is null
.
! */
!
! public String replacePropertiesRecursively(String ns, String value,
! Hashtable keys)
! throws BuildException {
! if (value == null) {
! return null;
! }
! StringBuffer sb = new StringBuffer(value);
!
! int nextOpenerIndex = RecursivePropertyParser.nextOpener(value, 0);
!
! while (nextOpenerIndex != RecursivePropertyParser.NO_MARKER) { // More inner expressions, recurse.
! // /* debug */ System.out.println("Head of replacePropertiesRecursively while loop, nextOpenerIndex = " + nextOpenerIndex + " sb=" + sb.toString());
! int balancingCloserIndex = RecursivePropertyParser.balancingCloser(sb.toString(), nextOpenerIndex);
! if (balancingCloserIndex == RecursivePropertyParser.NO_MARKER) {
! // ??? Should this be logged first?
! throw new BuildException("Unbalanced property expression: " + sb.substring(nextOpenerIndex).toString());
! }
! final String innerExpression = sb.substring(nextOpenerIndex + RecursivePropertyParser.OPENER_LENGTH , balancingCloserIndex);
!
! final String expansion = replacePropertiesRecursively(ns, innerExpression, keys);
! // /* debug */ System.out.println("replacePropertiesRecursively() innerExpression=" + innerExpression);
! Object replacement = null;
!
! // try to get it from the project or keys
! // Backward compatibility
! if (keys != null) {
! replacement = keys.get(expansion);
! }
! if (replacement == null) {
! replacement = getProperty(ns, expansion);
! }
!
! if (replacement == null) {
! project.log("Property ${" + expansion
! + "} has not been set", Project.MSG_VERBOSE);
! }
! final String fragment = (replacement != null)
! ? replacement.toString()
! : "${" + expansion + "}";
!
! sb.replace(nextOpenerIndex, balancingCloserIndex + RecursivePropertyParser.CLOSER_LENGTH, fragment);
! nextOpenerIndex = RecursivePropertyParser.nextOpener(sb.toString(), balancingCloserIndex+1);
! }
! return sb.toString();
! }
!
// -------------------- 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.
* This is the original 1.5 implementation, with calls to the hook
* added.
*/
public synchronized boolean setProperty(String ns, String name,
! Object value, boolean verbose) {
// user (CLI) properties take precedence
if (null != userProperties.get(name)) {
if (verbose) {
project.log("Override ignored for user property " + name,
! Project.MSG_VERBOSE);
}
return false;
}
!
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,
! Project.MSG_VERBOSE);
}
!
if (verbose) {
project.log("Setting project property: " + name + " -> "
! + value, Project.MSG_DEBUG);
}
properties.put(name, value);
return true;
}
!
/**
* Sets a property if no value currently exists. If the property
* exists already, a message is logged and the method returns with
***************
*** 336,360 ****
* @since Ant 1.6
*/
public synchronized void setNewProperty(String ns, 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) {
return;
}
!
project.log("Setting project property: " + name + " -> "
! + value, Project.MSG_DEBUG);
if (name != null && value != null) {
properties.put(name, value);
}
}
!
/**
* Sets a user property, which cannot be overwritten by
* set/unset property calls. Any previous value is overwritten.
--- 410,434 ----
* @since Ant 1.6
*/
public synchronized void setNewProperty(String ns, 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) {
return;
}
!
project.log("Setting project property: " + name + " -> "
! + value, Project.MSG_DEBUG);
if (name != null && value != null) {
properties.put(name, value);
}
}
!
/**
* Sets a user property, which cannot be overwritten by
* set/unset property calls. Any previous value is overwritten.
***************
*** 364,381 ****
* Must not be null
.
*/
public synchronized void setUserProperty(String ns, 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;
}
properties.put(name, value);
}
!
/**
* Sets a user property, which cannot be overwritten by set/unset
* property calls. Any previous value is overwritten. Also marks
--- 438,455 ----
* Must not be null
.
*/
public synchronized void setUserProperty(String ns, 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;
}
properties.put(name, value);
}
!
/**
* Sets a user property, which cannot be overwritten by set/unset
* property calls. Any previous value is overwritten. Also marks
***************
*** 388,409 ****
* Must not be null
.
*/
public synchronized void setInheritedProperty(String ns, String name,
! Object value) {
inheritedProperties.put(name, value);
!
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;
}
properties.put(name, value);
}
!
// -------------------- Getting properties --------------------
!
/**
* Returns the value of a property, if it is set. You can override
* this method in order to plug your own storage.
--- 462,483 ----
* Must not be null
.
*/
public synchronized void setInheritedProperty(String ns, String name,
! Object value) {
inheritedProperties.put(name, value);
!
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;
}
properties.put(name, value);
}
!
// -------------------- Getting properties --------------------
!
/**
* Returns the value of a property, if it is set. You can override
* this method in order to plug your own storage.
***************
*** 418,429 ****
if (name == null) {
return null;
}
!
Object o = getPropertyHook(ns, name, false);
if (o != null) {
return o;
}
!
return properties.get(name);
}
/**
--- 492,503 ----
if (name == null) {
return null;
}
!
Object o = getPropertyHook(ns, name, false);
if (o != null) {
return o;
}
!
return properties.get(name);
}
/**
***************
*** 445,459 ****
}
return userProperties.get(name);
}
!
!
// -------------------- Access to property tables --------------------
// This is used to support ant call and similar tasks. It should be
// 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
--- 519,533 ----
}
return userProperties.get(name);
}
!
!
// -------------------- Access to property tables --------------------
// This is used to support ant call and similar tasks. It should be
// 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
***************
*** 461,497 ****
*/
public Hashtable getProperties() {
Hashtable propertiesCopy = new Hashtable();
!
Enumeration e = properties.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
Object value = properties.get(name);
propertiesCopy.put(name, value);
}
!
// There is a better way to save the context. This shouldn't
// delegate to next, it's for backward compatibility only.
!
return propertiesCopy;
}
!
/**
* Returns a copy of the user property hashtable
* @return a hashtable containing just the user properties
*/
public Hashtable getUserProperties() {
Hashtable propertiesCopy = new Hashtable();
!
Enumeration e = userProperties.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
Object value = properties.get(name);
propertiesCopy.put(name, value);
}
!
return propertiesCopy;
}
!
/**
* Copies all user properties that have not been set on the
* command line or a GUI tool from this instance to the Project
--- 535,571 ----
*/
public Hashtable getProperties() {
Hashtable propertiesCopy = new Hashtable();
!
Enumeration e = properties.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
Object value = properties.get(name);
propertiesCopy.put(name, value);
}
!
// There is a better way to save the context. This shouldn't
// delegate to next, it's for backward compatibility only.
!
return propertiesCopy;
}
!
/**
* Returns a copy of the user property hashtable
* @return a hashtable containing just the user properties
*/
public Hashtable getUserProperties() {
Hashtable propertiesCopy = new Hashtable();
!
Enumeration e = userProperties.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
Object value = properties.get(name);
propertiesCopy.put(name, value);
}
!
return propertiesCopy;
}
!
/**
* Copies all user properties that have not been set on the
* command line or a GUI tool from this instance to the Project
***************
*** 515,521 ****
other.setInheritedProperty(arg, value.toString());
}
}
!
/**
* Copies all user properties that have been set on the command
* line or a GUI tool from this instance to the Project instance
--- 589,595 ----
other.setInheritedProperty(arg, value.toString());
}
}
!
/**
* Copies all user properties that have been set on the command
* line or a GUI tool from this instance to the Project instance
***************
*** 539,561 ****
other.setUserProperty(arg.toString(), value.toString());
}
}
!
// -------------------- Property parsing --------------------
// Moved from ProjectHelper. You can override the static method -
// 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
* for the static ProjectHelper.parsePropertyString().
*/
static void parsePropertyStringDefault(String value, Vector fragments,
! Vector propertyRefs)
! throws BuildException {
int prev = 0;
int pos;
//search for the next instance of $ from the 'prev' position
while ((pos = value.indexOf("$", prev)) >= 0) {
!
//if there was any text before this, add it as a fragment
//TODO, this check could be modified to go if pos>prev;
//seems like this current version could stick empty strings
--- 613,635 ----
other.setUserProperty(arg.toString(), value.toString());
}
}
!
// -------------------- Property parsing --------------------
// Moved from ProjectHelper. You can override the static method -
// 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
* for the static ProjectHelper.parsePropertyString().
*/
static void parsePropertyStringDefault(String value, Vector fragments,
! Vector propertyRefs)
! throws BuildException {
int prev = 0;
int pos;
//search for the next instance of $ from the 'prev' position
while ((pos = value.indexOf("$", prev)) >= 0) {
!
//if there was any text before this, add it as a fragment
//TODO, this check could be modified to go if pos>prev;
//seems like this current version could stick empty strings
***************
*** 574,580 ****
/*
fragments.addElement(value.substring(pos + 1, pos + 2));
prev = pos + 2;
! */
if (value.charAt(pos + 1) == '$') {
//backwards compatibility two $ map to one mode
fragments.addElement("$");
--- 648,654 ----
/*
fragments.addElement(value.substring(pos + 1, pos + 2));
prev = pos + 2;
! */
if (value.charAt(pos + 1) == '$') {
//backwards compatibility two $ map to one mode
fragments.addElement("$");
***************
*** 584,596 ****
fragments.addElement(value.substring(pos, pos + 2));
prev = pos + 2;
}
!
} else {
//property found, extract its name or bail on a typo
int endName = value.indexOf('}', pos);
if (endName < 0) {
throw new BuildException("Syntax error in property: "
! + value);
}
String propertyName = value.substring(pos + 2, endName);
fragments.addElement(null);
--- 658,670 ----
fragments.addElement(value.substring(pos, pos + 2));
prev = pos + 2;
}
!
} else {
//property found, extract its name or bail on a typo
int endName = value.indexOf('}', pos);
if (endName < 0) {
throw new BuildException("Syntax error in property: "
! + value);
}
String propertyName = value.substring(pos + 2, endName);
fragments.addElement(null);
***************
*** 604,608 ****
fragments.addElement(value.substring(prev));
}
}
!
}
--- 678,682 ----
fragments.addElement(value.substring(prev));
}
}
!
}