Browse Source

Avoid ConcurrentModificationException when iteratong over life-maps. PR 48310

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@908035 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 15 years ago
parent
commit
11b928d06e
4 changed files with 75 additions and 14 deletions
  1. +9
    -0
      WHATSNEW
  2. +53
    -4
      src/main/org/apache/tools/ant/Project.java
  3. +11
    -8
      src/main/org/apache/tools/ant/taskdefs/AntStructure.java
  4. +2
    -2
      src/main/org/apache/tools/ant/util/ScriptRunnerBase.java

+ 9
- 0
WHATSNEW View File

@@ -7,9 +7,18 @@ Changes that could break older environments:
Fixed bugs:
-----------

* Tasks that iterate over task or type definitions, references or
targets now iterate over copies instead of the live maps to avoid
ConcurrentModificationExceptions if another thread changes the
maps.
Bugzilla Report 48310.

Other changes:
--------------

* Project provides new get methods that return copies instead of the
live maps of task and type definitions, references and targets.

Changes from Ant 1.8.0RC1 TO Ant 1.8.0
======================================



+ 53
- 4
src/main/org/apache/tools/ant/Project.java View File

@@ -425,10 +425,10 @@ public class Project implements ResourceFactory {
}

/**
* Return a copy of the list of build listeners for the project.
*
* @return a list of build listeners for the project
*/
* Return a copy of the list of build listeners for the project.
*
* @return a list of build listeners for the project
*/
public Vector getBuildListeners() {
synchronized (listenersLock) {
Vector r = new Vector(listeners.length);
@@ -1024,6 +1024,19 @@ public class Project implements ResourceFactory {
return ComponentHelper.getComponentHelper(this).getTaskDefinitions();
}

/**
* Return the current task definition map. The returned map is a
* copy of the "live" definitions.
*
* @return a map of from task name to implementing class
* (String to Class).
*
* @since Ant 1.8.1
*/
public Map getCopyOfTaskDefinitions() {
return new HashMap(getTaskDefinitions());
}

/**
* Add a new datatype definition.
* Attempting to override an existing definition with an
@@ -1053,6 +1066,19 @@ public class Project implements ResourceFactory {
return ComponentHelper.getComponentHelper(this).getDataTypeDefinitions();
}

/**
* Return the current datatype definition map. The returned
* map is a copy pf the "live" definitions.
*
* @return a map of from datatype name to implementing class
* (String to Class).
*
* @since Ant 1.8.1
*/
public Map getCopyOfDataTypeDefinitions() {
return new HashMap(getDataTypeDefinitions());
}

/**
* Add a <em>new</em> target to the project.
*
@@ -1123,6 +1149,16 @@ public class Project implements ResourceFactory {
return targets;
}

/**
* Return the map of targets. The returned map
* is a copy of the &quot;live&quot; targets.
* @return a map from name to target (String to Target).
* @since Ant 1.8.1
*/
public Map getCopyOfTargets() {
return new HashMap(targets);
}

/**
* Create a new instance of a task, adding it to a list of
* created tasks for later invalidation. This causes all tasks
@@ -1970,6 +2006,19 @@ public class Project implements ResourceFactory {
return references.containsKey(key);
}

/**
* Return a map of the references in the project (String to
* Object). The returned hashtable is a copy of the
* &quot;live&quot; references.
*
* @return a map of the references in the project (String to Object).
*
* @since Ant 1.8.1
*/
public Map getCopyOfReferences() {
return new HashMap(references);
}

/**
* Look up a reference by its key (ID).
*


+ 11
- 8
src/main/org/apache/tools/ant/taskdefs/AntStructure.java View File

@@ -27,6 +27,7 @@ import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.IntrospectionHelper;
@@ -95,22 +96,24 @@ public class AntStructure extends Task {
}

printer.printHead(out, getProject(),
getProject().getTaskDefinitions(),
getProject().getDataTypeDefinitions());
new Hashtable(getProject().getTaskDefinitions()),
new Hashtable(getProject().getDataTypeDefinitions()));

printer.printTargetDecl(out);

Enumeration dataTypes = getProject().getDataTypeDefinitions().keys();
while (dataTypes.hasMoreElements()) {
String typeName = (String) dataTypes.nextElement();
Iterator dataTypes = getProject().getCopyOfDataTypeDefinitions()
.keySet().iterator();
while (dataTypes.hasNext()) {
String typeName = (String) dataTypes.next();
printer.printElementDecl(
out, getProject(), typeName,
(Class) getProject().getDataTypeDefinitions().get(typeName));
}

Enumeration tasks = getProject().getTaskDefinitions().keys();
while (tasks.hasMoreElements()) {
String tName = (String) tasks.nextElement();
Iterator tasks = getProject().getCopyOfTaskDefinitions().keySet()
.iterator();
while (tasks.hasNext()) {
String tName = (String) tasks.next();
printer.printElementDecl(out, getProject(), tName,
(Class) getProject().getTaskDefinitions().get(tName));
}


+ 2
- 2
src/main/org/apache/tools/ant/util/ScriptRunnerBase.java View File

@@ -306,8 +306,8 @@ public abstract class ScriptRunnerBase {
project = component.getProject();
addBeans(project.getProperties());
addBeans(project.getUserProperties());
addBeans(project.getTargets());
addBeans(project.getReferences());
addBeans(project.getCopyOfTargets());
addBeans(project.getCopyOfReferences());
addBean("project", project);
addBean("self", component);
}


Loading…
Cancel
Save