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; | |||||
| } | } | ||||
| } | } | ||||