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