peterreilly    2005/01/13 06:05:11

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

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to