diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/PropertySet.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/PropertySet.java | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/PropertySet.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/PropertySet.java new file mode 100644 index 00000000..f5992044 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/PropertySet.java @@ -0,0 +1,577 @@ +/* + * 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.types; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.resources.MappedResource; +import org.apache.tools.ant.types.resources.PropertyResource; +import org.apache.tools.ant.util.FileNameMapper; +import org.apache.tools.ant.util.regexp.RegexpMatcher; +import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; + +/** + * A set of properties. + * + * @since Ant 1.6 + */ +public class PropertySet extends DataType implements ResourceCollection { + + private boolean dynamic = true; + private boolean negate = false; + private Set<String> cachedNames; + private List<PropertyRef> ptyRefs = new ArrayList<PropertyRef>(); + private List<PropertySet> setRefs = new ArrayList<PropertySet>(); + private Mapper mapper; + + /** + * This is a nested class containing a reference to some properties + * and optionally a source of properties. + */ + public static class PropertyRef { + + private int count; + private String name; + private String regex; + private String prefix; + private String builtin; + + /** + * Set the name. + * @param name a <code>String</code> value. + */ + public void setName(String name) { + assertValid("name", name); + this.name = name; + } + + /** + * Set the regular expression to use to filter the properties. + * @param regex a regular expression. + */ + public void setRegex(String regex) { + assertValid("regex", regex); + this.regex = regex; + } + + /** + * Set the prefix to use. + * @param prefix a <code>String</code> value. + */ + public void setPrefix(String prefix) { + assertValid("prefix", prefix); + this.prefix = prefix; + } + + /** + * Builtin property names - all, system or commandline. + * @param b an enumerated <code>BuildinPropertySetName</code> value. + */ + public void setBuiltin(BuiltinPropertySetName b) { + String pBuiltIn = b.getValue(); + assertValid("builtin", pBuiltIn); + this.builtin = pBuiltIn; + } + + private void assertValid(String attr, String value) { + if (value == null || value.length() < 1) { + throw new BuildException("Invalid attribute: " + attr); + } + + if (++count != 1) { + throw new BuildException("Attributes name, regex, and " + + "prefix are mutually exclusive"); + } + } + + /** + * A debug toString(). + * @return a string version of this object. + */ + public String toString() { + return "name=" + name + ", regex=" + regex + ", prefix=" + prefix + + ", builtin=" + builtin; + } + + } //end nested class + + /** + * Allow properties of a particular name in the set. + * @param name the property name to allow. + */ + public void appendName(String name) { + PropertyRef r = new PropertyRef(); + r.setName(name); + addPropertyref(r); + } + + /** + * Allow properties whose names match a regex in the set. + * @param regex the regular expression to use. + */ + public void appendRegex(String regex) { + PropertyRef r = new PropertyRef(); + r.setRegex(regex); + addPropertyref(r); + } + + /** + * Allow properties whose names start with a prefix in the set. + * @param prefix the prefix to use. + */ + public void appendPrefix(String prefix) { + PropertyRef r = new PropertyRef(); + r.setPrefix(prefix); + addPropertyref(r); + } + + /** + * Allow builtin (all, system or commandline) properties in the set. + * @param b the type of builtin properties. + */ + public void appendBuiltin(BuiltinPropertySetName b) { + PropertyRef r = new PropertyRef(); + r.setBuiltin(b); + addPropertyref(r); + } + + /** + * Set a mapper to change property names. + * @param type mapper type. + * @param from source pattern. + * @param to output pattern. + */ + public void setMapper(String type, String from, String to) { + Mapper m = createMapper(); + Mapper.MapperType mapperType = new Mapper.MapperType(); + mapperType.setValue(type); + m.setType(mapperType); + m.setFrom(from); + m.setTo(to); + } + + /** + * Add a property reference (nested element) to the references to be used. + * @param ref a property reference. + */ + public void addPropertyref(PropertyRef ref) { + assertNotReference(); + setChecked(false); + ptyRefs.add(ref); + } + + /** + * Add another property set to this set. + * @param ref another property set. + */ + public void addPropertyset(PropertySet ref) { + assertNotReference(); + setChecked(false); + setRefs.add(ref); + } + + /** + * Create a mapper to map the property names. + * @return a mapper to be configured. + */ + public Mapper createMapper() { + assertNotReference(); + if (mapper != null) { + throw new BuildException("Too many <mapper>s!"); + } + mapper = new Mapper(getProject()); + setChecked(false); + return mapper; + } + + /** + * Add a nested FileNameMapper. + * @param fileNameMapper the mapper to add. + * @since Ant 1.6.3 + */ + public void add(FileNameMapper fileNameMapper) { + createMapper().add(fileNameMapper); + } + + /** + * Set whether to reevaluate the set every time the set is used. + * Default is true. + * + * @param dynamic if true, reevaluate the property set each time + * the set is used. if false cache the property set + * the first time and use the cached set on subsequent + * occasions. + */ + public void setDynamic(boolean dynamic) { + assertNotReference(); + this.dynamic = dynamic; + } + + /** + * Set whether to negate results. + * If "true", all properties not selected by nested elements will be returned. + * Default is "false". + * @param negate if true, negate the selection criteria. + */ + public void setNegate(boolean negate) { + assertNotReference(); + this.negate = negate; + } + + /** + * Get the dynamic attribute. + * @return true if the property set is to be evaluated each time it is used. + */ + public boolean getDynamic() { + if (isReference()) { + return getRef().dynamic; + } + dieOnCircularReference(); + return dynamic; + } + + /** + * Get the mapper attribute. + * @return the mapper attribute. + */ + public Mapper getMapper() { + if (isReference()) { + return getRef().mapper; + } + dieOnCircularReference(); + return mapper; + } + + /** + * Convert the system properties to a hashtable. + * Use propertynames to get the list of properties (including + * default ones). + */ + private Hashtable<String, Object> getAllSystemProperties() { + Hashtable<String, Object> ret = new Hashtable<String, Object>(); + for (Enumeration<?> e = System.getProperties().propertyNames(); + e.hasMoreElements();) { + String name = (String) e.nextElement(); + ret.put(name, System.getProperties().getProperty(name)); + } + return ret; + } + + /** + * This is the operation to get the existing or recalculated properties. + * @return the properties for this propertyset. + */ + public Properties getProperties() { + final Properties result = new Properties(); + result.putAll(getPropertyMap()); + return result; + } + + /** + * + * @return Map + * @since 1.9.0 + */ + private Map<String, Object> getPropertyMap() { + if (isReference()) { + return getRef().getPropertyMap(); + } + dieOnCircularReference(); + final Mapper myMapper = getMapper(); + final FileNameMapper m = myMapper == null ? null : myMapper.getImplementation(); + + final Map<String, Object> effectiveProperties = getEffectiveProperties(); + final Set<String> propertyNames = getPropertyNames(effectiveProperties); + final Map<String, Object> result = new HashMap<String, Object>(); + + //iterate through the names, get the matching values + for (String name : propertyNames) { + Object value = effectiveProperties.get(name); + // TODO should we include null properties? + // TODO should we query the PropertyHelper for property value to grab potentially shadowed values? + if (value != null) { + // may be null if a system property has been added + // after the project instance has been initialized + if (m != null) { + //map the names + String[] newname = m.mapFileName(name); + if (newname != null) { + name = newname[0]; + } + } + result.put(name, value); + } + } + return result; + + } + + private Map<String, Object> getEffectiveProperties() { + final Project prj = getProject(); + final Map<String, Object> result = prj == null ? getAllSystemProperties() : prj.getProperties(); + //quick & dirty, to make nested mapped p-sets work: + for (PropertySet set : setRefs) { + result.putAll(set.getPropertyMap()); + } + return result; + } + + private Set<String> getPropertyNames(Map<String, Object> props) { + Set<String> names; + if (getDynamic() || cachedNames == null) { + names = new HashSet<String>(); + addPropertyNames(names, props); + // Add this PropertySet's nested PropertySets' property names. + for (PropertySet set : setRefs) { + names.addAll(set.getPropertyMap().keySet()); + } + if (negate) { + //make a copy... + HashSet<String> complement = new HashSet<String>(props.keySet()); + complement.removeAll(names); + names = complement; + } + if (!getDynamic()) { + cachedNames = names; + } + } else { + names = cachedNames; + } + return names; + } + + /** + * @param names the output Set to fill with the property names + * matching this PropertySet selection criteria. + * @param props the current Project properties, passed in to + * avoid needless duplication of the Hashtable during recursion. + */ + private void addPropertyNames(Set<String> names, Map<String, Object> props) { + if (isReference()) { + getRef().addPropertyNames(names, props); + } + dieOnCircularReference(); + // Add this PropertySet's property names. + for (PropertyRef r : ptyRefs) { + if (r.name != null) { + if (props.get(r.name) != null) { + names.add(r.name); + } + } else if (r.prefix != null) { + for (String name : props.keySet()) { + if (name.startsWith(r.prefix)) { + names.add(name); + } + } + } else if (r.regex != null) { + RegexpMatcherFactory matchMaker = new RegexpMatcherFactory(); + RegexpMatcher matcher = matchMaker.newRegexpMatcher(); + matcher.setPattern(r.regex); + for (String name : props.keySet()) { + if (matcher.matches(name)) { + names.add(name); + } + } + } else if (r.builtin != null) { + + if (r.builtin.equals(BuiltinPropertySetName.ALL)) { + names.addAll(props.keySet()); + } else if (r.builtin.equals(BuiltinPropertySetName.SYSTEM)) { + names.addAll(getAllSystemProperties().keySet()); + } else if (r.builtin.equals(BuiltinPropertySetName + .COMMANDLINE)) { + names.addAll(getProject().getUserProperties().keySet()); + } else { + throw new BuildException("Impossible: Invalid builtin " + + "attribute!"); + } + } else { + throw new BuildException("Impossible: Invalid PropertyRef!"); + } + } + } + + /** + * Performs the check for circular references and returns the + * referenced PropertySet. + * @return the referenced PropertySet. + */ + protected PropertySet getRef() { + return (PropertySet) getCheckedRef(PropertySet.class, "propertyset"); + } + + /** + * Sets the value of the refid attribute. + * + * @param r the reference this datatype should point to. + * @throws BuildException if another attribute was set, since + * refid and all other attributes are mutually exclusive. + */ + public final void setRefid(Reference r) { + if (!noAttributeSet) { + throw tooManyAttributes(); + } + super.setRefid(r); + } + + /** + * Ensures this data type is not a reference. + * + * <p>Calling this method as the first line of every bean method of + * this data type (setXyz, addXyz, createXyz) ensure proper handling + * of the refid attribute.</p> + * + * @throws BuildException if the refid attribute was already set, since + * refid and all other attributes are mutually exclusive. + */ + protected final void assertNotReference() { + if (isReference()) { + throw tooManyAttributes(); + } + noAttributeSet = false; + } + + /** + * Flag which tracks whether any attribute has been set; used by + * {@link #assertNotReference()} and {@link #setRefid(Reference)}. + */ + private boolean noAttributeSet = true; + + /** + * Used for propertyref's builtin attribute. + */ + public static class BuiltinPropertySetName extends EnumeratedAttribute { + static final String ALL = "all"; + static final String SYSTEM = "system"; + static final String COMMANDLINE = "commandline"; + /** {@inheritDoc}. */ + public String[] getValues() { + return new String[] {ALL, SYSTEM, COMMANDLINE}; + } + } + + /** + * A debug toString. + * This gets a comma separated list of key=value pairs for + * the properties in the set. + * The output order is sorted according to the keys' <i>natural order</i>. + * @return a string rep of this object. + */ + public String toString() { + if (isReference()) { + return getRef().toString(); + } + dieOnCircularReference(); + StringBuilder b = new StringBuilder(); + TreeMap<String, Object> sorted = new TreeMap<String, Object>(getPropertyMap()); + for (Entry<String, Object> e : sorted.entrySet()) { + if (b.length() != 0) { + b.append(", "); + } + b.append(e.getKey()); + b.append("="); + b.append(e.getValue()); + } + return b.toString(); + } + + /** + * Fulfill the ResourceCollection interface. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator<Resource> iterator() { + if (isReference()) { + return getRef().iterator(); + } + dieOnCircularReference(); + final Set<String> names = getPropertyNames(getEffectiveProperties()); + + Mapper myMapper = getMapper(); + final FileNameMapper m = myMapper == null ? null : myMapper.getImplementation(); + final Iterator<String> iter = names.iterator(); + + return new Iterator<Resource>() { + public boolean hasNext() { + return iter.hasNext(); + } + public Resource next() { + PropertyResource p = new PropertyResource(getProject(), iter.next()); + return m == null ? (Resource) p : new MappedResource(p, m); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /** + * Fulfill the ResourceCollection contract. + * @return the size of this ResourceCollection. + */ + public int size() { + return isReference() ? getRef().size() : getProperties().size(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return whether this is a filesystem-only resource collection. + */ + public boolean isFilesystemOnly() { + if (isReference()) { + return getRef().isFilesystemOnly(); + } + dieOnCircularReference(); + return false; + } + + protected synchronized void dieOnCircularReference(Stack<Object> stk, Project p) + throws BuildException { + if (isChecked()) { + return; + } + if (isReference()) { + super.dieOnCircularReference(stk, p); + } else { + if (mapper != null) { + pushAndInvokeCircularReferenceCheck(mapper, stk, p); + } + for (PropertySet propertySet : setRefs) { + pushAndInvokeCircularReferenceCheck(propertySet, stk, + p); + } + setChecked(true); + } + } + +} |