blob: 61548a619d03dc4d1e18b97e7ea8be77d4a02523 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "Ant" and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.ant.taskdefs;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
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.Task;
import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.UnknownElement;
import org.apache.tools.ant.types.EnumeratedAttribute;
/**
* Describe class <code>MacroDef</code> here.
*
* @author Peter Reilly
* @since Ant 1.6
*/
public class MacroDef extends AntlibDefinition implements TaskContainer {
private UnknownElement nestedTask;
private String name;
private List attributes = new ArrayList();
private Map elements = new HashMap();
/**
* Name of the definition
* @param name the name of the definition
*/
public void setName(String name) {
this.name = name;
}
/**
* Add a nested task to ExtendType
* @param nestedTask Nested task/type to extend
*/
public void addTask(Task nestedTask) {
if (this.nestedTask != null) {
throw new BuildException("Only one sequential/Parallel allowed");
}
UnknownElement ue = (UnknownElement) nestedTask;
if (!ue.getNamespace().equals("")
|| (!ue.getTag().equals("sequential")
&& !ue.getTag().equals("parallel"))) {
throw new BuildException("Unsupported tag " + ue.getQName());
}
this.nestedTask = ue;
}
/**
* @return the nested task
*/
public UnknownElement getNestedTask() {
return nestedTask;
}
/**
* @return the nested Attributes
*/
public List getAttributes() {
return attributes;
}
/**
* @return the nested elements
*/
public Map 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");
}
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");
}
elements.put(element.getName(), element);
}
/**
* Create a new ant type based on the embedded tasks and types.
*
*/
public void execute() {
if (nestedTask == null) {
throw new BuildException("Missing nested 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);
}
/**
* A nested element for the MacroDef task.
*
*/
public static class Attribute {
private String name;
private String defaultValue;
/**
* 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;
}
/**
* @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;
}
/**
* 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;
}
}
/**
* A nested element for the MacroDef task.
*
*/
public static class TemplateElement {
private String name;
private boolean optional = false;
/**
* The name of the element.
*
* @param name the name of the element.
*/
public void setName(String name) {
if (!isValidName(name)) {
throw new BuildException(
"Illegal name [" + name + "] for attribute");
}
this.name = name;
}
/**
* @return the name of the element.
*/
public String getName() {
return name;
}
/**
* is this element optional ?
*
* @param optional if true this element may be left out, default
* is false.
*/
public void setOptional(boolean optional) {
this.optional = optional;
}
/**
* @return the optional attribute
*/
public boolean isOptional() {
return optional;
}
/**
* 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;
}
TemplateElement other = (TemplateElement) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return optional == other.optional;
}
}
/**
* equality method for macrodef, ignores project and
* runtime info.
*
* @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().equals(getClass())) {
return false;
}
MacroDef other = (MacroDef) obj;
if (name == null) {
return other.name == null;
}
if (!name.equals(other.name)) {
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 (!nestedTask.similar(other.nestedTask)) {
return false;
}
if (!attributes.equals(other.attributes)) {
return false;
}
if (!elements.equals(other.elements)) {
return false;
}
return 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.equals(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.equals(otherDef.macroDef);
}
}
}