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. | |||
* | |||
*/ | |||
public class AntClassLoader extends ClassLoader implements BuildListener { | |||
public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||
private static final FileUtils fileUtils = FileUtils.newFileUtils(); | |||
@@ -118,7 +118,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
private void findNextResource() { | |||
URL url = null; | |||
while ((pathElementsIndex < pathComponents.size()) | |||
&& (url == null)) { | |||
&& (url == null)) { | |||
try { | |||
File pathComponent | |||
= (File) pathComponents.elementAt(pathElementsIndex); | |||
@@ -222,7 +222,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
Class protectionDomain | |||
= Class.forName("java.security.ProtectionDomain"); | |||
Class[] args = new Class[] {String.class, byte[].class, | |||
Integer.TYPE, Integer.TYPE, protectionDomain}; | |||
Integer.TYPE, Integer.TYPE, protectionDomain}; | |||
defineClassProtectionDomain | |||
= ClassLoader.class.getDeclaredMethod("defineClass", args); | |||
} catch (Exception e) { | |||
@@ -392,9 +392,9 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
if (project != null) { | |||
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 { | |||
File pathComponent | |||
= project != null ? project.resolveFile(pathElement) | |||
: new File(pathElement); | |||
: new File(pathElement); | |||
try { | |||
addPathFile(pathComponent); | |||
} catch (IOException e) { | |||
@@ -582,7 +582,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
* on this loader's classpath. | |||
*/ | |||
public Class forceLoadClass(String classname) | |||
throws ClassNotFoundException { | |||
throws ClassNotFoundException { | |||
log("force loading " + classname, Project.MSG_DEBUG); | |||
Class theClass = findLoadedClass(classname); | |||
@@ -611,7 +611,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
* on this loader's classpath. | |||
*/ | |||
public Class forceLoadSystemClass(String classname) | |||
throws ClassNotFoundException { | |||
throws ClassNotFoundException { | |||
log("force system loading " + classname, Project.MSG_DEBUG); | |||
Class theClass = findLoadedClass(classname); | |||
@@ -815,7 +815,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
URL url = null; | |||
if (isParentFirst(name)) { | |||
url = (parent == null) ? super.getResource(name) | |||
: parent.getResource(name); | |||
: parent.getResource(name); | |||
} | |||
if (url != null) { | |||
@@ -907,7 +907,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
if (entry != null) { | |||
try { | |||
return new URL("jar:" + fileUtils.getFileURL(file) | |||
+ "!/" + entry); | |||
+ "!/" + entry); | |||
} catch (MalformedURLException ex) { | |||
return null; | |||
} | |||
@@ -941,7 +941,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
* classpath. | |||
*/ | |||
protected synchronized Class loadClass(String classname, boolean resolve) | |||
throws ClassNotFoundException { | |||
throws ClassNotFoundException { | |||
// 'sync' is needed - otherwise 2 threads can load the same class | |||
// twice, resulting in LinkageError: duplicated class definition. | |||
// 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. | |||
*/ | |||
private Class getClassFromStream(InputStream stream, String classname, | |||
File container) | |||
throws IOException, SecurityException { | |||
File container) | |||
throws IOException, SecurityException { | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
int bytesRead = -1; | |||
byte[] buffer = new byte[BUFFER_SIZE]; | |||
@@ -1120,7 +1120,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
* on this loader's classpath. | |||
*/ | |||
private Class findClassInComponents(String name) | |||
throws ClassNotFoundException { | |||
throws ClassNotFoundException { | |||
// we need to search the components of the path to see if | |||
// we can find the class we want. | |||
InputStream stream = null; | |||
@@ -1219,6 +1219,31 @@ public class AntClassLoader extends ClassLoader implements BuildListener { | |||
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. | |||
* | |||
@@ -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. | |||
@@ -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(); | |||
if (target != null && !"".equals(target)) { | |||
Throwable t = null; | |||
try { | |||
log("Entering " + antFile + "...", Project.MSG_VERBOSE); | |||
newProject.fireSubBuildStarted(); | |||
newProject.executeTarget(target); | |||
} catch (BuildException ex) { | |||
throw ProjectHelper.addLocationToBuildException( | |||
ex, getLocation()); | |||
} finally { | |||
t = ProjectHelper | |||
.addLocationToBuildException(ex, getLocation()); | |||
throw (BuildException) t; | |||
} finally { | |||
log("Exiting " + antFile + ".", Project.MSG_VERBOSE); | |||
newProject.fireSubBuildFinished(t); | |||
} | |||
} | |||
} finally { | |||
// 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; | |||
Enumeration e = properties.elements(); | |||
while (e.hasMoreElements()) { | |||
@@ -211,7 +211,7 @@ public class Recorder extends Task { | |||
throw new BuildException("Problems creating a recorder entry", | |||
ioe); | |||
} | |||
proj.addBuildListener(entry); | |||
entry.setProject(proj); | |||
recorderEntries.put(name, entry); | |||
} else { | |||
entry = (RecorderEntry) o; | |||
@@ -21,6 +21,7 @@ import org.apache.tools.ant.BuildEvent; | |||
import org.apache.tools.ant.BuildLogger; | |||
import org.apache.tools.ant.DefaultLogger; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.SubBuildListener; | |||
import org.apache.tools.ant.util.StringUtils; | |||
/** | |||
@@ -30,7 +31,7 @@ import org.apache.tools.ant.util.StringUtils; | |||
* @version 0.5 | |||
* @since Ant 1.4 | |||
*/ | |||
public class RecorderEntry implements BuildLogger { | |||
public class RecorderEntry implements BuildLogger, SubBuildListener { | |||
////////////////////////////////////////////////////////////////////// | |||
// ATTRIBUTES | |||
@@ -47,6 +48,8 @@ public class RecorderEntry implements BuildLogger { | |||
private long targetStartTime = 0L; | |||
/** Strip task banners if true. */ | |||
private boolean emacsMode = false; | |||
/** project instance the recorder is associated with */ | |||
private Project project; | |||
////////////////////////////////////////////////////////////////////// | |||
// CONSTRUCTORS / INITIALIZERS | |||
@@ -99,7 +102,32 @@ public class RecorderEntry implements BuildLogger { | |||
+ StringUtils.LINE_SEP); | |||
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 | |||
*/ | |||
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.close(); | |||
if (project != null) { | |||
project.removeBuildListener(this); | |||
} | |||
project = null; | |||
} | |||
} | |||