diff --git a/src/main/org/apache/tools/ant/Project.java b/src/main/org/apache/tools/ant/Project.java index 60847f9cc..4d7af3cf6 100644 --- a/src/main/org/apache/tools/ant/Project.java +++ b/src/main/org/apache/tools/ant/Project.java @@ -114,6 +114,7 @@ public class Project { private String defaultTarget; private Hashtable dataClassDefinitions = new Hashtable(); private Hashtable taskClassDefinitions = new Hashtable(); + private Hashtable createdTasks = new Hashtable(); private Hashtable targets = new Hashtable(); private FilterSet globalFilterSet = new FilterSet(); private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet); @@ -589,9 +590,18 @@ public class Project { * conditions, that will cause the task execution to fail. */ public void addTaskDefinition(String taskName, Class taskClass) throws BuildException { - if (null != taskClassDefinitions.get(taskName)) { - log("Trying to override old definition of task "+taskName, - MSG_WARN); + Class old = (Class)taskClassDefinitions.get(taskName); + if (null != old) { + if (old.equals(taskClass)) { + log("Ignoring override for task " + taskName + + ", it is already defined by the same class.", + MSG_VERBOSE); + return; + } else { + log("Trying to override old definition of task "+taskName, + MSG_WARN); + invalidateCreatedTasks(taskName); + } } String msg = " +User task: " + taskName + " " + taskClass.getName(); @@ -751,6 +761,7 @@ public class Project { String msg = " +Task: " + taskType; log (msg, MSG_DEBUG); + addCreatedTask(taskType, task); return task; } catch (Throwable t) { String msg = "Could not create task of type: " @@ -759,6 +770,40 @@ public class Project { } } + /** + * Keep a record of all tasks that have been created so that they + * can be invalidated if a taskdef overrides the definition. + */ + private void addCreatedTask(String type, Task task) { + synchronized (createdTasks) { + Vector v = (Vector) createdTasks.get(type); + if (v == null) { + v = new Vector(); + createdTasks.put(type, v); + } + v.addElement(task); + } + } + + /** + * Mark tasks as invalid which no longer are of the correct type + * for a given taskname. + */ + private void invalidateCreatedTasks(String type) { + synchronized (createdTasks) { + Vector v = (Vector) createdTasks.get(type); + if (v != null) { + Enumeration enum = v.elements(); + while (enum.hasMoreElements()) { + Task t = (Task) enum.nextElement(); + t.markInvalid(); + } + v.removeAllElements(); + createdTasks.remove(type); + } + } + } + /** * create a new DataType instance * @param typeName name of the datatype diff --git a/src/main/org/apache/tools/ant/RuntimeConfigurable.java b/src/main/org/apache/tools/ant/RuntimeConfigurable.java index 15ddddd09..23668a635 100644 --- a/src/main/org/apache/tools/ant/RuntimeConfigurable.java +++ b/src/main/org/apache/tools/ant/RuntimeConfigurable.java @@ -138,7 +138,7 @@ public class RuntimeConfigurable { * Configure the wrapped element and all children. */ public void maybeConfigure(Project p) throws BuildException { - String id = null; + String id = null; if (attributes != null) { ProjectHelper.configure(wrappedObject, attributes, p); @@ -152,7 +152,13 @@ public class RuntimeConfigurable { Enumeration enum = children.elements(); while (enum.hasMoreElements()) { RuntimeConfigurable child = (RuntimeConfigurable) enum.nextElement(); - child.maybeConfigure(p); + if (child.wrappedObject instanceof Task) { + Task childTask = (Task) child.wrappedObject; + childTask.setRuntimeConfigurableWrapper(child); + childTask.maybeConfigure(); + } else { + child.maybeConfigure(p); + } ProjectHelper.storeChild(p, wrappedObject, child.wrappedObject, child.getElementTag().toLowerCase(Locale.US)); } diff --git a/src/main/org/apache/tools/ant/Target.java b/src/main/org/apache/tools/ant/Target.java index aa075e592..d69074217 100644 --- a/src/main/org/apache/tools/ant/Target.java +++ b/src/main/org/apache/tools/ant/Target.java @@ -210,7 +210,7 @@ public class Target implements TaskContainer { } } - void replaceChild(UnknownElement el, Object o) { + void replaceChild(Task el, Object o) { int index = -1; while ((index = children.indexOf(el)) >= 0) { children.setElementAt(o, index); diff --git a/src/main/org/apache/tools/ant/Task.java b/src/main/org/apache/tools/ant/Task.java index 9937a0716..b8cc37be4 100644 --- a/src/main/org/apache/tools/ant/Task.java +++ b/src/main/org/apache/tools/ant/Task.java @@ -68,6 +68,7 @@ public abstract class Task extends ProjectComponent { protected String taskName = null; protected String taskType = null; protected RuntimeConfigurable wrapper; + private boolean invalid = false; /** * Sets the target object of this task. @@ -174,8 +175,12 @@ public abstract class Task extends ProjectComponent { * Configure this task - if it hasn't been done already. */ public void maybeConfigure() throws BuildException { - if (wrapper != null) { - wrapper.maybeConfigure(project); + if (!invalid) { + if (wrapper != null) { + wrapper.maybeConfigure(project); + } + } else { + getReplacement(); } } @@ -211,22 +216,56 @@ public abstract class Task extends ProjectComponent { * Perform this task */ public final void perform() { - try { - project.fireTaskStarted(this); - maybeConfigure(); - execute(); - project.fireTaskFinished(this, null); - } - catch(RuntimeException exc) { - if (exc instanceof BuildException) { - BuildException be = (BuildException) exc; - if (be.getLocation() == Location.UNKNOWN_LOCATION) { - be.setLocation(getLocation()); + if (!invalid) { + try { + project.fireTaskStarted(this); + maybeConfigure(); + execute(); + project.fireTaskFinished(this, null); + } + catch(RuntimeException exc) { + if (exc instanceof BuildException) { + BuildException be = (BuildException) exc; + if (be.getLocation() == Location.UNKNOWN_LOCATION) { + be.setLocation(getLocation()); + } } + project.fireTaskFinished(this, exc); + throw exc; } - project.fireTaskFinished(this, exc); - throw exc; + } else { + UnknownElement ue = getReplacement(); + Task task = ue.getTask(); + task.perform(); + } + } + + /** + * Mark this task as invalid. + */ + final void markInvalid() { + invalid = true; + } + + private UnknownElement replacement; + + /** + * Create an UnknownElement that can be used to replace this task. + */ + private UnknownElement getReplacement() { + if (replacement == null) { + replacement = new UnknownElement(taskType); + replacement.setProject(project); + replacement.setTaskType(taskType); + replacement.setTaskName(taskName); + replacement.setLocation(location); + replacement.setOwningTarget(target); + replacement.setRuntimeConfigurableWrapper(wrapper); + wrapper.setProxy(replacement); + target.replaceChild(this, replacement); + replacement.maybeConfigure(); } + return replacement; } } diff --git a/src/main/org/apache/tools/ant/UnknownElement.java b/src/main/org/apache/tools/ant/UnknownElement.java index 3615eb160..af33d29f4 100644 --- a/src/main/org/apache/tools/ant/UnknownElement.java +++ b/src/main/org/apache/tools/ant/UnknownElement.java @@ -238,4 +238,14 @@ public class UnknownElement extends Task { super.getTaskName() : ((Task) realThing).getTaskName(); } + /** + * Return the task instance after it has been created (and if it is a task. + */ + public Task getTask() { + if (realThing != null && realThing instanceof Task) { + return (Task) realThing; + } + return null; + } + }// UnknownElement