child elements of user defined tasks that override built-in tasks. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270141 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -114,6 +114,7 @@ public class Project { | |||||
| private String defaultTarget; | private String defaultTarget; | ||||
| private Hashtable dataClassDefinitions = new Hashtable(); | private Hashtable dataClassDefinitions = new Hashtable(); | ||||
| private Hashtable taskClassDefinitions = new Hashtable(); | private Hashtable taskClassDefinitions = new Hashtable(); | ||||
| private Hashtable createdTasks = new Hashtable(); | |||||
| private Hashtable targets = new Hashtable(); | private Hashtable targets = new Hashtable(); | ||||
| private FilterSet globalFilterSet = new FilterSet(); | private FilterSet globalFilterSet = new FilterSet(); | ||||
| private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet); | private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet); | ||||
| @@ -589,9 +590,18 @@ public class Project { | |||||
| * conditions, that will cause the task execution to fail. | * conditions, that will cause the task execution to fail. | ||||
| */ | */ | ||||
| public void addTaskDefinition(String taskName, Class taskClass) throws BuildException { | 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(); | String msg = " +User task: " + taskName + " " + taskClass.getName(); | ||||
| @@ -751,6 +761,7 @@ public class Project { | |||||
| String msg = " +Task: " + taskType; | String msg = " +Task: " + taskType; | ||||
| log (msg, MSG_DEBUG); | log (msg, MSG_DEBUG); | ||||
| addCreatedTask(taskType, task); | |||||
| return task; | return task; | ||||
| } catch (Throwable t) { | } catch (Throwable t) { | ||||
| String msg = "Could not create task of type: " | 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 | * create a new DataType instance | ||||
| * @param typeName name of the datatype | * @param typeName name of the datatype | ||||
| @@ -138,7 +138,7 @@ public class RuntimeConfigurable { | |||||
| * Configure the wrapped element and all children. | * Configure the wrapped element and all children. | ||||
| */ | */ | ||||
| public void maybeConfigure(Project p) throws BuildException { | public void maybeConfigure(Project p) throws BuildException { | ||||
| String id = null; | |||||
| String id = null; | |||||
| if (attributes != null) { | if (attributes != null) { | ||||
| ProjectHelper.configure(wrappedObject, attributes, p); | ProjectHelper.configure(wrappedObject, attributes, p); | ||||
| @@ -152,7 +152,13 @@ public class RuntimeConfigurable { | |||||
| Enumeration enum = children.elements(); | Enumeration enum = children.elements(); | ||||
| while (enum.hasMoreElements()) { | while (enum.hasMoreElements()) { | ||||
| RuntimeConfigurable child = (RuntimeConfigurable) enum.nextElement(); | 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)); | ProjectHelper.storeChild(p, wrappedObject, child.wrappedObject, child.getElementTag().toLowerCase(Locale.US)); | ||||
| } | } | ||||
| @@ -210,7 +210,7 @@ public class Target implements TaskContainer { | |||||
| } | } | ||||
| } | } | ||||
| void replaceChild(UnknownElement el, Object o) { | |||||
| void replaceChild(Task el, Object o) { | |||||
| int index = -1; | int index = -1; | ||||
| while ((index = children.indexOf(el)) >= 0) { | while ((index = children.indexOf(el)) >= 0) { | ||||
| children.setElementAt(o, index); | children.setElementAt(o, index); | ||||
| @@ -68,6 +68,7 @@ public abstract class Task extends ProjectComponent { | |||||
| protected String taskName = null; | protected String taskName = null; | ||||
| protected String taskType = null; | protected String taskType = null; | ||||
| protected RuntimeConfigurable wrapper; | protected RuntimeConfigurable wrapper; | ||||
| private boolean invalid = false; | |||||
| /** | /** | ||||
| * Sets the target object of this task. | * 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. | * Configure this task - if it hasn't been done already. | ||||
| */ | */ | ||||
| public void maybeConfigure() throws BuildException { | 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 | * Perform this task | ||||
| */ | */ | ||||
| public final void perform() { | 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; | |||||
| } | } | ||||
| } | } | ||||
| @@ -238,4 +238,14 @@ public class UnknownElement extends Task { | |||||
| super.getTaskName() : ((Task) realThing).getTaskName(); | 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 | }// UnknownElement | ||||