git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276622 13f79535-47bb-0310-9956-ffa450edef68master
@@ -44,7 +44,7 @@ import org.apache.tools.ant.util.LoaderUtils; | |||||
* class will then use this loader rather than the system class loader. | * class will then use this loader rather than the system class loader. | ||||
* | * | ||||
*/ | */ | ||||
public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||||
private static final FileUtils fileUtils = FileUtils.newFileUtils(); | private static final FileUtils fileUtils = FileUtils.newFileUtils(); | ||||
@@ -118,7 +118,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
private void findNextResource() { | private void findNextResource() { | ||||
URL url = null; | URL url = null; | ||||
while ((pathElementsIndex < pathComponents.size()) | while ((pathElementsIndex < pathComponents.size()) | ||||
&& (url == null)) { | |||||
&& (url == null)) { | |||||
try { | try { | ||||
File pathComponent | File pathComponent | ||||
= (File) pathComponents.elementAt(pathElementsIndex); | = (File) pathComponents.elementAt(pathElementsIndex); | ||||
@@ -222,7 +222,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
Class protectionDomain | Class protectionDomain | ||||
= Class.forName("java.security.ProtectionDomain"); | = Class.forName("java.security.ProtectionDomain"); | ||||
Class[] args = new Class[] {String.class, byte[].class, | Class[] args = new Class[] {String.class, byte[].class, | ||||
Integer.TYPE, Integer.TYPE, protectionDomain}; | |||||
Integer.TYPE, Integer.TYPE, protectionDomain}; | |||||
defineClassProtectionDomain | defineClassProtectionDomain | ||||
= ClassLoader.class.getDeclaredMethod("defineClass", args); | = ClassLoader.class.getDeclaredMethod("defineClass", args); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
@@ -392,9 +392,9 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
if (project != null) { | if (project != null) { | ||||
project.log(message, priority); | project.log(message, priority); | ||||
} | } | ||||
// else { | |||||
// System.out.println(message); | |||||
// } | |||||
// else { | |||||
// System.out.println(message); | |||||
// } | |||||
} | } | ||||
/** | /** | ||||
@@ -442,7 +442,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
public void addPathElement(String pathElement) throws BuildException { | public void addPathElement(String pathElement) throws BuildException { | ||||
File pathComponent | File pathComponent | ||||
= project != null ? project.resolveFile(pathElement) | = project != null ? project.resolveFile(pathElement) | ||||
: new File(pathElement); | |||||
: new File(pathElement); | |||||
try { | try { | ||||
addPathFile(pathComponent); | addPathFile(pathComponent); | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
@@ -582,7 +582,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
* on this loader's classpath. | * on this loader's classpath. | ||||
*/ | */ | ||||
public Class forceLoadClass(String classname) | public Class forceLoadClass(String classname) | ||||
throws ClassNotFoundException { | |||||
throws ClassNotFoundException { | |||||
log("force loading " + classname, Project.MSG_DEBUG); | log("force loading " + classname, Project.MSG_DEBUG); | ||||
Class theClass = findLoadedClass(classname); | Class theClass = findLoadedClass(classname); | ||||
@@ -611,7 +611,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
* on this loader's classpath. | * on this loader's classpath. | ||||
*/ | */ | ||||
public Class forceLoadSystemClass(String classname) | public Class forceLoadSystemClass(String classname) | ||||
throws ClassNotFoundException { | |||||
throws ClassNotFoundException { | |||||
log("force system loading " + classname, Project.MSG_DEBUG); | log("force system loading " + classname, Project.MSG_DEBUG); | ||||
Class theClass = findLoadedClass(classname); | Class theClass = findLoadedClass(classname); | ||||
@@ -815,7 +815,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
URL url = null; | URL url = null; | ||||
if (isParentFirst(name)) { | if (isParentFirst(name)) { | ||||
url = (parent == null) ? super.getResource(name) | url = (parent == null) ? super.getResource(name) | ||||
: parent.getResource(name); | |||||
: parent.getResource(name); | |||||
} | } | ||||
if (url != null) { | if (url != null) { | ||||
@@ -907,7 +907,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
if (entry != null) { | if (entry != null) { | ||||
try { | try { | ||||
return new URL("jar:" + fileUtils.getFileURL(file) | return new URL("jar:" + fileUtils.getFileURL(file) | ||||
+ "!/" + entry); | |||||
+ "!/" + entry); | |||||
} catch (MalformedURLException ex) { | } catch (MalformedURLException ex) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -941,7 +941,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
* classpath. | * classpath. | ||||
*/ | */ | ||||
protected synchronized Class loadClass(String classname, boolean resolve) | protected synchronized Class loadClass(String classname, boolean resolve) | ||||
throws ClassNotFoundException { | |||||
throws ClassNotFoundException { | |||||
// 'sync' is needed - otherwise 2 threads can load the same class | // 'sync' is needed - otherwise 2 threads can load the same class | ||||
// twice, resulting in LinkageError: duplicated class definition. | // twice, resulting in LinkageError: duplicated class definition. | ||||
// findLoadedClass avoids that, but without sync it won't work. | // findLoadedClass avoids that, but without sync it won't work. | ||||
@@ -1059,8 +1059,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
* reading the class from the stream. | * reading the class from the stream. | ||||
*/ | */ | ||||
private Class getClassFromStream(InputStream stream, String classname, | private Class getClassFromStream(InputStream stream, String classname, | ||||
File container) | |||||
throws IOException, SecurityException { | |||||
File container) | |||||
throws IOException, SecurityException { | |||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||||
int bytesRead = -1; | int bytesRead = -1; | ||||
byte[] buffer = new byte[BUFFER_SIZE]; | byte[] buffer = new byte[BUFFER_SIZE]; | ||||
@@ -1120,7 +1120,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
* on this loader's classpath. | * on this loader's classpath. | ||||
*/ | */ | ||||
private Class findClassInComponents(String name) | private Class findClassInComponents(String name) | ||||
throws ClassNotFoundException { | |||||
throws ClassNotFoundException { | |||||
// we need to search the components of the path to see if | // we need to search the components of the path to see if | ||||
// we can find the class we want. | // we can find the class we want. | ||||
InputStream stream = null; | InputStream stream = null; | ||||
@@ -1219,6 +1219,31 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||||
cleanup(); | cleanup(); | ||||
} | } | ||||
/** | |||||
* Cleans up any resources held by this classloader at the end of | |||||
* a subbuild if it has been created for the subbuild's project | |||||
* instance. | |||||
* | |||||
* @param event the buildFinished event | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public void subBuildFinished(BuildEvent event) { | |||||
if (event.getProject() == project) { | |||||
cleanup(); | |||||
} | |||||
} | |||||
/** | |||||
* Empty implementation to satisfy the BuildListener interface. | |||||
* | |||||
* @param event the buildStarted event | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public void subBuildStarted(BuildEvent event) { | |||||
} | |||||
/** | /** | ||||
* Empty implementation to satisfy the BuildListener interface. | * Empty implementation to satisfy the BuildListener interface. | ||||
* | * | ||||
@@ -1790,6 +1790,43 @@ public class Project { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* Sends a "subbuild started" event to the build listeners for | |||||
* this project. | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public void fireSubBuildStarted() { | |||||
BuildEvent event = new BuildEvent(this); | |||||
Iterator iter = listeners.iterator(); | |||||
while (iter.hasNext()) { | |||||
Object listener = iter.next(); | |||||
if (listener instanceof SubBuildListener) { | |||||
((SubBuildListener) listener).subBuildStarted(event); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Sends a "subbuild finished" event to the build listeners for | |||||
* this project. | |||||
* @param exception an exception indicating a reason for a build | |||||
* failure. May be <code>null</code>, indicating | |||||
* a successful build. | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public void fireSubBuildFinished(Throwable exception) { | |||||
BuildEvent event = new BuildEvent(this); | |||||
event.setException(exception); | |||||
Iterator iter = listeners.iterator(); | |||||
while (iter.hasNext()) { | |||||
Object listener = iter.next(); | |||||
if (listener instanceof SubBuildListener) { | |||||
((SubBuildListener) listener).subBuildFinished(event); | |||||
} | |||||
} | |||||
} | |||||
/** | /** | ||||
* Sends a "target started" event to the build listeners for this project. | * Sends a "target started" event to the build listeners for this project. | ||||
@@ -0,0 +1,57 @@ | |||||
/* | |||||
* Copyright 2004 The Apache Software Foundation | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* | |||||
*/ | |||||
package org.apache.tools.ant; | |||||
/** | |||||
* Instances of classes that implement this interface can register | |||||
* to be also notified when things happened during a subbuild. | |||||
* | |||||
* <p>A subbuild is a separate project instance created by the | |||||
* <code><ant></code> task family. These project instances will | |||||
* never fire the buildStarted and buildFinished events, but they will | |||||
* fire subBuildStarted/ and subBuildFinished. The main project | |||||
* instance - the one created by running Ant in the first place - will | |||||
* never invoke one of the methods of this interface.</p> | |||||
* | |||||
* @see BuildEvent | |||||
* @see Project#addBuildListener(BuildListener) | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public interface SubBuildListener extends BuildListener { | |||||
/** | |||||
* Signals that a subbuild has started. This event | |||||
* is fired before any targets have started. | |||||
* | |||||
* @param event An event with any relevant extra information. | |||||
* Must not be <code>null</code>. | |||||
*/ | |||||
void subBuildStarted(BuildEvent event); | |||||
/** | |||||
* Signals that the last target has finished. This event | |||||
* will still be fired if an error occurred during the build. | |||||
* | |||||
* @param event An event with any relevant extra information. | |||||
* Must not be <code>null</code>. | |||||
* | |||||
* @see BuildEvent#getException() | |||||
*/ | |||||
void subBuildFinished(BuildEvent event); | |||||
} |
@@ -379,32 +379,22 @@ public class Ant extends Task { | |||||
addReferences(); | addReferences(); | ||||
if (target != null && !"".equals(target)) { | if (target != null && !"".equals(target)) { | ||||
Throwable t = null; | |||||
try { | try { | ||||
log("Entering " + antFile + "...", Project.MSG_VERBOSE); | log("Entering " + antFile + "...", Project.MSG_VERBOSE); | ||||
newProject.fireSubBuildStarted(); | |||||
newProject.executeTarget(target); | newProject.executeTarget(target); | ||||
} catch (BuildException ex) { | } catch (BuildException ex) { | ||||
throw ProjectHelper.addLocationToBuildException( | |||||
ex, getLocation()); | |||||
} finally { | |||||
t = ProjectHelper | |||||
.addLocationToBuildException(ex, getLocation()); | |||||
throw (BuildException) t; | |||||
} finally { | |||||
log("Exiting " + antFile + ".", Project.MSG_VERBOSE); | log("Exiting " + antFile + ".", Project.MSG_VERBOSE); | ||||
newProject.fireSubBuildFinished(t); | |||||
} | } | ||||
} | } | ||||
} finally { | } finally { | ||||
// help the gc | // help the gc | ||||
Iterator iter = getBuildListeners(); | |||||
while (iter.hasNext()) { | |||||
newProject.removeBuildListener((BuildListener) iter.next()); | |||||
} | |||||
iter = newProject.getBuildListeners().iterator(); | |||||
while (iter.hasNext()) { | |||||
Object o = iter.next(); | |||||
if (o instanceof RecorderEntry) { | |||||
((RecorderEntry) o).close(); | |||||
} else if (o instanceof AntClassLoader) { | |||||
((AntClassLoader) o).cleanup(); | |||||
} | |||||
} | |||||
newProject = null; | newProject = null; | ||||
Enumeration e = properties.elements(); | Enumeration e = properties.elements(); | ||||
while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
@@ -211,7 +211,7 @@ public class Recorder extends Task { | |||||
throw new BuildException("Problems creating a recorder entry", | throw new BuildException("Problems creating a recorder entry", | ||||
ioe); | ioe); | ||||
} | } | ||||
proj.addBuildListener(entry); | |||||
entry.setProject(proj); | |||||
recorderEntries.put(name, entry); | recorderEntries.put(name, entry); | ||||
} else { | } else { | ||||
entry = (RecorderEntry) o; | entry = (RecorderEntry) o; | ||||
@@ -21,6 +21,7 @@ import org.apache.tools.ant.BuildEvent; | |||||
import org.apache.tools.ant.BuildLogger; | import org.apache.tools.ant.BuildLogger; | ||||
import org.apache.tools.ant.DefaultLogger; | import org.apache.tools.ant.DefaultLogger; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.SubBuildListener; | |||||
import org.apache.tools.ant.util.StringUtils; | import org.apache.tools.ant.util.StringUtils; | ||||
/** | /** | ||||
@@ -30,7 +31,7 @@ import org.apache.tools.ant.util.StringUtils; | |||||
* @version 0.5 | * @version 0.5 | ||||
* @since Ant 1.4 | * @since Ant 1.4 | ||||
*/ | */ | ||||
public class RecorderEntry implements BuildLogger { | |||||
public class RecorderEntry implements BuildLogger, SubBuildListener { | |||||
////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////// | ||||
// ATTRIBUTES | // ATTRIBUTES | ||||
@@ -47,6 +48,8 @@ public class RecorderEntry implements BuildLogger { | |||||
private long targetStartTime = 0L; | private long targetStartTime = 0L; | ||||
/** Strip task banners if true. */ | /** Strip task banners if true. */ | ||||
private boolean emacsMode = false; | private boolean emacsMode = false; | ||||
/** project instance the recorder is associated with */ | |||||
private Project project; | |||||
////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////// | ||||
// CONSTRUCTORS / INITIALIZERS | // CONSTRUCTORS / INITIALIZERS | ||||
@@ -99,7 +102,32 @@ public class RecorderEntry implements BuildLogger { | |||||
+ StringUtils.LINE_SEP); | + StringUtils.LINE_SEP); | ||||
error.printStackTrace(out); | error.printStackTrace(out); | ||||
} | } | ||||
close(); | |||||
cleanup(); | |||||
} | |||||
/** | |||||
* Cleans up any resources held by this recorder entry at the end | |||||
* of a subbuild if it has been created for the subbuild's project | |||||
* instance. | |||||
* | |||||
* @param event the buildFinished event | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public void subBuildFinished(BuildEvent event) { | |||||
if (event.getProject() == project) { | |||||
cleanup(); | |||||
} | |||||
} | |||||
/** | |||||
* Empty implementation to satisfy the BuildListener interface. | |||||
* | |||||
* @param event the buildStarted event | |||||
* | |||||
* @since Ant 1.6.2 | |||||
*/ | |||||
public void subBuildStarted(BuildEvent event) { | |||||
} | } | ||||
@@ -209,11 +237,29 @@ public class RecorderEntry implements BuildLogger { | |||||
} | } | ||||
/** | /** | ||||
* Set the project associated with this recorder entry. | |||||
* | |||||
* @param project the project instance | |||||
* | |||||
* @since 1.6.2 | * @since 1.6.2 | ||||
*/ | */ | ||||
public void close() { | |||||
public void setProject(Project project) { | |||||
this.project = project; | |||||
if (project != null) { | |||||
project.addBuildListener(this); | |||||
} | |||||
} | |||||
/** | |||||
* @since 1.6.2 | |||||
*/ | |||||
public void cleanup() { | |||||
out.flush(); | out.flush(); | ||||
out.close(); | out.close(); | ||||
if (project != null) { | |||||
project.removeBuildListener(this); | |||||
} | |||||
project = null; | |||||
} | } | ||||
} | } | ||||