| @@ -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; | 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 | /** Initialization code - implementing the original ant component | ||||
| * loading from /org/apache/tools/ant/taskdefs/default.properties | * loading from /org/apache/tools/ant/taskdefs/default.properties | ||||
| * and .../types/default.properties | * and .../types/default.properties | ||||
| @@ -58,8 +58,10 @@ import java.io.File; | |||||
| import java.lang.reflect.Constructor; | import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
| import java.util.ArrayList; | |||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import java.util.List; | |||||
| import java.util.Locale; | import java.util.Locale; | ||||
| import org.apache.tools.ant.types.EnumeratedAttribute; | import org.apache.tools.ant.types.EnumeratedAttribute; | ||||
| import org.apache.tools.ant.types.Path; | import org.apache.tools.ant.types.Path; | ||||
| @@ -97,6 +99,11 @@ public class IntrospectionHelper implements BuildListener { | |||||
| */ | */ | ||||
| private Hashtable nestedCreators; | 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 | * Map from attribute names to methods to store configured nested types | ||||
| * (String to NestedStorer). | * (String to NestedStorer). | ||||
| @@ -199,6 +206,7 @@ public class IntrospectionHelper implements BuildListener { | |||||
| nestedTypes = new Hashtable(); | nestedTypes = new Hashtable(); | ||||
| nestedCreators = new Hashtable(); | nestedCreators = new Hashtable(); | ||||
| nestedStorers = new Hashtable(); | nestedStorers = new Hashtable(); | ||||
| addTypeMethods = new ArrayList(); | |||||
| this.bean = bean; | this.bean = bean; | ||||
| @@ -209,6 +217,14 @@ public class IntrospectionHelper implements BuildListener { | |||||
| Class returnType = m.getReturnType(); | Class returnType = m.getReturnType(); | ||||
| Class[] args = m.getParameterTypes(); | 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 | // not really user settable properties on tasks | ||||
| if (org.apache.tools.ant.Task.class.isAssignableFrom(bean) | if (org.apache.tools.ant.Task.class.isAssignableFrom(bean) | ||||
| && args.length == 1 && isHiddenSetMethod(name, args[0])) { | && args.length == 1 && isHiddenSetMethod(name, args[0])) { | ||||
| @@ -534,6 +550,16 @@ public class IntrospectionHelper implements BuildListener { | |||||
| public Object createElement(Project project, Object parent, | public Object createElement(Project project, Object parent, | ||||
| String elementName) throws BuildException { | String elementName) throws BuildException { | ||||
| NestedCreator nc = (NestedCreator) nestedCreators.get(elementName); | 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) { | if (nc == null && parent instanceof DynamicConfigurator) { | ||||
| DynamicConfigurator dc = (DynamicConfigurator) parent; | DynamicConfigurator dc = (DynamicConfigurator) parent; | ||||
| Object nestedElement = dc.createDynamicElement(elementName); | Object nestedElement = dc.createDynamicElement(elementName); | ||||
| @@ -578,7 +604,8 @@ public class IntrospectionHelper implements BuildListener { | |||||
| */ | */ | ||||
| public boolean supportsNestedElement(String elementName) { | public boolean supportsNestedElement(String elementName) { | ||||
| return nestedCreators.containsKey(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. | * @param event Ignored in this implementation. | ||||
| */ | */ | ||||
| public void messageLogged(BuildEvent event) {} | 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.Vector; | ||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.DynamicConfigurator; | |||||
| import org.apache.tools.ant.Project; | 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.EnumeratedAttribute; | ||||
| import org.apache.tools.ant.types.Parameter; | import org.apache.tools.ant.types.Parameter; | ||||
| import org.apache.tools.ant.types.RegularExpression; | import org.apache.tools.ant.types.RegularExpression; | ||||
| @@ -80,7 +80,7 @@ import org.apache.tools.ant.util.regexp.Regexp; | |||||
| */ | */ | ||||
| public class TokenFilter | public class TokenFilter | ||||
| extends BaseFilterReader | extends BaseFilterReader | ||||
| implements ChainableReader, DynamicConfigurator | |||||
| implements ChainableReader | |||||
| { | { | ||||
| /** | /** | ||||
| * input stream tokenizers implement this interface | * input stream tokenizers implement this interface | ||||
| @@ -229,9 +229,7 @@ public class TokenFilter | |||||
| */ | */ | ||||
| public void addLineTokenizer(LineTokenizer tokenizer) { | 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) { | 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 | * add a file tokenizer | ||||
| */ | */ | ||||
| public void addFileTokenizer(FileTokenizer tokenizer) { | public void addFileTokenizer(FileTokenizer tokenizer) { | ||||
| add(tokenizer); | |||||
| } | |||||
| /** | |||||
| * add a tokenizer | |||||
| */ | |||||
| public void add(Tokenizer tokenizer) { | |||||
| if (this.tokenizer != null) | if (this.tokenizer != null) | ||||
| throw new BuildException("Only one tokenizer allowed"); | throw new BuildException("Only one tokenizer allowed"); | ||||
| this.tokenizer = tokenizer; | this.tokenizer = tokenizer; | ||||
| } | } | ||||
| // ----------------------------------------- | // ----------------------------------------- | ||||
| // Predefined filters | // Predefined filters | ||||
| // ----------------------------------------- | // ----------------------------------------- | ||||
| @@ -297,48 +300,7 @@ public class TokenFilter | |||||
| filters.addElement(filter); | 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 | // Tokenizer Classes | ||||
| @@ -349,6 +311,7 @@ public class TokenFilter | |||||
| * class to read the complete input into a string | * class to read the complete input into a string | ||||
| */ | */ | ||||
| public static class FileTokenizer | public static class FileTokenizer | ||||
| extends ProjectComponent | |||||
| implements Tokenizer | implements Tokenizer | ||||
| { | { | ||||
| /** | /** | ||||
| @@ -378,6 +341,7 @@ public class TokenFilter | |||||
| * by \r (mac style), \r\n (dos/windows style) or \n (unix style) | * by \r (mac style), \r\n (dos/windows style) or \n (unix style) | ||||
| */ | */ | ||||
| public static class LineTokenizer | public static class LineTokenizer | ||||
| extends ProjectComponent | |||||
| implements Tokenizer | implements Tokenizer | ||||
| { | { | ||||
| private String lineEnd = ""; | private String lineEnd = ""; | ||||
| @@ -466,6 +430,7 @@ public class TokenFilter | |||||
| * as delims flag is set). | * as delims flag is set). | ||||
| */ | */ | ||||
| public static class StringTokenizer | public static class StringTokenizer | ||||
| extends ProjectComponent | |||||
| implements Tokenizer | implements Tokenizer | ||||
| { | { | ||||
| private String intraString = ""; | private String intraString = ""; | ||||
| @@ -585,6 +550,7 @@ public class TokenFilter | |||||
| // -------------------------------------------- | // -------------------------------------------- | ||||
| public static abstract class ChainableReaderFilter | public static abstract class ChainableReaderFilter | ||||
| extends ProjectComponent | |||||
| implements ChainableReader, Filter | implements ChainableReader, Filter | ||||
| { | { | ||||
| private boolean byLine = true; | private boolean byLine = true; | ||||
| @@ -596,7 +562,7 @@ public class TokenFilter | |||||
| public Reader chain(Reader reader) { | public Reader chain(Reader reader) { | ||||
| TokenFilter tokenFilter = new TokenFilter(reader); | TokenFilter tokenFilter = new TokenFilter(reader); | ||||
| if (!byLine) | if (!byLine) | ||||
| tokenFilter.addFileTokenizer(new FileTokenizer()); | |||||
| tokenFilter.add(new FileTokenizer()); | |||||
| tokenFilter.add(this); | tokenFilter.add(this); | ||||
| return tokenFilter; | return tokenFilter; | ||||
| } | } | ||||
| @@ -656,6 +622,7 @@ public class TokenFilter | |||||
| * Simple filter to filter lines contains strings | * Simple filter to filter lines contains strings | ||||
| */ | */ | ||||
| public static class ContainsString | public static class ContainsString | ||||
| extends ProjectComponent | |||||
| implements Filter | implements Filter | ||||
| { | { | ||||
| private String contains; | private String contains; | ||||
| @@ -818,6 +785,7 @@ public class TokenFilter | |||||
| * Filter to delete characters | * Filter to delete characters | ||||
| */ | */ | ||||
| public static class DeleteCharacters | public static class DeleteCharacters | ||||
| extends ProjectComponent | |||||
| implements Filter, ChainableReader | implements Filter, ChainableReader | ||||
| { | { | ||||
| // Attributes | // 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.PresentSelector; | ||||
| import org.apache.tools.ant.types.selectors.SelectSelector; | import org.apache.tools.ant.types.selectors.SelectSelector; | ||||
| import org.apache.tools.ant.types.selectors.SizeSelector; | 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. | * 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); | 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). | * Delete the file(s). | ||||
| */ | */ | ||||
| @@ -426,6 +426,7 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||||
| public void addDifferent(DifferentSelector selector) { | public void addDifferent(DifferentSelector selector) { | ||||
| fileset.addDifferent(selector); | fileset.addDifferent(selector); | ||||
| } | } | ||||
| /** | /** | ||||
| * add a type selector entry on the type list | * add a type selector entry on the type list | ||||
| * @param selector | * @param selector | ||||
| @@ -435,6 +436,14 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||||
| fileset.addType(selector); | fileset.addType(selector); | ||||
| } | } | ||||
| /** | |||||
| * add an arbitary selector | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public void add(FileSelector selector) { | |||||
| fileset.add(selector); | |||||
| } | |||||
| /** | /** | ||||
| * Accessor for the implict fileset. | * Accessor for the implict fileset. | ||||
| * | * | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * The Apache Software License, Version 1.1 | * 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. | * reserved. | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * 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);} | 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); | 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 | * Returns included files as a list of semicolon-separated filenames | ||||
| * | * | ||||
| @@ -59,7 +59,6 @@ import java.io.Reader; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import org.apache.tools.ant.BuildException; | 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.ChainableReader; | ||||
| import org.apache.tools.ant.filters.ClassConstants; | import org.apache.tools.ant.filters.ClassConstants; | ||||
| import org.apache.tools.ant.filters.EscapeUnicode; | import org.apache.tools.ant.filters.EscapeUnicode; | ||||
| @@ -85,7 +84,7 @@ import org.apache.tools.ant.taskdefs.Concat; | |||||
| * @author Magesh Umasankar | * @author Magesh Umasankar | ||||
| */ | */ | ||||
| public final class FilterChain extends DataType | public final class FilterChain extends DataType | ||||
| implements Cloneable, DynamicConfigurator | |||||
| implements Cloneable | |||||
| { | { | ||||
| private Vector filterReaders = new Vector(); | private Vector filterReaders = new Vector(); | ||||
| @@ -246,38 +245,14 @@ public final class FilterChain extends DataType | |||||
| super.setRefid(r); | 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 | * @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 ); | 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. | * Creates a nested <code><path></code> element. | ||||
| */ | */ | ||||
| @@ -79,8 +79,6 @@ import org.apache.tools.ant.Task; | |||||
| public class ScriptFilter | public class ScriptFilter | ||||
| extends TokenFilter.ChainableReaderFilter | extends TokenFilter.ChainableReaderFilter | ||||
| { | { | ||||
| /** The current project - set by ant reflection */ | |||||
| private Project project; | |||||
| /** The language - attribute of element */ | /** The language - attribute of element */ | ||||
| private String language; | private String language; | ||||
| /** The script - inline text or external file */ | /** The script - inline text or external file */ | ||||
| @@ -94,16 +92,6 @@ public class ScriptFilter | |||||
| /** the token used by the script */ | /** the token used by the script */ | ||||
| private String token; | 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). | * Defines the language (required). | ||||
| * | * | ||||
| @@ -305,5 +305,14 @@ public abstract class BaseSelectorContainer extends BaseSelector | |||||
| appendSelector(selector); | 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 | * @since ant 1.6 | ||||
| */ | */ | ||||
| public void addDifferent(DifferentSelector selector); | 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"); | |||||
| } | |||||
| } | |||||
| } | |||||