Browse Source

**** EXPERMINTAL ************

add in local properties
these can be activated by <localproperty/> nested element to macrodef


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277355 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Reilly 20 years ago
parent
commit
7517bc7058
4 changed files with 412 additions and 17 deletions
  1. +327
    -8
      src/main/org/apache/tools/ant/PropertyHelper.java
  2. +11
    -0
      src/main/org/apache/tools/ant/taskdefs/Ant.java
  3. +53
    -0
      src/main/org/apache/tools/ant/taskdefs/MacroDef.java
  4. +21
    -9
      src/main/org/apache/tools/ant/taskdefs/MacroInstance.java

+ 327
- 8
src/main/org/apache/tools/ant/PropertyHelper.java View File

@@ -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 @@ import java.util.Enumeration;
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 @@ import java.util.Enumeration;
*/
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 @@ public class PropertyHelper {
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 @@ public class PropertyHelper {
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 @@ public class PropertyHelper {
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 class PropertyHelper {
*/
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 @@ public class PropertyHelper {
}

Object o = getPropertyHook(ns, name, false);
if (o != null) {
if (o != null || threadLocalProperties.getLocalProperty(name) != null) {
return o;
}

@@ -451,6 +560,11 @@ public class PropertyHelper {
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 @@ public class PropertyHelper {
// 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.
}
@@ -481,6 +612,24 @@ public class PropertyHelper {
return new Hashtable(userProperties);
}

/**
* 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
@@ -594,4 +743,174 @@ public class PropertyHelper {
}
}

/**
* 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();
}
}

}

+ 11
- 0
src/main/org/apache/tools/ant/taskdefs/Ant.java View File

@@ -35,6 +35,7 @@ import org.apache.tools.ant.Executor;
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;
@@ -442,6 +443,16 @@ public class Ant extends Task {
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);
}



+ 53
- 0
src/main/org/apache/tools/ant/taskdefs/MacroDef.java View File

@@ -44,6 +44,7 @@ public class MacroDef extends AntlibDefinition {
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;
@@ -294,6 +295,58 @@ public class MacroDef extends AntlibDefinition {
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.
*


+ 21
- 9
src/main/org/apache/tools/ant/taskdefs/MacroInstance.java View File

@@ -31,6 +31,7 @@ import java.util.Enumeration;
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 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain
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 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain
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 class MacroInstance extends Task implements DynamicAttribute, TaskContain
*
*/
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 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain
}
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 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain
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 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain
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 @@ public class MacroInstance extends Task implements DynamicAttribute, TaskContain
} catch (BuildException ex) {
throw ProjectHelper.addLocationToBuildException(
ex, getLocation());
} finally {
presentElements = null;
localAttributes = null;
propertyHelper.exitLocalPropertyScope();
}
presentElements = null;
localProperties = null;
}
}

Loading…
Cancel
Save