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