NOT FINAL. API MAY CHANGE
Deals with properties - substitution, dynamic properties, etc.
This is the same code as in Ant1.5. The main addition is the ability
to chain multiple PropertyHelpers and to replace the default.
| Method from org.apache.tools.ant.PropertyHelper Detail: |
public void copyInheritedProperties(Project other) {
//avoid concurrent modification:
synchronized (inheritedProperties) {
Enumeration e = inheritedProperties.keys();
while (e.hasMoreElements()) {
String arg = e.nextElement().toString();
if (other.getUserProperty(arg) != null) {
continue;
}
Object value = inheritedProperties.get(arg);
other.setInheritedProperty(arg, value.toString());
}
}
}
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.
To copy all "user" properties, you will also have to call
copyUserProperties . |
public void copyUserProperties(Project other) {
//avoid concurrent modification:
synchronized (userProperties) {
Enumeration e = userProperties.keys();
while (e.hasMoreElements()) {
Object arg = e.nextElement();
if (inheritedProperties.containsKey(arg)) {
continue;
}
Object value = userProperties.get(arg);
other.setUserProperty(arg.toString(), 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
given as the argument.
To copy all "user" properties, you will also have to call
copyInheritedProperties . |
protected Hashtable getInternalInheritedProperties() {
return inheritedProperties;
}
special back door for subclasses, internal access to the hashtables |
protected Hashtable getInternalProperties() {
return properties;
}
special back door for subclasses, internal access to the hashtables |
protected Hashtable getInternalUserProperties() {
return userProperties;
}
special back door for subclasses, internal access to the hashtables |
public PropertyHelper getNext() {
return next;
}
Get the next property helper in the chain. |
public Project getProject() {
return project;
}
Get this PropertyHelper's Project. |
public Hashtable getProperties() {
//avoid concurrent modification:
synchronized (properties) {
return new Hashtable(properties);
}
// There is a better way to save the context. This shouldn't
// delegate to next, it's for backward compatibility only.
}
Returns a copy of the properties table. |
public synchronized Object getProperty(String ns,
String name) {
if (name == null) {
return null;
}
Object o = getPropertyHook(ns, name, false);
if (o != null) {
return o;
}
return properties.get(name);
}
Returns the value of a property, if it is set. You can override
this method in order to plug your own storage. |
public static synchronized PropertyHelper getPropertyHelper(Project project) {
PropertyHelper helper
= (PropertyHelper) project.getReference(MagicNames.REFID_PROPERTY_HELPER);
if (helper != null) {
return helper;
}
helper = new PropertyHelper();
helper.setProject(project);
project.addReference(MagicNames.REFID_PROPERTY_HELPER, helper);
return helper;
}
Factory method to create a property processor.
Users can provide their own or replace it using "ant.PropertyHelper"
reference. User tasks can also add themselves to the chain, and provide
dynamic properties. |
public Object getPropertyHook(String ns,
String name,
boolean user) {
if (getNext() != null) {
Object o = getNext().getPropertyHook(ns, name, user);
if (o != null) {
return o;
}
}
// Experimental/Testing, will be removed
if (name.startsWith("toString:")) {
name = name.substring("toString:".length());
Object v = project.getReference(name);
return (v == null) ? null : v.toString();
}
return null;
}
Get a property. If all hooks return null, the default
tables will be used. |
public Hashtable getUserProperties() {
//avoid concurrent modification:
synchronized (userProperties) {
return new Hashtable(userProperties);
}
}
Returns a copy of the user property hashtable |
public synchronized Object getUserProperty(String ns,
String name) {
if (name == null) {
return null;
}
Object o = getPropertyHook(ns, name, true);
if (o != null) {
return o;
}
return userProperties.get(name);
}
Returns the value of a user property, if it is set. |
public void parsePropertyString(String value,
Vector fragments,
Vector propertyRefs) throws BuildException {
parsePropertyStringDefault(value, fragments, propertyRefs);
}
Parses a string containing ${xxx} style property
references into two lists. The first list is a collection
of text fragments, while the other is a set of string property names.
null entries in the first list indicate a property
reference from the second list.
It can be overridden with a more efficient or customized version. |
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
//into the list
if (pos > 0) {
fragments.addElement(value.substring(prev, pos));
}
//if we are at the end of the string, we tack on a $
//then move past it
if (pos == (value.length() - 1)) {
fragments.addElement("$");
prev = pos + 1;
} else if (value.charAt(pos + 1) != '{") {
//peek ahead to see if the next char is a property or not
//not a property: insert the char as a literal
/*
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("$");
prev = pos + 2;
} else {
//new behaviour: $X maps to $X for all values of X!='$'
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);
propertyRefs.addElement(propertyName);
prev = endName + 1;
}
}
//no more $ signs found
//if there is any tail to the file, append it
if (prev < value.length()) {
fragments.addElement(value.substring(prev));
}
}
Default parsing method. It is here only to support backward compatibility
for the static ProjectHelper.parsePropertyString(). |
public String replaceProperties(String ns,
String value,
Hashtable keys) throws BuildException {
if (value == null || value.indexOf('$") == -1) {
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 + "}";
}
sb.append(fragment);
}
return sb.toString();
}
Replaces ${xxx} style constructions in the given value
with the string value of the corresponding data types. |
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);
}
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. |
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 property if no value currently exists. If the property
exists already, a message is logged and the method returns with
no other effect. |
public void setNext(PropertyHelper next) {
this.next = next;
}
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 :-)
- you can chain a property helper capable of storing some properties.
Again, you are required to respect the immutability semantics (at
least for non-dynamic properties) |
public void setProject(Project p) {
this.project = p;
}
Set the project for which this helper is performing property resolution. |
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);
}
if (name != null && value != null) {
properties.put(name, value);
}
return true;
}
Default implementation of setProperty. Will be called from Project.
This is the original 1.5 implementation, with calls to the hook
added. |
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;
}
Sets a property. Any existing property of the same name
is overwritten, unless it is a user property. Will be called
from setProperty().
If all helpers return false, the property will be saved in
the default properties table by setProperty. |
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. |