git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271542 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -54,12 +54,15 @@ | |||||
| package org.apache.ant.antcore.execution; | package org.apache.ant.antcore.execution; | ||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.Iterator; | import java.util.Iterator; | ||||
| import java.util.Map; | |||||
| import java.util.HashMap; | |||||
| import java.util.List; | import java.util.List; | ||||
| import org.apache.ant.common.model.ModelElement; | |||||
| import org.apache.ant.common.event.BuildListener; | |||||
| import org.apache.ant.common.event.BuildEvent; | |||||
| import org.apache.ant.common.antlib.Task; | import org.apache.ant.common.antlib.Task; | ||||
| import org.apache.ant.common.event.BuildEvent; | |||||
| import org.apache.ant.common.event.BuildListener; | |||||
| import org.apache.ant.common.model.ModelElement; | |||||
| import org.apache.ant.common.util.DemuxOutputReceiver; | |||||
| import org.apache.ant.common.event.MessageLevel; | |||||
| /** | /** | ||||
| * BuildEventSupport is used by classes which which to send build events to | * BuildEventSupport is used by classes which which to send build events to | ||||
| @@ -68,13 +71,16 @@ import org.apache.ant.common.antlib.Task; | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | ||||
| * @created 15 January 2002 | * @created 15 January 2002 | ||||
| */ | */ | ||||
| public class BuildEventSupport { | |||||
| public class BuildEventSupport implements DemuxOutputReceiver { | |||||
| /** | /** | ||||
| * The listeners attached to the object which contains this support | * The listeners attached to the object which contains this support | ||||
| * object | * object | ||||
| */ | */ | ||||
| private List listeners = new ArrayList(); | private List listeners = new ArrayList(); | ||||
| /** Records the latest task to be executed on a thread (Thread to Task). */ | |||||
| private Map threadTasks = new HashMap(); | |||||
| /** | /** | ||||
| * Gets the listeners of the BuildEventSupport | * Gets the listeners of the BuildEventSupport | ||||
| * | * | ||||
| @@ -166,6 +172,9 @@ public class BuildEventSupport { | |||||
| * @param task the task with which the event is associated | * @param task the task with which the event is associated | ||||
| */ | */ | ||||
| public void fireTaskStarted(Task task) { | public void fireTaskStarted(Task task) { | ||||
| synchronized (this) { | |||||
| threadTasks.put(Thread.currentThread(), task); | |||||
| } | |||||
| BuildEvent event = new BuildEvent(task, BuildEvent.TASK_STARTED); | BuildEvent event = new BuildEvent(task, BuildEvent.TASK_STARTED); | ||||
| for (Iterator i = listeners.iterator(); i.hasNext(); ) { | for (Iterator i = listeners.iterator(); i.hasNext(); ) { | ||||
| BuildListener listener = (BuildListener)i.next(); | BuildListener listener = (BuildListener)i.next(); | ||||
| @@ -181,6 +190,11 @@ public class BuildEventSupport { | |||||
| */ | */ | ||||
| public void fireTaskFinished(Task task, | public void fireTaskFinished(Task task, | ||||
| Throwable cause) { | Throwable cause) { | ||||
| System.out.flush(); | |||||
| System.err.flush(); | |||||
| synchronized (this) { | |||||
| threadTasks.remove(Thread.currentThread()); | |||||
| } | |||||
| BuildEvent event = new BuildEvent(task, BuildEvent.TASK_FINISHED, | BuildEvent event = new BuildEvent(task, BuildEvent.TASK_FINISHED, | ||||
| cause); | cause); | ||||
| for (Iterator i = listeners.iterator(); i.hasNext(); ) { | for (Iterator i = listeners.iterator(); i.hasNext(); ) { | ||||
| @@ -204,5 +218,28 @@ public class BuildEventSupport { | |||||
| listener.messageLogged(event); | listener.messageLogged(event); | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Demultiplexes output so that each task receives the appropriate | |||||
| * messages. If the current thread is not currently executing a task, | |||||
| * the message is logged directly. | |||||
| * | |||||
| * @param line Message to handle. Should not be <code>null</code>. | |||||
| * @param isError Whether the text represents an error (<code>true</code> | |||||
| * ) or information (<code>false</code>). | |||||
| */ | |||||
| public void threadOutput(String line, boolean isError) { | |||||
| Task task = (Task)threadTasks.get(Thread.currentThread()); | |||||
| if (task == null) { | |||||
| fireMessageLogged(this, line, | |||||
| isError ? MessageLevel.MSG_ERR : MessageLevel.MSG_INFO); | |||||
| } else { | |||||
| if (isError) { | |||||
| task.handleSystemErr(line); | |||||
| } else { | |||||
| task.handleSystemOut(line); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -422,7 +422,12 @@ public class ComponentManager implements ComponentService { | |||||
| throws ExecutionException { | throws ExecutionException { | ||||
| ImportInfo definition = getDefinition(componentName); | ImportInfo definition = getDefinition(componentName); | ||||
| if (definition == null) { | |||||
| throw new ExecutionException("There is no definition of the <" | |||||
| + componentName + "> component"); | |||||
| } | |||||
| String className = definition.getClassName(); | String className = definition.getClassName(); | ||||
| ComponentLibrary componentLibrary | ComponentLibrary componentLibrary | ||||
| = definition.getComponentLibrary(); | = definition.getComponentLibrary(); | ||||
| String localName = definition.getLocalName(); | String localName = definition.getLocalName(); | ||||
| @@ -64,6 +64,7 @@ import org.apache.ant.common.event.BuildListener; | |||||
| import org.apache.ant.common.model.Project; | import org.apache.ant.common.model.Project; | ||||
| import org.apache.ant.common.util.AntException; | import org.apache.ant.common.util.AntException; | ||||
| import org.apache.ant.common.util.ExecutionException; | import org.apache.ant.common.util.ExecutionException; | ||||
| import org.apache.ant.common.util.DemuxOutputReceiver; | |||||
| import org.apache.ant.init.InitConfig; | import org.apache.ant.init.InitConfig; | ||||
| /** | /** | ||||
| @@ -75,7 +76,7 @@ import org.apache.ant.init.InitConfig; | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | ||||
| * @created 12 January 2002 | * @created 12 January 2002 | ||||
| */ | */ | ||||
| public class ExecutionManager { | |||||
| public class ExecutionManager implements DemuxOutputReceiver { | |||||
| /** The AntLibraries built from Ant's Populated Task Libraries. */ | /** The AntLibraries built from Ant's Populated Task Libraries. */ | ||||
| private Map antLibraries = new HashMap(); | private Map antLibraries = new HashMap(); | ||||
| @@ -212,5 +213,17 @@ public class ExecutionManager { | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Handle the content from a single thread. This method will be called | |||||
| * by the thread producing the content. The content is broken up into | |||||
| * separate lines | |||||
| * | |||||
| * @param line the content produce by the current thread. | |||||
| * @param isErr true if this content is from the thread's error stream. | |||||
| */ | |||||
| public void threadOutput(String line, boolean isErr) { | |||||
| eventSupport.threadOutput(line, isErr); | |||||
| } | |||||
| } | } | ||||
| @@ -74,6 +74,7 @@ import org.apache.ant.common.service.FileService; | |||||
| import org.apache.ant.common.service.MagicProperties; | import org.apache.ant.common.service.MagicProperties; | ||||
| import org.apache.ant.common.util.AntException; | import org.apache.ant.common.util.AntException; | ||||
| import org.apache.ant.common.util.ConfigException; | import org.apache.ant.common.util.ConfigException; | ||||
| import org.apache.ant.common.util.DemuxOutputReceiver; | |||||
| import org.apache.ant.common.util.ExecutionException; | import org.apache.ant.common.util.ExecutionException; | ||||
| import org.apache.ant.common.util.FileUtils; | import org.apache.ant.common.util.FileUtils; | ||||
| import org.apache.ant.init.InitConfig; | import org.apache.ant.init.InitConfig; | ||||
| @@ -86,7 +87,7 @@ import org.apache.ant.init.InitConfig; | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | ||||
| * @created 14 January 2002 | * @created 14 January 2002 | ||||
| */ | */ | ||||
| public class Frame { | |||||
| public class Frame implements DemuxOutputReceiver { | |||||
| /** the base dir of the project */ | /** the base dir of the project */ | ||||
| private File baseDir; | private File baseDir; | ||||
| @@ -143,11 +144,9 @@ public class Frame { | |||||
| */ | */ | ||||
| private ComponentManager componentManager; | private ComponentManager componentManager; | ||||
| /** | |||||
| * The core's execution Service | |||||
| */ | |||||
| /** The core's execution Service */ | |||||
| private CoreExecService execService; | private CoreExecService execService; | ||||
| /** | /** | ||||
| * Create an Execution Frame for the given project | * Create an Execution Frame for the given project | ||||
| * | * | ||||
| @@ -165,6 +164,18 @@ public class Frame { | |||||
| this.initConfig = initConfig; | this.initConfig = initConfig; | ||||
| } | } | ||||
| /** | |||||
| * Replace ${} style constructions in the given value with the string | |||||
| * value of the corresponding data values in the frame | |||||
| * | |||||
| * @param value the string to be scanned for property references. | |||||
| * @return the string with all property references replaced | |||||
| * @exception ExecutionException if any of the properties do not exist | |||||
| */ | |||||
| public String replacePropertyRefs(String value) throws ExecutionException { | |||||
| return dataService.replacePropertyRefs(value); | |||||
| } | |||||
| /** | /** | ||||
| * Sets the Project of the Frame | * Sets the Project of the Frame | ||||
| * | * | ||||
| @@ -189,18 +200,6 @@ public class Frame { | |||||
| setMagicProperties(); | setMagicProperties(); | ||||
| } | } | ||||
| /** | |||||
| * Replace ${} style constructions in the given value with the string | |||||
| * value of the corresponding data values in the frame | |||||
| * | |||||
| * @param value the string to be scanned for property references. | |||||
| * @return the string with all property references replaced | |||||
| * @exception ExecutionException if any of the properties do not exist | |||||
| */ | |||||
| public String replacePropertyRefs(String value) throws ExecutionException { | |||||
| return dataService.replacePropertyRefs(value); | |||||
| } | |||||
| /** | /** | ||||
| * Set a value in this frame or any of its imported frames. | * Set a value in this frame or any of its imported frames. | ||||
| * | * | ||||
| @@ -603,7 +602,6 @@ public class Frame { | |||||
| } catch (ConfigException e) { | } catch (ConfigException e) { | ||||
| throw new ExecutionException(e); | throw new ExecutionException(e); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| @@ -623,8 +621,8 @@ public class Frame { | |||||
| if (component instanceof Task) { | if (component instanceof Task) { | ||||
| execService.executeTask((Task)component); | execService.executeTask((Task)component); | ||||
| } else { | } else { | ||||
| String typeId | |||||
| = model.getAspectValue(Constants.ANT_ASPECT, "id"); | |||||
| String typeId | |||||
| = model.getAspectValue(Constants.ANT_ASPECT, "id"); | |||||
| if (typeId != null) { | if (typeId != null) { | ||||
| setDataValue(typeId, component, true); | setDataValue(typeId, component, true); | ||||
| } | } | ||||
| @@ -709,6 +707,18 @@ public class Frame { | |||||
| executeTasks(taskIterator); | executeTasks(taskIterator); | ||||
| } | } | ||||
| /** | |||||
| * Handle the content from a single thread. This method will be called | |||||
| * by the thread producing the content. The content is broken up into | |||||
| * separate lines | |||||
| * | |||||
| * @param line the content produce by the current thread. | |||||
| * @param isErr true if this content is from the thread's error stream. | |||||
| */ | |||||
| public void threadOutput(String line, boolean isErr) { | |||||
| eventSupport.threadOutput(line, isErr); | |||||
| } | |||||
| /** | /** | ||||
| * Determine the base directory for each frame in the frame hierarchy | * Determine the base directory for each frame in the frame hierarchy | ||||
| * | * | ||||
| @@ -755,7 +765,7 @@ public class Frame { | |||||
| dataService = new CoreDataService(this, | dataService = new CoreDataService(this, | ||||
| config.isUnsetPropertiesAllowed()); | config.isUnsetPropertiesAllowed()); | ||||
| execService = new CoreExecService(this); | execService = new CoreExecService(this); | ||||
| services.put(FileService.class, fileService); | services.put(FileService.class, fileService); | ||||
| services.put(ComponentService.class, componentManager); | services.put(ComponentService.class, componentManager); | ||||
| services.put(DataService.class, dataService); | services.put(DataService.class, dataService); | ||||
| @@ -76,6 +76,15 @@ public class ProjectHandler extends ElementHandler { | |||||
| /** The default attribute name */ | /** The default attribute name */ | ||||
| public static final String DEFAULT_ATTR = "default"; | public static final String DEFAULT_ATTR = "default"; | ||||
| /** The name of the element used to define references */ | |||||
| public static final String REF_ELEMENT = "ant:ref"; | |||||
| /** The name of the element used to define references */ | |||||
| public static final String INCLUDE_ELEMENT = "ant:include"; | |||||
| /** The name of the element used to define references */ | |||||
| public static final String TARGET_ELEMENT = "target"; | |||||
| /** The project being parsed. */ | /** The project being parsed. */ | ||||
| private Project project; | private Project project; | ||||
| @@ -148,8 +157,8 @@ public class ProjectHandler extends ElementHandler { | |||||
| public void startElement(String uri, String localName, String qualifiedName, | public void startElement(String uri, String localName, String qualifiedName, | ||||
| Attributes attributes) | Attributes attributes) | ||||
| throws SAXParseException { | throws SAXParseException { | ||||
| if (qualifiedName.equals("ref")) { | |||||
| if (qualifiedName.equals(REF_ELEMENT)) { | |||||
| RefHandler refHandler = new RefHandler(); | RefHandler refHandler = new RefHandler(); | ||||
| refHandler.start(getParseContext(), getXMLReader(), this, | refHandler.start(getParseContext(), getXMLReader(), this, | ||||
| getLocator(), attributes, getElementSource(), | getLocator(), attributes, getElementSource(), | ||||
| @@ -160,12 +169,12 @@ public class ProjectHandler extends ElementHandler { | |||||
| } catch (ModelException e) { | } catch (ModelException e) { | ||||
| throw new SAXParseException(e.getMessage(), getLocator(), e); | throw new SAXParseException(e.getMessage(), getLocator(), e); | ||||
| } | } | ||||
| } else if (qualifiedName.equals("include")) { | |||||
| } else if (qualifiedName.equals(INCLUDE_ELEMENT)) { | |||||
| IncludeHandler includeHandler = new IncludeHandler(project); | IncludeHandler includeHandler = new IncludeHandler(project); | ||||
| includeHandler.start(getParseContext(), getXMLReader(), | includeHandler.start(getParseContext(), getXMLReader(), | ||||
| this, getLocator(), attributes, getElementSource(), | this, getLocator(), attributes, getElementSource(), | ||||
| qualifiedName); | qualifiedName); | ||||
| } else if (qualifiedName.equals("target")) { | |||||
| } else if (qualifiedName.equals(TARGET_ELEMENT)) { | |||||
| TargetHandler targetHandler = new TargetHandler(); | TargetHandler targetHandler = new TargetHandler(); | ||||
| targetHandler.start(getParseContext(), getXMLReader(), | targetHandler.start(getParseContext(), getXMLReader(), | ||||
| this, getLocator(), attributes, | this, getLocator(), attributes, | ||||
| @@ -175,13 +184,17 @@ public class ProjectHandler extends ElementHandler { | |||||
| } catch (ModelException e) { | } catch (ModelException e) { | ||||
| throw new SAXParseException(e.getMessage(), getLocator(), e); | throw new SAXParseException(e.getMessage(), getLocator(), e); | ||||
| } | } | ||||
| } else { | |||||
| } else if (localName != null) { | |||||
| // everything else is a task | // everything else is a task | ||||
| BuildElementHandler buildElementHandler = new BuildElementHandler(); | BuildElementHandler buildElementHandler = new BuildElementHandler(); | ||||
| buildElementHandler.start(getParseContext(), getXMLReader(), | buildElementHandler.start(getParseContext(), getXMLReader(), | ||||
| this, getLocator(), attributes, getElementSource(), | this, getLocator(), attributes, getElementSource(), | ||||
| qualifiedName); | qualifiedName); | ||||
| project.addTask(buildElementHandler.getBuildElement()); | project.addTask(buildElementHandler.getBuildElement()); | ||||
| } else { | |||||
| // ignore namespaced elements | |||||
| throw new SAXParseException("Only the \"ant\" namespace is " | |||||
| + "currently recognized (" + qualifiedName + ")", getLocator()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -164,6 +164,31 @@ public abstract class Task extends ProjectComponent | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Handle Output produced by the task. When a task prints to System.out | |||||
| * the container may catch this and redirect the content back to the | |||||
| * task by invoking this method. This method must NOT call System.out, | |||||
| * directly or indirectly. | |||||
| * | |||||
| * @param line The line of content produce by the task | |||||
| */ | |||||
| public void handleSystemOut(String line) { | |||||
| handleOutput(line); | |||||
| } | |||||
| /** | |||||
| * Handle error information produced by the task. When a task prints to | |||||
| * System.err the container may catch this and redirect the content back | |||||
| * to the task by invoking this method. This method must NOT call | |||||
| * System.err, directly or indirectly. | |||||
| * | |||||
| * @param line The line of error info produce by the task | |||||
| */ | |||||
| public void handleSystemErr(String line) { | |||||
| // default behaviout is to log at WARN level | |||||
| handleErrorOutput(line); | |||||
| } | |||||
| /** | /** | ||||
| * Handle output captured for this task | * Handle output captured for this task | ||||
| * | * | ||||
| @@ -57,6 +57,7 @@ import java.io.FileNotFoundException; | |||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||
| import java.io.OutputStream; | |||||
| import java.net.MalformedURLException; | import java.net.MalformedURLException; | ||||
| import java.net.URL; | import java.net.URL; | ||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| @@ -75,6 +76,7 @@ import org.apache.ant.common.event.BuildListener; | |||||
| import org.apache.ant.common.event.MessageLevel; | import org.apache.ant.common.event.MessageLevel; | ||||
| import org.apache.ant.common.model.Project; | import org.apache.ant.common.model.Project; | ||||
| import org.apache.ant.common.util.ConfigException; | import org.apache.ant.common.util.ConfigException; | ||||
| import org.apache.ant.common.util.DemuxOutputStream; | |||||
| import org.apache.ant.init.InitConfig; | import org.apache.ant.init.InitConfig; | ||||
| import org.apache.ant.init.InitUtils; | import org.apache.ant.init.InitUtils; | ||||
| @@ -298,6 +300,12 @@ public class Commandline { | |||||
| // create the execution manager to execute the build | // create the execution manager to execute the build | ||||
| executionManager = new ExecutionManager(initConfig, config); | executionManager = new ExecutionManager(initConfig, config); | ||||
| OutputStream demuxOut | |||||
| = new DemuxOutputStream(executionManager, false); | |||||
| OutputStream demuxErr | |||||
| = new DemuxOutputStream(executionManager, true); | |||||
| System.setOut(new PrintStream(demuxOut)); | |||||
| System.setErr(new PrintStream(demuxErr)); | |||||
| addBuildListeners(executionManager); | addBuildListeners(executionManager); | ||||
| } catch (Throwable e) { | } catch (Throwable e) { | ||||
| if (logger != null) { | if (logger != null) { | ||||
| @@ -52,6 +52,7 @@ | |||||
| * <http://www.apache.org/>. | * <http://www.apache.org/>. | ||||
| */ | */ | ||||
| package org.apache.ant.common.antlib; | package org.apache.ant.common.antlib; | ||||
| import org.apache.ant.common.event.MessageLevel; | |||||
| /** | /** | ||||
| * Abstract implementation of the Task interface | * Abstract implementation of the Task interface | ||||
| @@ -81,5 +82,30 @@ public abstract class AbstractTask extends AbstractComponent implements Task { | |||||
| return taskName; | return taskName; | ||||
| } | } | ||||
| /** | |||||
| * Handle Output produced by the task. When a task prints to System.out | |||||
| * the container may catch this and redirect the content back to the | |||||
| * task by invoking this method. This method must NOT call System.out, | |||||
| * directly or indirectly. | |||||
| * | |||||
| * @param line The line of content produce by the task | |||||
| */ | |||||
| public void handleSystemOut(String line) { | |||||
| // default behaviout is to log at INFO level | |||||
| log(line, MessageLevel.MSG_INFO); | |||||
| } | |||||
| /** | |||||
| * Handle error information produced by the task. When a task prints to | |||||
| * System.err the container may catch this and redirect the content back | |||||
| * to the task by invoking this method. This method must NOT call | |||||
| * System.err, directly or indirectly. | |||||
| * | |||||
| * @param line The line of error info produce by the task | |||||
| */ | |||||
| public void handleSystemErr(String line) { | |||||
| // default behaviout is to log at WARN level | |||||
| log(line, MessageLevel.MSG_WARN); | |||||
| } | |||||
| } | } | ||||
| @@ -81,5 +81,25 @@ public interface Task extends ExecutionComponent { | |||||
| * @return the taskName value | * @return the taskName value | ||||
| */ | */ | ||||
| String getTaskName(); | String getTaskName(); | ||||
| /** | |||||
| * Handle Output produced by the task. When a task prints to System.out | |||||
| * the container may catch this and redirect the content back to the | |||||
| * task by invoking this method. This method must NOT call System.out, | |||||
| * directly or indirectly. | |||||
| * | |||||
| * @param line The line of content produce by the task | |||||
| */ | |||||
| void handleSystemOut(String line); | |||||
| /** | |||||
| * Handle error information produced by the task. When a task prints to | |||||
| * System.err the container may catch this and redirect the content back | |||||
| * to the task by invoking this method. This method must NOT call | |||||
| * System.err, directly or indirectly. | |||||
| * | |||||
| * @param line The line of error info produce by the task | |||||
| */ | |||||
| void handleSystemErr(String line); | |||||
| } | } | ||||
| @@ -253,9 +253,16 @@ public class Project extends ModelElement { | |||||
| * | * | ||||
| * @param fullTargetName The name of the target relative to this project | * @param fullTargetName The name of the target relative to this project | ||||
| * @return the Target object with the given name | * @return the Target object with the given name | ||||
| * @exception ModelException if the given target does not exist in this | |||||
| * project | |||||
| */ | */ | ||||
| public Target getRefTarget(String fullTargetName) { | |||||
| public Target getRefTarget(String fullTargetName) throws ModelException { | |||||
| Project containingProject = getRefProject(fullTargetName); | Project containingProject = getRefProject(fullTargetName); | ||||
| if (containingProject == null) { | |||||
| throw new ModelException("The target name \"" + fullTargetName | |||||
| + "\" does not exist in this project"); | |||||
| } | |||||
| if (containingProject == this) { | if (containingProject == this) { | ||||
| return getTarget(fullTargetName); | return getTarget(fullTargetName); | ||||
| } | } | ||||
| @@ -504,19 +511,23 @@ public class Project extends ModelElement { | |||||
| if (flattenedList.contains(fullTargetName)) { | if (flattenedList.contains(fullTargetName)) { | ||||
| return; | return; | ||||
| } | } | ||||
| String fullProjectName = getFullProjectName(fullTargetName); | |||||
| Target target = getRefTarget(fullTargetName); | |||||
| if (target == null) { | |||||
| throw new ConfigException("Target " + fullTargetName | |||||
| + " does not exist"); | |||||
| } | |||||
| for (Iterator i = target.getDependencies(); i.hasNext(); ) { | |||||
| String localDependencyName = (String)i.next(); | |||||
| String fullDependencyName | |||||
| = fullProjectName == null ? localDependencyName | |||||
| : fullProjectName + REF_DELIMITER + localDependencyName; | |||||
| flattenDependency(flattenedList, fullDependencyName); | |||||
| flattenedList.add(fullDependencyName); | |||||
| try { | |||||
| String fullProjectName = getFullProjectName(fullTargetName); | |||||
| Target target = getRefTarget(fullTargetName); | |||||
| if (target == null) { | |||||
| throw new ConfigException("Target " + fullTargetName | |||||
| + " does not exist"); | |||||
| } | |||||
| for (Iterator i = target.getDependencies(); i.hasNext(); ) { | |||||
| String localDependencyName = (String)i.next(); | |||||
| String fullDependencyName | |||||
| = fullProjectName == null ? localDependencyName | |||||
| : fullProjectName + REF_DELIMITER + localDependencyName; | |||||
| flattenDependency(flattenedList, fullDependencyName); | |||||
| flattenedList.add(fullDependencyName); | |||||
| } | |||||
| } catch (ModelException e) { | |||||
| throw new ConfigException(e); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,74 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2001-2002 The Apache Software Foundation. All rights | |||||
| * reserved. | |||||
| * | |||||
| * Redistribution and use in source and binary forms, with or without | |||||
| * modification, are permitted provided that the following conditions | |||||
| * are met: | |||||
| * | |||||
| * 1. Redistributions of source code must retain the above copyright | |||||
| * notice, this list of conditions and the following disclaimer. | |||||
| * | |||||
| * 2. Redistributions in binary form must reproduce the above copyright | |||||
| * notice, this list of conditions and the following disclaimer in | |||||
| * the documentation and/or other materials provided with the | |||||
| * distribution. | |||||
| * | |||||
| * 3. The end-user documentation included with the redistribution, if | |||||
| * any, must include the following acknowlegement: | |||||
| * "This product includes software developed by the | |||||
| * Apache Software Foundation (http://www.apache.org/)." | |||||
| * Alternately, this acknowlegement may appear in the software itself, | |||||
| * if and wherever such third-party acknowlegements normally appear. | |||||
| * | |||||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||||
| * Foundation" must not be used to endorse or promote products derived | |||||
| * from this software without prior written permission. For written | |||||
| * permission, please contact apache@apache.org. | |||||
| * | |||||
| * 5. Products derived from this software may not be called "Apache" | |||||
| * nor may "Apache" appear in their names without prior written | |||||
| * permission of the Apache Group. | |||||
| * | |||||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
| * SUCH DAMAGE. | |||||
| * ==================================================================== | |||||
| * | |||||
| * This software consists of voluntary contributions made by many | |||||
| * individuals on behalf of the Apache Software Foundation. For more | |||||
| * information on the Apache Software Foundation, please see | |||||
| * <http://www.apache.org/>. | |||||
| */ | |||||
| package org.apache.ant.common.util; | |||||
| /** | |||||
| * A Demux output receiver receives buffered content which has been | |||||
| * demultiplexed from the output potentially generated by multiple threads | |||||
| * | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
| * @created 22 February 2002 | |||||
| */ | |||||
| public interface DemuxOutputReceiver { | |||||
| /** | |||||
| * Handle the content from a single thread. This method will be called | |||||
| * by the thread producing the content. The content is broken up into | |||||
| * separate lines | |||||
| * | |||||
| * @param line the content produce by the current thread. | |||||
| * @param isErr true if this content is from the thread's error stream. | |||||
| */ | |||||
| void threadOutput(String line, boolean isErr); | |||||
| } | |||||
| @@ -0,0 +1,198 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2001-2002 The Apache Software Foundation. All rights | |||||
| * reserved. | |||||
| * | |||||
| * Redistribution and use in source and binary forms, with or without | |||||
| * modification, are permitted provided that the following conditions | |||||
| * are met: | |||||
| * | |||||
| * 1. Redistributions of source code must retain the above copyright | |||||
| * notice, this list of conditions and the following disclaimer. | |||||
| * | |||||
| * 2. Redistributions in binary form must reproduce the above copyright | |||||
| * notice, this list of conditions and the following disclaimer in | |||||
| * the documentation and/or other materials provided with the | |||||
| * distribution. | |||||
| * | |||||
| * 3. The end-user documentation included with the redistribution, if | |||||
| * any, must include the following acknowlegement: | |||||
| * "This product includes software developed by the | |||||
| * Apache Software Foundation (http://www.apache.org/)." | |||||
| * Alternately, this acknowlegement may appear in the software itself, | |||||
| * if and wherever such third-party acknowlegements normally appear. | |||||
| * | |||||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||||
| * Foundation" must not be used to endorse or promote products derived | |||||
| * from this software without prior written permission. For written | |||||
| * permission, please contact apache@apache.org. | |||||
| * | |||||
| * 5. Products derived from this software may not be called "Apache" | |||||
| * nor may "Apache" appear in their names without prior written | |||||
| * permission of the Apache Group. | |||||
| * | |||||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
| * SUCH DAMAGE. | |||||
| * ==================================================================== | |||||
| * | |||||
| * This software consists of voluntary contributions made by many | |||||
| * individuals on behalf of the Apache Software Foundation. For more | |||||
| * information on the Apache Software Foundation, please see | |||||
| * <http://www.apache.org/>. | |||||
| */ | |||||
| package org.apache.ant.common.util; | |||||
| import java.io.ByteArrayOutputStream; | |||||
| import java.io.IOException; | |||||
| import java.io.OutputStream; | |||||
| import java.util.Hashtable; | |||||
| /** | |||||
| * Buffers content written per thread and forwards the buffers onto the | |||||
| * given receiver | |||||
| * | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
| * @created 22 February 2002 | |||||
| */ | |||||
| public class DemuxOutputStream extends OutputStream { | |||||
| /** | |||||
| * A data class to store information about a buffer. Such informatio is | |||||
| * stored on a per-thread basis. | |||||
| * | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
| * @created 22 February 2002 | |||||
| */ | |||||
| private static class BufferInfo { | |||||
| /** The per-thread output stream */ | |||||
| private ByteArrayOutputStream buffer; | |||||
| /** | |||||
| * Whether the next line-terminator should be skipped in terms of | |||||
| * processing the buffer or not. Used to avoid \r\n invoking | |||||
| * processBuffer twice. | |||||
| */ | |||||
| private boolean skip = false; | |||||
| } | |||||
| /** Maximum buffer size */ | |||||
| private static final int MAX_SIZE = 1024; | |||||
| /** Mapping from thread to buffer (Thread to BufferInfo) */ | |||||
| private Hashtable buffers = new Hashtable(); | |||||
| /** The object which receives the output */ | |||||
| private DemuxOutputReceiver receiver; | |||||
| /** Whether or not this stream represents an error stream */ | |||||
| private boolean isErrorStream; | |||||
| /** | |||||
| * Creates a new instance of this class. | |||||
| * | |||||
| * @param isErrorStream true if this is the error string, otherwise a | |||||
| * normal output stream. This is passed to the project so it knows | |||||
| * which stream it is receiving. | |||||
| * @param receiver The receiver to which demux'd content is sent. | |||||
| */ | |||||
| public DemuxOutputStream(DemuxOutputReceiver receiver, | |||||
| boolean isErrorStream) { | |||||
| this.receiver = receiver; | |||||
| this.isErrorStream = isErrorStream; | |||||
| } | |||||
| /** | |||||
| * Writes the data to the buffer and flushes the buffer if a line | |||||
| * separator is detected or if the buffer has reached its maximum size. | |||||
| * | |||||
| * @param cc data to log (byte). | |||||
| * @exception IOException if the data cannot be written to the stream | |||||
| */ | |||||
| public void write(int cc) throws IOException { | |||||
| final byte c = (byte)cc; | |||||
| BufferInfo bufferInfo = getBufferInfo(); | |||||
| if ((c == '\n') || (c == '\r')) { | |||||
| if (!bufferInfo.skip) { | |||||
| processBuffer(bufferInfo.buffer); | |||||
| } | |||||
| } else { | |||||
| bufferInfo.buffer.write(cc); | |||||
| if (bufferInfo.buffer.size() > MAX_SIZE) { | |||||
| processBuffer(bufferInfo.buffer); | |||||
| } | |||||
| } | |||||
| bufferInfo.skip = (c == '\r'); | |||||
| } | |||||
| /** | |||||
| * Equivalent to calling {@link #flush flush} on the stream. | |||||
| * | |||||
| * @exception IOException if there is a problem closing the stream. | |||||
| */ | |||||
| public void close() throws IOException { | |||||
| flush(); | |||||
| } | |||||
| /** | |||||
| * Writes all remaining data in the buffer associated with the current | |||||
| * thread to the project. | |||||
| * | |||||
| * @exception IOException if there is a problem flushing the stream. | |||||
| */ | |||||
| public void flush() throws IOException { | |||||
| BufferInfo bufferInfo = getBufferInfo(); | |||||
| if (bufferInfo.buffer.size() > 0) { | |||||
| processBuffer(bufferInfo.buffer); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Converts the buffer to a string and sends it to {@link | |||||
| * Project#demuxOutput(String,boolean) Project.demuxOutput}. | |||||
| * | |||||
| * @param buffer the ByteArrayOutputStream used to collect the output | |||||
| * until a line separator is seen. | |||||
| */ | |||||
| protected void processBuffer(ByteArrayOutputStream buffer) { | |||||
| String output = buffer.toString(); | |||||
| receiver.threadOutput(output, isErrorStream); | |||||
| resetBufferInfo(); | |||||
| } | |||||
| /** | |||||
| * Returns the buffer associated with the current thread. | |||||
| * | |||||
| * @return a ByteArrayOutputStream for the current thread to write data | |||||
| * to | |||||
| */ | |||||
| private BufferInfo getBufferInfo() { | |||||
| Thread current = Thread.currentThread(); | |||||
| BufferInfo bufferInfo = (BufferInfo)buffers.get(current); | |||||
| if (bufferInfo == null) { | |||||
| bufferInfo = new BufferInfo(); | |||||
| bufferInfo.buffer = new ByteArrayOutputStream(); | |||||
| bufferInfo.skip = false; | |||||
| buffers.put(current, bufferInfo); | |||||
| } | |||||
| return bufferInfo; | |||||
| } | |||||
| /** Resets the buffer for the current thread. */ | |||||
| private void resetBufferInfo() { | |||||
| Thread current = Thread.currentThread(); | |||||
| buffers.remove(current); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,71 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||||
| * reserved. | |||||
| * | |||||
| * Redistribution and use in source and binary forms, with or without | |||||
| * modification, are permitted provided that the following conditions | |||||
| * are met: | |||||
| * | |||||
| * 1. Redistributions of source code must retain the above copyright | |||||
| * notice, this list of conditions and the following disclaimer. | |||||
| * | |||||
| * 2. Redistributions in binary form must reproduce the above copyright | |||||
| * notice, this list of conditions and the following disclaimer in | |||||
| * the documentation and/or other materials provided with the | |||||
| * distribution. | |||||
| * | |||||
| * 3. The end-user documentation included with the redistribution, if | |||||
| * any, must include the following acknowlegement: | |||||
| * "This product includes software developed by the | |||||
| * Apache Software Foundation (http://www.apache.org/)." | |||||
| * Alternately, this acknowlegement may appear in the software itself, | |||||
| * if and wherever such third-party acknowlegements normally appear. | |||||
| * | |||||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||||
| * Foundation" must not be used to endorse or promote products derived | |||||
| * from this software without prior written permission. For written | |||||
| * permission, please contact apache@apache.org. | |||||
| * | |||||
| * 5. Products derived from this software may not be called "Apache" | |||||
| * nor may "Apache" appear in their names without prior written | |||||
| * permission of the Apache Group. | |||||
| * | |||||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
| * SUCH DAMAGE. | |||||
| * ==================================================================== | |||||
| * | |||||
| * This software consists of voluntary contributions made by many | |||||
| * individuals on behalf of the Apache Software Foundation. For more | |||||
| * information on the Apache Software Foundation, please see | |||||
| * <http://www.apache.org/>. | |||||
| */ | |||||
| package org.apache.tools.ant; | |||||
| /** | |||||
| * Old Ant1 entry point | |||||
| * | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
| */ | |||||
| public class Main { | |||||
| /** | |||||
| * Entry point for starting command line Ant | |||||
| * | |||||
| * @param args commandline arguments | |||||
| */ | |||||
| public static void main(String[] args) { | |||||
| org.apache.ant.start.Main.main(args); | |||||
| } | |||||
| } | |||||