diff --git a/src/etc/testcases/types/addtype.xml b/src/etc/testcases/types/addtype.xml new file mode 100644 index 000000000..88d93eb80 --- /dev/null +++ b/src/etc/testcases/types/addtype.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + This is line 1 + This is line 2 + This is line 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + before + + after + + + before + + after + + + + + + + + > + + + + + diff --git a/src/main/org/apache/tools/ant/ComponentHelper.java b/src/main/org/apache/tools/ant/ComponentHelper.java index 05ec724e9..574a7a05e 100644 --- a/src/main/org/apache/tools/ant/ComponentHelper.java +++ b/src/main/org/apache/tools/ant/ComponentHelper.java @@ -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 diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java index 93ee07751..b8dd4d1e2 100644 --- a/src/main/org/apache/tools/ant/IntrospectionHelper.java +++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java @@ -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; + } + } diff --git a/src/main/org/apache/tools/ant/filters/TokenFilter.java b/src/main/org/apache/tools/ant/filters/TokenFilter.java index 27d0a307d..ec1e35afb 100644 --- a/src/main/org/apache/tools/ant/filters/TokenFilter.java +++ b/src/main/org/apache/tools/ant/filters/TokenFilter.java @@ -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 diff --git a/src/main/org/apache/tools/ant/taskdefs/Delete.java b/src/main/org/apache/tools/ant/taskdefs/Delete.java index 9200043d4..93c373842 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Delete.java +++ b/src/main/org/apache/tools/ant/taskdefs/Delete.java @@ -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). */ diff --git a/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java b/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java index b7f72962b..a52d6a5ef 100644 --- a/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java @@ -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. * diff --git a/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java b/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java index b05967e8e..092b32352 100644 --- a/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java +++ b/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java @@ -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);} + } diff --git a/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/src/main/org/apache/tools/ant/types/AbstractFileSet.java index 56fccb58c..f4c82f65b 100644 --- a/src/main/org/apache/tools/ant/types/AbstractFileSet.java +++ b/src/main/org/apache/tools/ant/types/AbstractFileSet.java @@ -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 * diff --git a/src/main/org/apache/tools/ant/types/FilterChain.java b/src/main/org/apache/tools/ant/types/FilterChain.java index 321b15245..fa2cfac5c 100644 --- a/src/main/org/apache/tools/ant/types/FilterChain.java +++ b/src/main/org/apache/tools/ant/types/FilterChain.java @@ -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); } } diff --git a/src/main/org/apache/tools/ant/types/Path.java b/src/main/org/apache/tools/ant/types/Path.java index 6b7e6dccd..0516e3aea 100644 --- a/src/main/org/apache/tools/ant/types/Path.java +++ b/src/main/org/apache/tools/ant/types/Path.java @@ -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 <path> element. */ diff --git a/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java b/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java index b08618ee8..adf14f63b 100644 --- a/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java +++ b/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java @@ -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). * diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java index 81ab28937..479b4638e 100644 --- a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java +++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java @@ -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); + } + } diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java index 07b4b64d9..bbbf28a86 100644 --- a/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java +++ b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java @@ -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); } diff --git a/src/testcases/org/apache/tools/ant/types/AddTypeTest.java b/src/testcases/org/apache/tools/ant/types/AddTypeTest.java new file mode 100644 index 000000000..60ede5971 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/AddTypeTest.java @@ -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 + * . + */ + +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"); + } + } + +}