diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/MacroDef.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/MacroDef.java | 851 |
1 files changed, 851 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/MacroDef.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/MacroDef.java new file mode 100644 index 00000000..63f68c5a --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/MacroDef.java @@ -0,0 +1,851 @@ +/* + * 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.taskdefs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.tools.ant.AntTypeDefinition; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ComponentHelper; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.RuntimeConfigurable; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.TaskContainer; +import org.apache.tools.ant.UnknownElement; + +/** + * Describe class <code>MacroDef</code> here. + * + * @since Ant 1.6 + */ +public class MacroDef extends AntlibDefinition { + + private NestedSequential nestedSequential; + private String name; + private boolean backTrace = true; + private List<Attribute> attributes = new ArrayList<Attribute>(); + private Map<String, TemplateElement> elements = new HashMap<String, TemplateElement>(); + private String textName = null; + private Text text = null; + private boolean hasImplicitElement = false; + + /** + * Name of the definition + * @param name the name of the definition + */ + public void setName(String name) { + this.name = name; + } + + /** + * Add the text element. + * @param text the nested text element to add + * @since ant 1.6.1 + */ + public void addConfiguredText(Text text) { + if (this.text != null) { + throw new BuildException( + "Only one nested text element allowed"); + } + if (text.getName() == null) { + throw new BuildException( + "the text nested element needed a \"name\" attribute"); + } + // Check if used by attributes + for (Attribute attribute : attributes) { + if (text.getName().equals(attribute.getName())) { + throw new BuildException( + "the name \"" + text.getName() + + "\" is already used as an attribute"); + } + } + this.text = text; + this.textName = text.getName(); + } + + /** + * @return the nested text element + * @since ant 1.6.1 + */ + public Text getText() { + return text; + } + + /** + * Set the backTrace attribute. + * + * @param backTrace if true and the macro instance generates + * an error, a backtrace of the location within + * the macro and call to the macro will be output. + * if false, only the location of the call to the + * macro will be shown. Default is true. + * @since ant 1.7 + */ + public void setBackTrace(boolean backTrace) { + this.backTrace = backTrace; + } + + /** + * @return the backTrace attribute. + * @since ant 1.7 + */ + public boolean getBackTrace() { + return backTrace; + } + + /** + * This is the sequential nested element of the macrodef. + * + * @return a sequential element to be configured. + */ + public NestedSequential createSequential() { + if (this.nestedSequential != null) { + throw new BuildException("Only one sequential allowed"); + } + this.nestedSequential = new NestedSequential(); + return this.nestedSequential; + } + + /** + * The class corresponding to the sequential nested element. + * This is a simple task container. + */ + public static class NestedSequential implements TaskContainer { + private List<Task> nested = new ArrayList<Task>(); + + /** + * Add a task or type to the container. + * + * @param task an unknown element. + */ + public void addTask(Task task) { + nested.add(task); + } + + /** + * @return the list of unknown elements + */ + public List<Task> getNested() { + return nested; + } + + /** + * A compare function to compare this with another + * NestedSequential. + * It calls similar on the nested unknown elements. + * + * @param other the nested sequential to compare with. + * @return true if they are similar, false otherwise + */ + public boolean similar(NestedSequential other) { + final int size = nested.size(); + if (size != other.nested.size()) { + return false; + } + for (int i = 0; i < size; ++i) { + UnknownElement me = (UnknownElement) nested.get(i); + UnknownElement o = (UnknownElement) other.nested.get(i); + if (!me.similar(o)) { + return false; + } + } + return true; + } + } + + /** + * Convert the nested sequential to an unknown element + * @return the nested sequential as an unknown element. + */ + public UnknownElement getNestedTask() { + UnknownElement ret = new UnknownElement("sequential"); + ret.setTaskName("sequential"); + ret.setNamespace(""); + ret.setQName("sequential"); + new RuntimeConfigurable(ret, "sequential"); + final int size = nestedSequential.getNested().size(); + for (int i = 0; i < size; ++i) { + UnknownElement e = + (UnknownElement) nestedSequential.getNested().get(i); + ret.addChild(e); + ret.getWrapper().addChild(e.getWrapper()); + } + return ret; + } + + /** + * Gets this macro's attribute (and define?) list. + * + * @return the nested Attributes + */ + public List<Attribute> getAttributes() { + return attributes; + } + + /** + * Gets this macro's elements. + * + * @return the map nested elements, keyed by element name, with + * {@link TemplateElement} values. + */ + public Map<String, TemplateElement> getElements() { + return elements; + } + + /** + * Check if a character is a valid character for an element or + * attribute name. + * + * @param c the character to check + * @return true if the character is a letter or digit or '.' or '-' + * attribute name + */ + public static boolean isValidNameCharacter(char c) { + // ? is there an xml api for this ? + return Character.isLetterOrDigit(c) || c == '.' || c == '-'; + } + + /** + * Check if a string is a valid name for an element or attribute. + * + * @param name the string to check + * @return true if the name consists of valid name characters + */ + private static boolean isValidName(String name) { + if (name.length() == 0) { + return false; + } + for (int i = 0; i < name.length(); ++i) { + if (!isValidNameCharacter(name.charAt(i))) { + return false; + } + } + return true; + } + + /** + * Add an attribute element. + * + * @param attribute an attribute nested element. + */ + public void addConfiguredAttribute(Attribute attribute) { + if (attribute.getName() == null) { + throw new BuildException( + "the attribute nested element needed a \"name\" attribute"); + } + if (attribute.getName().equals(textName)) { + throw new BuildException( + "the name \"" + attribute.getName() + + "\" has already been used by the text element"); + } + final int size = attributes.size(); + for (int i = 0; i < size; ++i) { + Attribute att = (Attribute) attributes.get(i); + if (att.getName().equals(attribute.getName())) { + throw new BuildException( + "the name \"" + attribute.getName() + + "\" has already been used in " + + "another attribute element"); + } + } + attributes.add(attribute); + } + + /** + * Add an element element. + * + * @param element an element nested element. + */ + public void addConfiguredElement(TemplateElement element) { + if (element.getName() == null) { + throw new BuildException( + "the element nested element needed a \"name\" attribute"); + } + if (elements.get(element.getName()) != null) { + throw new BuildException( + "the element " + element.getName() + + " has already been specified"); + } + if (hasImplicitElement + || (element.isImplicit() && elements.size() != 0)) { + throw new BuildException( + "Only one element allowed when using implicit elements"); + } + hasImplicitElement = element.isImplicit(); + elements.put(element.getName(), element); + } + + /** + * Create a new ant type based on the embedded tasks and types. + */ + public void execute() { + if (nestedSequential == null) { + throw new BuildException("Missing sequential element"); + } + if (name == null) { + throw new BuildException("Name not specified"); + } + + name = ProjectHelper.genComponentName(getURI(), name); + + MyAntTypeDefinition def = new MyAntTypeDefinition(this); + def.setName(name); + def.setClass(MacroInstance.class); + + ComponentHelper helper = ComponentHelper.getComponentHelper( + getProject()); + + helper.addDataTypeDefinition(def); + log("creating macro " + name, Project.MSG_VERBOSE); + } + + + /** + * An attribute for the MacroDef task. + * + */ + public static class Attribute { + private String name; + private String defaultValue; + private String description; + private boolean doubleExpanding = true; + + /** + * The name of the attribute. + * + * @param name the name of the attribute + */ + public void setName(String name) { + if (!isValidName(name)) { + throw new BuildException( + "Illegal name [" + name + "] for attribute"); + } + this.name = name.toLowerCase(Locale.ENGLISH); + } + + /** + * @return the name of the attribute + */ + public String getName() { + return name; + } + + /** + * The default value to use if the parameter is not + * used in the templated instance. + * + * @param defaultValue the default value + */ + public void setDefault(String defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * @return the default value, null if not set + */ + public String getDefault() { + return defaultValue; + } + + /** + * @param desc Description of the element. + * @since ant 1.6.1 + */ + public void setDescription(String desc) { + description = desc; + } + + /** + * @return the description of the element, or <code>null</code> if + * no description is available. + * @since ant 1.6.1 + */ + public String getDescription() { + return description; + } + + /** + * See {@link #isDoubleExpanding} for explanation. + * @param doubleExpanding true to expand twice, false for just once + * @since Ant 1.8.3 + */ + public void setDoubleExpanding(boolean doubleExpanding) { + this.doubleExpanding = doubleExpanding; + } + + /** + * Determines whether {@link RuntimeConfigurable#maybeConfigure(Project, boolean)} will reevaluate this property. + * For compatibility reasons (#52621) it will, though for most applications (#42046) it should not. + * @return true if expanding twice (the default), false for just once + * @since Ant 1.8.3 + */ + public boolean isDoubleExpanding() { + return doubleExpanding; + } + + /** + * equality method + * + * @param obj an <code>Object</code> value + * @return a <code>boolean</code> value + */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + Attribute other = (Attribute) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (defaultValue == null) { + if (other.defaultValue != null) { + return false; + } + } else if (!defaultValue.equals(other.defaultValue)) { + return false; + } + return true; + } + + /** + * @return a hash code value for this object. + */ + public int hashCode() { + return objectHashCode(defaultValue) + objectHashCode(name); + } + } + + /** + * A nested text element for the MacroDef task. + * @since ant 1.6.1 + */ + public static class Text { + private String name; + private boolean optional; + private boolean trim; + private String description; + private String defaultString; + + /** + * The name of the attribute. + * + * @param name the name of the attribute + */ + public void setName(String name) { + if (!isValidName(name)) { + throw new BuildException( + "Illegal name [" + name + "] for attribute"); + } + this.name = name.toLowerCase(Locale.ENGLISH); + } + + /** + * @return the name of the attribute + */ + public String getName() { + return name; + } + + /** + * The optional attribute of the text element. + * + * @param optional if true this is optional + */ + public void setOptional(boolean optional) { + this.optional = optional; + } + + /** + * @return true if the text is optional + */ + public boolean getOptional() { + return optional; + } + + /** + * The trim attribute of the text element. + * + * @param trim if true this String.trim() is called on + * the contents of the text element. + */ + public void setTrim(boolean trim) { + this.trim = trim; + } + + /** + * @return true if the text is trim + */ + public boolean getTrim() { + return trim; + } + + /** + * @param desc Description of the text. + */ + public void setDescription(String desc) { + description = desc; + } + + /** + * @return the description of the text, or <code>null</code> if + * no description is available. + */ + public String getDescription() { + return description; + } + + /** + * @param defaultString default text for the string. + */ + public void setDefault(String defaultString) { + this.defaultString = defaultString; + } + + /** + * @return the default text if set, null otherwise. + */ + public String getDefault() { + return defaultString; + } + + /** + * equality method + * + * @param obj an <code>Object</code> value + * @return a <code>boolean</code> value + */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + Text other = (Text) obj; + return safeCompare(name, other.name) + && optional == other.optional + && trim == other.trim + && safeCompare(defaultString, other.defaultString); + } + + /** + * @return a hash code value for this object. + */ + public int hashCode() { + return objectHashCode(name); + } + } + + private static boolean safeCompare(Object a, Object b) { + return a == null ? b == null : a.equals(b); + } + + /** + * A nested element for the MacroDef task. + */ + public static class TemplateElement { + + private String name; + private String description; + private boolean optional = false; + private boolean implicit = false; + + /** + * Sets the name of this element. + * + * @param name the name of the element + */ + public void setName(String name) { + if (!isValidName(name)) { + throw new BuildException( + "Illegal name [" + name + "] for macro element"); + } + this.name = name.toLowerCase(Locale.ENGLISH); + } + + /** + * Gets the name of this element. + * + * @return the name of the element. + */ + public String getName() { + return name; + } + + /** + * Sets a textual description of this element, + * for build documentation purposes only. + * + * @param desc Description of the element. + * @since ant 1.6.1 + */ + public void setDescription(String desc) { + description = desc; + } + + /** + * Gets the description of this element. + * + * @return the description of the element, or <code>null</code> if + * no description is available. + * @since ant 1.6.1 + */ + public String getDescription() { + return description; + } + + /** + * Sets whether this element is optional. + * + * @param optional if true this element may be left out, default + * is false. + */ + public void setOptional(boolean optional) { + this.optional = optional; + } + + /** + * Gets whether this element is optional. + * + * @return the optional attribute + */ + public boolean isOptional() { + return optional; + } + + /** + * Sets whether this element is implicit. + * + * @param implicit if true this element may be left out, default + * is false. + */ + public void setImplicit(boolean implicit) { + this.implicit = implicit; + } + + /** + * Gets whether this element is implicit. + * + * @return the implicit attribute + */ + public boolean isImplicit() { + return implicit; + } + + /** + * equality method. + * + * @param obj an <code>Object</code> value + * @return a <code>boolean</code> value + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || !obj.getClass().equals(getClass())) { + return false; + } + TemplateElement t = (TemplateElement) obj; + return + (name == null ? t.name == null : name.equals(t.name)) + && optional == t.optional + && implicit == t.implicit; + } + + /** + * @return a hash code value for this object. + */ + public int hashCode() { + return objectHashCode(name) + + (optional ? 1 : 0) + (implicit ? 1 : 0); + } + + } // END static class TemplateElement + + /** + * same or similar equality method for macrodef, ignores project and + * runtime info. + * + * @param obj an <code>Object</code> value + * @param same if true test for sameness, otherwise just similar + * @return a <code>boolean</code> value + */ + private boolean sameOrSimilar(Object obj, boolean same) { + if (obj == this) { + return true; + } + + if (obj == null) { + return false; + } + if (!obj.getClass().equals(getClass())) { + return false; + } + MacroDef other = (MacroDef) obj; + if (name == null) { + return other.name == null; + } + if (!name.equals(other.name)) { + return false; + } + // Allow two macro definitions with the same location + // to be treated as similar - bugzilla 31215 + if (other.getLocation() != null + && other.getLocation().equals(getLocation()) + && !same) { + return true; + } + if (text == null) { + if (other.text != null) { + return false; + } + } else { + if (!text.equals(other.text)) { + return false; + } + } + if (getURI() == null || getURI().equals("") + || getURI().equals(ProjectHelper.ANT_CORE_URI)) { + if (!(other.getURI() == null || other.getURI().equals("") + || other.getURI().equals(ProjectHelper.ANT_CORE_URI))) { + return false; + } + } else { + if (!getURI().equals(other.getURI())) { + return false; + } + } + + if (!nestedSequential.similar(other.nestedSequential)) { + return false; + } + if (!attributes.equals(other.attributes)) { + return false; + } + if (!elements.equals(other.elements)) { + return false; + } + return true; + } + + /** + * Similar method for this definition + * + * @param obj another definition + * @return true if the definitions are similar + */ + public boolean similar(Object obj) { + return sameOrSimilar(obj, false); + } + + /** + * Equality method for this definition + * + * @param obj another definition + * @return true if the definitions are the same + */ + public boolean sameDefinition(Object obj) { + return sameOrSimilar(obj, true); + } + + /** + * extends AntTypeDefinition, on create + * of the object, the template macro definition + * is given. + */ + private static class MyAntTypeDefinition extends AntTypeDefinition { + private MacroDef macroDef; + + /** + * Creates a new <code>MyAntTypeDefinition</code> instance. + * + * @param macroDef a <code>MacroDef</code> value + */ + public MyAntTypeDefinition(MacroDef macroDef) { + this.macroDef = macroDef; + } + + /** + * Create an instance of the definition. + * The instance may be wrapped in a proxy class. + * @param project the current project + * @return the created object + */ + public Object create(Project project) { + Object o = super.create(project); + if (o == null) { + return null; + } + ((MacroInstance) o).setMacroDef(macroDef); + return o; + } + + /** + * Equality method for this definition + * + * @param other another definition + * @param project the current project + * @return true if the definitions are the same + */ + public boolean sameDefinition(AntTypeDefinition other, Project project) { + if (!super.sameDefinition(other, project)) { + return false; + } + MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other; + return macroDef.sameDefinition(otherDef.macroDef); + } + + /** + * Similar method for this definition + * + * @param other another definition + * @param project the current project + * @return true if the definitions are the same + */ + public boolean similarDefinition( + AntTypeDefinition other, Project project) { + if (!super.similarDefinition(other, project)) { + return false; + } + MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other; + return macroDef.similar(otherDef.macroDef); + } + } + + private static int objectHashCode(Object o) { + if (o == null) { + return 0; + } else { + return o.hashCode(); + } + } + +} |