| @@ -0,0 +1,115 @@ | |||
| <project name="test" basedir="."> | |||
| <target name="addpath"> | |||
| <typedef name="mypath" classname="org.apache.tools.ant.types.Path"/> | |||
| <path> | |||
| <mypath path="build.xml"/> | |||
| </path> | |||
| </target> | |||
| <target name="addcondition"> | |||
| <typedef name="mycondition" | |||
| classname="org.apache.tools.ant.taskdefs.condition.Equals"/> | |||
| <condition property="mycondition.set"> | |||
| <mycondition arg1="string" arg2="string"/> | |||
| </condition> | |||
| <fail unless="mycondition.set"/> | |||
| </target> | |||
| <target name="addfilter"> | |||
| <typedef name="headfilter2" | |||
| classname="org.apache.tools.ant.filters.HeadFilter"/> | |||
| <concat>This is line 1 | |||
| This is line 2 | |||
| This is line 3 | |||
| <filterchain> | |||
| <headfilter2 lines="2"/> | |||
| </filterchain> | |||
| </concat> | |||
| </target> | |||
| <target name="addselector"> | |||
| <typedef | |||
| name="myselector" | |||
| classname="org.apache.tools.ant.types.selectors.ContainsSelector"/> | |||
| <fileset id="myselector.test" dir="${basedir}" includes="*"> | |||
| <myselector text="myselector"/> | |||
| </fileset> | |||
| </target> | |||
| <target name="init"> | |||
| <property name="nested.package" value="org.apache.tools.ant.types."/> | |||
| <path id="test-classes"> | |||
| <pathelement location="../../../../build/testcases" /> | |||
| <pathelement path="${java.class.path}" /> | |||
| </path> | |||
| <typedef loaderref="nested.loader" classpathref="test-classes" | |||
| name = "nested.a" | |||
| classname="${nested.package}AddTypeTest$AImpl"/> | |||
| <typedef loaderref="nested.loader" classpathref="test-classes" | |||
| name = "nested.b" | |||
| classname="${nested.package}AddTypeTest$BImpl"/> | |||
| <typedef loaderref="nested.loader" classpathref="test-classes" | |||
| name = "nested.c" | |||
| classname="${nested.package}AddTypeTest$CImpl"/> | |||
| <typedef loaderref="nested.loader" classpathref="test-classes" | |||
| name = "nested.ab" | |||
| classname="${nested.package}AddTypeTest$ABImpl"/> | |||
| <taskdef loaderref="nested.loader" classpathref="test-classes" | |||
| name = "nested.container" | |||
| classname="${nested.package}AddTypeTest$NestedContainer"/> | |||
| <taskdef loaderref="nested.loader" classpathref="nested.classes" | |||
| name = "nested.condition.task" | |||
| classname="${nested.package}AddTypeTest$MyCondition"/> | |||
| <typedef loaderref="nested.loader" classpathref="nested.classes" | |||
| name = "nested.condition.type" | |||
| classname="${nested.package}AddTypeTest$MyCondition"/> | |||
| </target> | |||
| <target name="nested.a" depends="init"> | |||
| <nested.container> | |||
| <nested.a/> | |||
| </nested.container> | |||
| </target> | |||
| <target name="nested.b" depends="init"> | |||
| <nested.container> | |||
| <nested.b/> | |||
| </nested.container> | |||
| </target> | |||
| <target name="nested.c" depends="init"> | |||
| <nested.container> | |||
| <nested.c/> | |||
| </nested.container> | |||
| </target> | |||
| <target name="nested.ab" depends="init"> | |||
| <nested.container> | |||
| <nested.ab/> | |||
| </nested.container> | |||
| </target> | |||
| <!-- tests for task adaptor --> | |||
| <target name="condition.type" depends="init"> | |||
| <echo>before</echo> | |||
| <nested.condition.type/> | |||
| <echo>after</echo> | |||
| </target> | |||
| <target name="condition.task" depends="init"> | |||
| <echo>before</echo> | |||
| <nested.condition.task/> | |||
| <echo>after</echo> | |||
| </target> | |||
| <target name="condition.condition.type" depends="init"> | |||
| <condition property="condition.condition.type"> | |||
| <nested.condition.type/> | |||
| </condition> | |||
| </target> | |||
| <target name="condition.condition.task" depends="init"> | |||
| <condition property="condition.condition.task">> | |||
| <nested.condition.task/> | |||
| </condition> | |||
| </target> | |||
| </project> | |||
| @@ -161,6 +161,41 @@ public class ComponentHelper { | |||
| return component; | |||
| } | |||
| /** | |||
| * get the class of a particular component | |||
| */ | |||
| public Class getComponentClass(String componentName) { | |||
| Class elementClass = | |||
| (Class) getTaskDefinitions().get(componentName); | |||
| if (elementClass != null) { | |||
| if (! (Task.class.isAssignableFrom(elementClass))) { | |||
| elementClass = TaskAdapter.class; | |||
| } | |||
| return elementClass; | |||
| } | |||
| return (Class) getDataTypeDefinitions().get(componentName); | |||
| } | |||
| /** | |||
| * create a named component | |||
| */ | |||
| public Object createComponent(String componentName) | |||
| throws BuildException | |||
| { | |||
| Object obj = createTask(componentName); | |||
| if (obj == null) { | |||
| obj = createDataType(componentName); | |||
| } | |||
| if (obj == null) { | |||
| return obj; | |||
| } | |||
| project.setProjectReference(obj); | |||
| if (obj instanceof Task) { | |||
| ((Task)obj).init(); // Needed here ?? | |||
| } | |||
| return obj; | |||
| } | |||
| /** Initialization code - implementing the original ant component | |||
| * loading from /org/apache/tools/ant/taskdefs/default.properties | |||
| * and .../types/default.properties | |||
| @@ -58,8 +58,10 @@ import java.io.File; | |||
| import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import java.util.ArrayList; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.List; | |||
| import java.util.Locale; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Path; | |||
| @@ -97,6 +99,11 @@ public class IntrospectionHelper implements BuildListener { | |||
| */ | |||
| private Hashtable nestedCreators; | |||
| /** | |||
| * Vector of methods matching add[Configured](Class) pattern | |||
| */ | |||
| private List addTypeMethods; | |||
| /** | |||
| * Map from attribute names to methods to store configured nested types | |||
| * (String to NestedStorer). | |||
| @@ -199,6 +206,7 @@ public class IntrospectionHelper implements BuildListener { | |||
| nestedTypes = new Hashtable(); | |||
| nestedCreators = new Hashtable(); | |||
| nestedStorers = new Hashtable(); | |||
| addTypeMethods = new ArrayList(); | |||
| this.bean = bean; | |||
| @@ -209,6 +217,14 @@ public class IntrospectionHelper implements BuildListener { | |||
| Class returnType = m.getReturnType(); | |||
| Class[] args = m.getParameterTypes(); | |||
| // check of add[Configured](Class) pattern | |||
| if (args.length == 1 | |||
| && java.lang.Void.TYPE.equals(returnType) | |||
| && (name.equals("add") /*|| name.equals("addConfigured")*/)) { | |||
| insertAddTypeMethod(m); | |||
| continue; | |||
| } | |||
| // not really user settable properties on tasks | |||
| if (org.apache.tools.ant.Task.class.isAssignableFrom(bean) | |||
| && args.length == 1 && isHiddenSetMethod(name, args[0])) { | |||
| @@ -534,6 +550,16 @@ public class IntrospectionHelper implements BuildListener { | |||
| public Object createElement(Project project, Object parent, | |||
| String elementName) throws BuildException { | |||
| NestedCreator nc = (NestedCreator) nestedCreators.get(elementName); | |||
| if (nc == null && addTypeMethods.size() > 0) { | |||
| Object nestedElement = createAddTypeElement( | |||
| project, parent, elementName); | |||
| if (nestedElement != null) { | |||
| if (project != null) { | |||
| project.setProjectReference(nestedElement); | |||
| } | |||
| return nestedElement; | |||
| } | |||
| } | |||
| if (nc == null && parent instanceof DynamicConfigurator) { | |||
| DynamicConfigurator dc = (DynamicConfigurator) parent; | |||
| Object nestedElement = dc.createDynamicElement(elementName); | |||
| @@ -578,7 +604,8 @@ public class IntrospectionHelper implements BuildListener { | |||
| */ | |||
| public boolean supportsNestedElement(String elementName) { | |||
| return nestedCreators.containsKey(elementName) || | |||
| DynamicConfigurator.class.isAssignableFrom(bean); | |||
| DynamicConfigurator.class.isAssignableFrom(bean) || | |||
| addTypeMethods.size() != 0; | |||
| } | |||
| /** | |||
| @@ -978,4 +1005,102 @@ public class IntrospectionHelper implements BuildListener { | |||
| * @param event Ignored in this implementation. | |||
| */ | |||
| public void messageLogged(BuildEvent event) {} | |||
| /** | |||
| * Check if the parent accepts a typed nested element | |||
| * and if so, create the object, call the parents | |||
| * addmethod. | |||
| * This method is part of the initial support | |||
| * for add(Type) and addConfigured(Type). | |||
| * AddConfigured(Type) will be done later. | |||
| */ | |||
| private Object createAddTypeElement( | |||
| Project project, Object parent, String elementName) | |||
| { | |||
| ComponentHelper helper = ComponentHelper.getComponentHelper(project); | |||
| Object addedObject = null; | |||
| Method addMethod = null; | |||
| Class clazz = helper.getComponentClass(elementName); | |||
| if (clazz == null) { | |||
| return null; | |||
| } | |||
| addMethod = findMatchingMethod(clazz, addTypeMethods); | |||
| if (addMethod == null) { | |||
| return null; | |||
| } | |||
| addedObject = helper.createComponent(elementName); | |||
| if (addedObject == null) { | |||
| return null; | |||
| } | |||
| try { | |||
| addMethod.invoke(parent, new Object[] {addedObject}); | |||
| } catch (IllegalAccessException ex) { | |||
| throw new BuildException(ex); | |||
| } catch (InvocationTargetException ex) { | |||
| Throwable t = ex.getTargetException(); | |||
| if (t instanceof BuildException) { | |||
| throw (BuildException) t; | |||
| } | |||
| throw new BuildException(t); | |||
| } catch (Throwable t) { | |||
| throw new BuildException(t); | |||
| } | |||
| return addedObject; | |||
| } | |||
| /** | |||
| * Inserts an add or addConfigured method into | |||
| * the addTypeMethods array. The array is | |||
| * ordered so that the more derived classes | |||
| * are first. | |||
| */ | |||
| private void insertAddTypeMethod(Method method) { | |||
| Class argClass = method.getParameterTypes()[0]; | |||
| for (int c = 0; c < addTypeMethods.size(); ++c) { | |||
| Method current = (Method) addTypeMethods.get(c); | |||
| if (current.getParameterTypes()[0].equals(argClass)) { | |||
| return; // Already present | |||
| } | |||
| if (current.getParameterTypes()[0].isAssignableFrom( | |||
| argClass)) { | |||
| addTypeMethods.add(c, method); | |||
| return; // higher derived | |||
| } | |||
| } | |||
| addTypeMethods.add(method); | |||
| } | |||
| /** | |||
| * Search the list of methods to find the first method | |||
| * that has a parameter that accepts the nested element object | |||
| */ | |||
| private Method findMatchingMethod(Class paramClass, List methods) { | |||
| Class matchedClass = null; | |||
| Method matchedMethod = null; | |||
| for (int i = 0; i < methods.size(); ++i) { | |||
| Method method = (Method) methods.get(i); | |||
| Class methodClass = method.getParameterTypes()[0]; | |||
| if (methodClass.isAssignableFrom(paramClass)) { | |||
| if (matchedClass == null) { | |||
| matchedClass = methodClass; | |||
| matchedMethod = method; | |||
| } else { | |||
| if (! methodClass.isAssignableFrom(matchedClass)) { | |||
| throw new BuildException( | |||
| "ambiguous: types " + matchedClass.getName() + | |||
| " and " + methodClass.getName() + | |||
| " match " + paramClass.getName()); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return matchedMethod; | |||
| } | |||
| } | |||
| @@ -59,8 +59,8 @@ import java.util.Hashtable; | |||
| import java.util.Vector; | |||
| import java.util.Enumeration; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DynamicConfigurator; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Parameter; | |||
| import org.apache.tools.ant.types.RegularExpression; | |||
| @@ -80,7 +80,7 @@ import org.apache.tools.ant.util.regexp.Regexp; | |||
| */ | |||
| public class TokenFilter | |||
| extends BaseFilterReader | |||
| implements ChainableReader, DynamicConfigurator | |||
| implements ChainableReader | |||
| { | |||
| /** | |||
| * input stream tokenizers implement this interface | |||
| @@ -229,9 +229,7 @@ public class TokenFilter | |||
| */ | |||
| public void addLineTokenizer(LineTokenizer tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| this.tokenizer = tokenizer; | |||
| add(tokenizer); | |||
| } | |||
| /** | |||
| @@ -239,21 +237,26 @@ public class TokenFilter | |||
| */ | |||
| public void addStringTokenizer(StringTokenizer tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| this.tokenizer = tokenizer; | |||
| add(tokenizer); | |||
| } | |||
| /** | |||
| * add a file tokenizer | |||
| */ | |||
| public void addFileTokenizer(FileTokenizer tokenizer) { | |||
| add(tokenizer); | |||
| } | |||
| /** | |||
| * add a tokenizer | |||
| */ | |||
| public void add(Tokenizer tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| this.tokenizer = tokenizer; | |||
| } | |||
| // ----------------------------------------- | |||
| // Predefined filters | |||
| // ----------------------------------------- | |||
| @@ -297,48 +300,7 @@ public class TokenFilter | |||
| filters.addElement(filter); | |||
| } | |||
| /** | |||
| * create the named datatype and check if it | |||
| * is a filter or a tokenizer | |||
| * | |||
| * @throws BuildException if unknown datatype or incorrect datatype | |||
| */ | |||
| public Object createDynamicElement(String name) | |||
| { | |||
| if (getProject() == null) | |||
| throw new BuildException( | |||
| "createDynamicElement.TokenFilter" + | |||
| " - Unable to get the project"); | |||
| Object obj = getProject().createDataType(name); | |||
| if (obj == null) | |||
| throw new BuildException("Unknown type " + name); | |||
| if (obj instanceof Filter) | |||
| filters.addElement(obj); | |||
| else if (obj instanceof Tokenizer) { | |||
| if (this.tokenizer != null) | |||
| throw new BuildException("Only one tokenizer allowed"); | |||
| tokenizer = (Tokenizer) obj; | |||
| } | |||
| else | |||
| throw new BuildException( | |||
| "type " + name + " is not a TokenFilter.Filter or " + | |||
| "TokenFiler.Tokenizer"); | |||
| return obj; | |||
| } | |||
| /** | |||
| * Needed for dynamic element support. | |||
| * | |||
| * @throws BuildException always | |||
| */ | |||
| public void setDynamicAttribute(String name, String value) { | |||
| throw new BuildException("Unknown attribute " + name); | |||
| } | |||
| // -------------------------------------------- | |||
| // | |||
| // Tokenizer Classes | |||
| @@ -349,6 +311,7 @@ public class TokenFilter | |||
| * class to read the complete input into a string | |||
| */ | |||
| public static class FileTokenizer | |||
| extends ProjectComponent | |||
| implements Tokenizer | |||
| { | |||
| /** | |||
| @@ -378,6 +341,7 @@ public class TokenFilter | |||
| * by \r (mac style), \r\n (dos/windows style) or \n (unix style) | |||
| */ | |||
| public static class LineTokenizer | |||
| extends ProjectComponent | |||
| implements Tokenizer | |||
| { | |||
| private String lineEnd = ""; | |||
| @@ -466,6 +430,7 @@ public class TokenFilter | |||
| * as delims flag is set). | |||
| */ | |||
| public static class StringTokenizer | |||
| extends ProjectComponent | |||
| implements Tokenizer | |||
| { | |||
| private String intraString = ""; | |||
| @@ -585,6 +550,7 @@ public class TokenFilter | |||
| // -------------------------------------------- | |||
| public static abstract class ChainableReaderFilter | |||
| extends ProjectComponent | |||
| implements ChainableReader, Filter | |||
| { | |||
| private boolean byLine = true; | |||
| @@ -596,7 +562,7 @@ public class TokenFilter | |||
| public Reader chain(Reader reader) { | |||
| TokenFilter tokenFilter = new TokenFilter(reader); | |||
| if (!byLine) | |||
| tokenFilter.addFileTokenizer(new FileTokenizer()); | |||
| tokenFilter.add(new FileTokenizer()); | |||
| tokenFilter.add(this); | |||
| return tokenFilter; | |||
| } | |||
| @@ -656,6 +622,7 @@ public class TokenFilter | |||
| * Simple filter to filter lines contains strings | |||
| */ | |||
| public static class ContainsString | |||
| extends ProjectComponent | |||
| implements Filter | |||
| { | |||
| private String contains; | |||
| @@ -818,6 +785,7 @@ public class TokenFilter | |||
| * Filter to delete characters | |||
| */ | |||
| public static class DeleteCharacters | |||
| extends ProjectComponent | |||
| implements Filter, ChainableReader | |||
| { | |||
| // Attributes | |||
| @@ -76,6 +76,7 @@ import org.apache.tools.ant.types.selectors.OrSelector; | |||
| import org.apache.tools.ant.types.selectors.PresentSelector; | |||
| import org.apache.tools.ant.types.selectors.SelectSelector; | |||
| import org.apache.tools.ant.types.selectors.SizeSelector; | |||
| import org.apache.tools.ant.types.selectors.FileSelector; | |||
| /** | |||
| * Deletes a file or directory, or set of files defined by a fileset. | |||
| @@ -418,6 +419,15 @@ public class Delete extends MatchingTask { | |||
| super.addContainsRegexp(selector); | |||
| } | |||
| /** | |||
| * add an arbitary selector | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(FileSelector selector) { | |||
| usedMatchingTask = true; | |||
| super.add(selector); | |||
| } | |||
| /** | |||
| * Delete the file(s). | |||
| */ | |||
| @@ -426,6 +426,7 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||
| public void addDifferent(DifferentSelector selector) { | |||
| fileset.addDifferent(selector); | |||
| } | |||
| /** | |||
| * add a type selector entry on the type list | |||
| * @param selector | |||
| @@ -435,6 +436,14 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||
| fileset.addType(selector); | |||
| } | |||
| /** | |||
| * add an arbitary selector | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(FileSelector selector) { | |||
| fileset.add(selector); | |||
| } | |||
| /** | |||
| * Accessor for the implict fileset. | |||
| * | |||
| @@ -1,7 +1,7 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2001-2002 The Apache Software Foundation. All rights | |||
| * Copyright (c) 2001-2003 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| @@ -203,4 +203,10 @@ public abstract class ConditionBase extends ProjectComponent { | |||
| */ | |||
| public void addIsReference(IsReference i) {conditions.addElement(i);} | |||
| /** | |||
| * Add an arbitary condition | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(Condition c) {conditions.addElement(c);} | |||
| } | |||
| @@ -649,6 +649,14 @@ public abstract class AbstractFileSet extends DataType implements Cloneable, | |||
| appendSelector(selector); | |||
| } | |||
| /** | |||
| * add an arbitary selector | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(FileSelector selector) { | |||
| appendSelector(selector); | |||
| } | |||
| /** | |||
| * Returns included files as a list of semicolon-separated filenames | |||
| * | |||
| @@ -59,7 +59,6 @@ import java.io.Reader; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DynamicConfigurator; | |||
| import org.apache.tools.ant.filters.ChainableReader; | |||
| import org.apache.tools.ant.filters.ClassConstants; | |||
| import org.apache.tools.ant.filters.EscapeUnicode; | |||
| @@ -85,7 +84,7 @@ import org.apache.tools.ant.taskdefs.Concat; | |||
| * @author Magesh Umasankar | |||
| */ | |||
| public final class FilterChain extends DataType | |||
| implements Cloneable, DynamicConfigurator | |||
| implements Cloneable | |||
| { | |||
| private Vector filterReaders = new Vector(); | |||
| @@ -246,38 +245,14 @@ public final class FilterChain extends DataType | |||
| super.setRefid(r); | |||
| } | |||
| /** | |||
| * create the named datatype and check if it | |||
| * is a filter. | |||
| * | |||
| * @throws BuildException if unknown datatype or incorrect datatype | |||
| * add a chainfilter | |||
| * @since Ant 1.6 | |||
| */ | |||
| public Object createDynamicElement(String name) | |||
| { | |||
| if (getProject() == null) | |||
| throw new BuildException("Unable to get the project"); | |||
| Object obj = getProject().createDataType(name); | |||
| if (obj == null) | |||
| throw new BuildException("Unknown type " + name); | |||
| if (! (obj instanceof ChainableReader)) | |||
| throw new BuildException( | |||
| "type " + name + " is not a filterreader"); | |||
| filterReaders.addElement(obj); | |||
| return obj; | |||
| } | |||
| /** | |||
| * Needed for dynamic element support. | |||
| * | |||
| * @throws BuildException always | |||
| */ | |||
| public void setDynamicAttribute(String name, String value) { | |||
| throw new BuildException("Unknown attribute " + name); | |||
| public void add(ChainableReader filter) { | |||
| filterReaders.addElement(filter); | |||
| } | |||
| } | |||
| @@ -220,6 +220,19 @@ public class Path extends DataType implements Cloneable { | |||
| setChecked( false ); | |||
| } | |||
| /** | |||
| * Adds a nested path | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(Path path) throws BuildException { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| elements.addElement(path); | |||
| setChecked( false ); | |||
| } | |||
| /** | |||
| * Creates a nested <code><path></code> element. | |||
| */ | |||
| @@ -79,8 +79,6 @@ import org.apache.tools.ant.Task; | |||
| public class ScriptFilter | |||
| extends TokenFilter.ChainableReaderFilter | |||
| { | |||
| /** The current project - set by ant reflection */ | |||
| private Project project; | |||
| /** The language - attribute of element */ | |||
| private String language; | |||
| /** The script - inline text or external file */ | |||
| @@ -94,16 +92,6 @@ public class ScriptFilter | |||
| /** the token used by the script */ | |||
| private String token; | |||
| /** Called by ant reflection to set the project */ | |||
| public void setProject(Project project) { | |||
| this.project = project; | |||
| } | |||
| /** this is provided to allow easier CAP from the ScriptTask */ | |||
| private Project getProject() { | |||
| return project; | |||
| } | |||
| /** | |||
| * Defines the language (required). | |||
| * | |||
| @@ -305,5 +305,14 @@ public abstract class BaseSelectorContainer extends BaseSelector | |||
| appendSelector(selector); | |||
| } | |||
| /** | |||
| * add an arbitary selector | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(FileSelector selector) { | |||
| appendSelector(selector); | |||
| } | |||
| } | |||
| @@ -189,5 +189,11 @@ public interface SelectorContainer { | |||
| * @since ant 1.6 | |||
| */ | |||
| public void addDifferent(DifferentSelector selector); | |||
| /** | |||
| * add an arbitary selector | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void add(FileSelector selector); | |||
| } | |||
| @@ -0,0 +1,164 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2002 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.types; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.taskdefs.condition.Condition; | |||
| public class AddTypeTest extends BuildFileTest { | |||
| public AddTypeTest(String name) { | |||
| super(name); | |||
| } | |||
| public void setUp() { | |||
| configureProject("src/etc/testcases/types/addtype.xml"); | |||
| } | |||
| public void testAddPath() { | |||
| executeTarget("addpath"); | |||
| } | |||
| public void testAddCondition() { | |||
| executeTarget("addcondition"); | |||
| } | |||
| public void testAddFilter() { | |||
| executeTarget("addfilter"); | |||
| } | |||
| public void testAddSelector() { | |||
| executeTarget("addselector"); | |||
| } | |||
| public void testNestedA() { | |||
| expectLogContaining("nested.a", "add A called"); | |||
| } | |||
| public void testNestedB() { | |||
| expectLogContaining("nested.b", "add B called"); | |||
| } | |||
| public void testNestedC() { | |||
| expectLogContaining("nested.c", "add C called"); | |||
| } | |||
| public void testNestedAB() { | |||
| expectBuildExceptionContaining( | |||
| "nested.ab", "Should have got ambiguous", "ambiguous"); | |||
| } | |||
| public void testConditionType() { | |||
| expectLogContaining("condition.type", "beforeafter"); | |||
| } | |||
| public void testConditionTask() { | |||
| expectLogContaining("condition.task", "My Condition execution"); | |||
| } | |||
| public void testConditionConditionType() { | |||
| expectLogContaining("condition.condition.type", "My Condition eval"); | |||
| } | |||
| public void testConditionConditionTask() { | |||
| expectBuildExceptionContaining( | |||
| "condition.condition.task", "task masking condition", | |||
| "doesn't support the nested"); | |||
| } | |||
| // The following will be used as types and tasks | |||
| public static interface A {} | |||
| public static interface B {} | |||
| public static interface C extends A {} | |||
| public static interface AB extends A, B {} | |||
| public static class AImpl implements A{} | |||
| public static class BImpl implements B{} | |||
| public static class CImpl implements C{} | |||
| public static class ABImpl implements AB{} | |||
| public static class NestedContainer | |||
| extends Task | |||
| { | |||
| public void add(A el) { | |||
| log("add A called"); | |||
| } | |||
| public void add(B el) { | |||
| log("add B called"); | |||
| } | |||
| public void add(C el) { | |||
| log("add C called"); | |||
| } | |||
| } | |||
| public static class MyCondition | |||
| implements Condition | |||
| { | |||
| Project project; | |||
| public void setProject(Project project) { | |||
| this.project = project; | |||
| } | |||
| public boolean eval() { | |||
| project.log("My Condition eval"); | |||
| return true; | |||
| } | |||
| public void execute() { | |||
| project.log("My Condition execution"); | |||
| } | |||
| } | |||
| } | |||