Non-forked Java tasks can now have their input redirected. Note that it would be possible to add a noninteractive flag to Ant preventing any input from System.in in any java classes druing a build. Would prevent locking up waiting for input git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274021 13f79535-47bb-0310-9956-ffa450edef68master
@@ -0,0 +1,100 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2003 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; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
/** | |||
* | |||
* Passes input requests tot he project objetc for demuxing into | |||
* individual tasks and threads. | |||
* | |||
* @since Ant 1.6 | |||
* @author Conor MacNeill | |||
*/ | |||
public class DemuxInputStream extends InputStream { | |||
/** | |||
* The project to from which to get input. | |||
*/ | |||
private Project project; | |||
/** | |||
* Create a DemuxInputStream for the given project | |||
* | |||
* @param project the project instance | |||
*/ | |||
public DemuxInputStream(Project project) { | |||
this.project = project; | |||
} | |||
/** | |||
* @see InputStream.read() | |||
*/ | |||
public int read() throws IOException { | |||
byte[] buffer = new byte[1]; | |||
project.demuxInput(buffer, 0, 1); | |||
return buffer[0]; | |||
} | |||
/** | |||
* @see InputStream.read(byte[], int, int) | |||
*/ | |||
public int read(byte[] buffer, int offset, int length) throws IOException { | |||
return project.demuxInput(buffer, offset, length); | |||
} | |||
} |
@@ -572,6 +572,8 @@ public class Main { | |||
//System.setSecurityManager(new NoExitSecurityManager()); | |||
} | |||
try { | |||
project.setDefaultInputStream(System.in); | |||
System.setIn(new DemuxInputStream(project)); | |||
System.setOut(new PrintStream(new DemuxOutputStream(project, false))); | |||
System.setErr(new PrintStream(new DemuxOutputStream(project, true))); | |||
@@ -662,7 +664,7 @@ public class Main { | |||
* @exception BuildException if a specified InputHandler | |||
* implementation could not be loaded. | |||
*/ | |||
private void addInputHandler(Project project) { | |||
private void addInputHandler(Project project) throws BuildException { | |||
InputHandler handler = null; | |||
if (inputHandlerClassname == null) { | |||
handler = new DefaultInputHandler(); | |||
@@ -675,8 +677,7 @@ public class Main { | |||
+ inputHandlerClassname | |||
+ " does not implement the InputHandler interface"; | |||
throw new BuildException(msg); | |||
} | |||
catch (Exception e) { | |||
} catch (Exception e) { | |||
String msg = "Unable to instantiate specified input handler " | |||
+ "class " + inputHandlerClassname + " : " | |||
+ e.getClass().getName(); | |||
@@ -866,8 +867,8 @@ public class Main { | |||
maxLength); | |||
//if there were no main targets, we list all subtargets | |||
//as it means nothing has a description | |||
if(topNames.size()==0) { | |||
printSubTargets=true; | |||
if (topNames.size() == 0) { | |||
printSubTargets = true; | |||
} | |||
if (printSubTargets) { | |||
printTargets(project, subNames, null, "Subtargets:", 0); | |||
@@ -918,8 +919,8 @@ public class Main { | |||
* position so they line up (so long as the names really | |||
* <i>are</i> shorter than this). | |||
*/ | |||
private static void printTargets(Project project,Vector names, | |||
Vector descriptions,String heading, | |||
private static void printTargets(Project project, Vector names, | |||
Vector descriptions, String heading, | |||
int maxlen) { | |||
// now, start printing the targets and their descriptions | |||
String lSep = System.getProperty("line.separator"); | |||
@@ -90,7 +90,6 @@ import org.apache.tools.ant.util.LazyHashtable; | |||
*/ | |||
public class Project { | |||
/** Message priority of "error". */ | |||
public static final int MSG_ERR = 0; | |||
/** Message priority of "warning". */ | |||
@@ -113,6 +112,13 @@ public class Project { | |||
*/ | |||
private static final String VISITED = "VISITED"; | |||
/** | |||
* The class name of the Ant class loader to use for | |||
* JDK 1.2 and above | |||
*/ | |||
private static final String ANTCLASSLOADER_JDK12 | |||
= "org.apache.tools.ant.loader.AntClassLoader2"; | |||
/** | |||
* Version constant for Java 1.0 | |||
* | |||
@@ -204,15 +210,37 @@ public class Project { | |||
*/ | |||
private InputHandler inputHandler = null; | |||
/** | |||
* The default input stream used to read any input | |||
*/ | |||
private InputStream defaultInputStream = null; | |||
/** | |||
* Sets the input handler | |||
* | |||
* @param handler the InputHandler instance to use for gathering input. | |||
*/ | |||
public void setInputHandler(InputHandler handler) { | |||
inputHandler = handler; | |||
} | |||
/** | |||
* Set the default System input stream. Normally this stream is set to | |||
* System.in. This inputStream is used when no task inptu redirection is | |||
* being performed. | |||
* | |||
* @param defaultInputStream the default input stream to use when input | |||
* is reuested. | |||
*/ | |||
public void setDefaultInputStream(InputStream defaultInputStream) { | |||
this.defaultInputStream = defaultInputStream; | |||
} | |||
/** | |||
* Retrieves the current input handler. | |||
* | |||
* @return the InputHandler instance currently in place for the project | |||
* instance. | |||
*/ | |||
public InputHandler getInputHandler() { | |||
return inputHandler; | |||
@@ -250,7 +278,7 @@ public class Project { | |||
} | |||
props.load(in); | |||
in.close(); | |||
((AntTaskTable)taskClassDefinitions).addDefinitions( props ); | |||
((AntTaskTable) taskClassDefinitions).addDefinitions(props); | |||
} catch (IOException ioe) { | |||
@@ -268,7 +296,7 @@ public class Project { | |||
props.load(in); | |||
in.close(); | |||
((AntTaskTable)dataClassDefinitions).addDefinitions(props); | |||
((AntTaskTable) dataClassDefinitions).addDefinitions(props); | |||
} catch (IOException ioe) { | |||
@@ -278,13 +306,18 @@ public class Project { | |||
setSystemProperties(); | |||
} | |||
/** | |||
* Factory method to create a class loader for loading classes | |||
* | |||
* @return an appropriate classloader | |||
*/ | |||
private AntClassLoader createClassLoader() { | |||
AntClassLoader loader = null; | |||
if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) { | |||
try { | |||
// 1.2+ - create advanced helper dynamically | |||
Class loaderClass | |||
= Class.forName("org.apache.tools.ant.loader.AntClassLoader2"); | |||
= Class.forName(ANTCLASSLOADER_JDK12); | |||
loader = (AntClassLoader) loaderClass.newInstance(); | |||
} catch (Exception e) { | |||
log("Unable to create Class Loader: " | |||
@@ -300,6 +333,14 @@ public class Project { | |||
return loader; | |||
} | |||
/** | |||
* Factory method to create a class loader for loading classes from | |||
* a given path | |||
* | |||
* @param path the path from whcih clases are to be loaded. | |||
* | |||
* @return an appropriate classloader | |||
*/ | |||
public AntClassLoader createClassLoader(Path path) { | |||
AntClassLoader loader = createClassLoader(); | |||
loader.setClassPath(path); | |||
@@ -434,7 +475,8 @@ public class Project { | |||
* @since 1.5 | |||
*/ | |||
public synchronized void setNewProperty(String name, String value) { | |||
PropertyHelper.getPropertyHelper(this).setNewProperty( null, name, value); | |||
PropertyHelper.getPropertyHelper(this).setNewProperty(null, name, | |||
value); | |||
} | |||
/** | |||
@@ -447,7 +489,8 @@ public class Project { | |||
* @see #setProperty(String,String) | |||
*/ | |||
public synchronized void setUserProperty(String name, String value) { | |||
PropertyHelper.getPropertyHelper(this).setUserProperty( null, name, value); | |||
PropertyHelper.getPropertyHelper(this).setUserProperty(null, name, | |||
value); | |||
} | |||
/** | |||
@@ -463,7 +506,7 @@ public class Project { | |||
* @see #setProperty(String,String) | |||
*/ | |||
public synchronized void setInheritedProperty(String name, String value) { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
ph.setInheritedProperty(null, name, value); | |||
} | |||
@@ -476,8 +519,8 @@ public class Project { | |||
* @param value The property value. Must not be <code>null</code>. | |||
*/ | |||
private void setPropertyInternal(String name, String value) { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
ph.setProperty(null, name, value, false ); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
ph.setProperty(null, name, value, false); | |||
} | |||
/** | |||
@@ -490,8 +533,8 @@ public class Project { | |||
* or if a <code>null</code> name is provided. | |||
*/ | |||
public String getProperty(String name) { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
return (String)ph.getProperty(null, name); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
return (String) ph.getProperty(null, name); | |||
} | |||
/** | |||
@@ -509,9 +552,8 @@ public class Project { | |||
* property name, e.g. <code>${xxx</code> | |||
*/ | |||
public String replaceProperties(String value) | |||
throws BuildException | |||
{ | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
throws BuildException { | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
return ph.replaceProperties(null, value, null); | |||
} | |||
@@ -525,8 +567,8 @@ public class Project { | |||
* or if a <code>null</code> name is provided. | |||
*/ | |||
public String getUserProperty(String name) { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
return (String)ph.getUserProperty( null, name ); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
return (String) ph.getUserProperty(null, name); | |||
} | |||
/** | |||
@@ -535,7 +577,7 @@ public class Project { | |||
* (including user properties). | |||
*/ | |||
public Hashtable getProperties() { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
return ph.getProperties(); | |||
} | |||
@@ -544,7 +586,7 @@ public class Project { | |||
* @return a hashtable containing just the user properties | |||
*/ | |||
public Hashtable getUserProperties() { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
return ph.getUserProperties(); | |||
} | |||
@@ -561,7 +603,7 @@ public class Project { | |||
* @since Ant 1.5 | |||
*/ | |||
public void copyUserProperties(Project other) { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
ph.copyUserProperties(other); | |||
} | |||
@@ -578,7 +620,7 @@ public class Project { | |||
* @since Ant 1.5 | |||
*/ | |||
public void copyInheritedProperties(Project other) { | |||
PropertyHelper ph=PropertyHelper.getPropertyHelper(this); | |||
PropertyHelper ph = PropertyHelper.getPropertyHelper(this); | |||
ph.copyInheritedProperties(other); | |||
} | |||
@@ -654,8 +696,8 @@ public class Project { | |||
* been set. | |||
*/ | |||
public String getDescription() { | |||
if( description== null ) { | |||
description=Description.getDescription(this); | |||
if (description == null) { | |||
description = Description.getDescription(this); | |||
} | |||
return description; | |||
@@ -924,7 +966,7 @@ public class Project { | |||
* Must not be <code>null</code>. | |||
*/ | |||
public void addDataTypeDefinition(String typeName, Class typeClass) { | |||
synchronized(dataClassDefinitions) { | |||
synchronized (dataClassDefinitions) { | |||
Class old = (Class) dataClassDefinitions.get(typeName); | |||
if (null != old) { | |||
if (old.equals(typeClass)) { | |||
@@ -1043,8 +1085,8 @@ public class Project { | |||
* creation fails. | |||
*/ | |||
public Task createTask(String taskType) throws BuildException { | |||
Task task=createNewTask(taskType); | |||
if(task!=null) { | |||
Task task = createNewTask(taskType); | |||
if (task != null) { | |||
addCreatedTask(taskType, task); | |||
} | |||
return task; | |||
@@ -1132,11 +1174,11 @@ public class Project { | |||
if (v != null) { | |||
Enumeration enum = v.elements(); | |||
while (enum.hasMoreElements()) { | |||
WeakishReference ref= | |||
WeakishReference ref = | |||
(WeakishReference) enum.nextElement(); | |||
Task t = (Task) ref.get(); | |||
//being a weak ref, it may be null by this point | |||
if(t!=null) { | |||
if (t != null) { | |||
t.markInvalid(); | |||
} | |||
} | |||
@@ -1240,6 +1282,48 @@ public class Project { | |||
} | |||
} | |||
/** | |||
* Read data from the default input stream. If no default has been | |||
* specified, System.in is used. | |||
* | |||
* @param buffer the buffer into which data is to be read. | |||
* @param offset the offset into the buffer at which data is stored. | |||
* @param length the amount of data to read | |||
* | |||
* @return the number of bytes read | |||
* | |||
* @exception IOException if the data cannot be read | |||
*/ | |||
public int defaultInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (defaultInputStream != null) { | |||
return defaultInputStream.read(buffer, offset, length); | |||
} else { | |||
return System.in.read(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Demux an input request to the correct task. | |||
* | |||
* @param buffer the buffer into which data is to be read. | |||
* @param offset the offset into the buffer at which data is stored. | |||
* @param length the amount of data to read | |||
* | |||
* @return the number of bytes read | |||
* | |||
* @exception IOException if the data cannot be read | |||
*/ | |||
public int demuxInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
Task task = (Task) threadTasks.get(Thread.currentThread()); | |||
if (task == null) { | |||
return defaultInput(buffer, offset, length); | |||
} else { | |||
return task.handleInput(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Demultiplexes flush operation so that each task receives the appropriate | |||
* messages. If the current thread is not currently executing a task, | |||
@@ -1250,8 +1334,6 @@ public class Project { | |||
* @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>). | |||
* @param terminated true if this line should be terminated with an | |||
* end-of-line marker | |||
*/ | |||
public void demuxFlush(String line, boolean isError) { | |||
Task task = (Task) threadTasks.get(Thread.currentThread()); | |||
@@ -1763,7 +1845,7 @@ public class Project { | |||
*/ | |||
public void addReference(String name, Object value) { | |||
synchronized (references) { | |||
Object old = ((AntRefTable)references).getReal(name); | |||
Object old = ((AntRefTable) references).getReal(name); | |||
if (old == value) { | |||
// no warning, this is not changing anything | |||
return; | |||
@@ -1777,7 +1859,7 @@ public class Project { | |||
try { | |||
valueAsString = value.toString(); | |||
} catch (Throwable t) { | |||
log("Caught exception (" + t.getClass().getName() +")" | |||
log("Caught exception (" + t.getClass().getName() + ")" | |||
+ " while expanding " + name + ": " + t.getMessage(), | |||
MSG_WARN); | |||
} | |||
@@ -2051,7 +2133,7 @@ public class Project { | |||
Project project; | |||
public AntRefTable(Project project) { | |||
super(); | |||
this.project=project; | |||
this.project = project; | |||
} | |||
/** Returns the unmodified original object. | |||
@@ -2061,8 +2143,8 @@ public class Project { | |||
* of UnknownElement ( this is similar with the JDNI | |||
* refs behavior ) | |||
*/ | |||
public Object getReal(Object key ) { | |||
return super.get( key ); | |||
public Object getReal(Object key) { | |||
return super.get(key); | |||
} | |||
/** Get method for the reference table. | |||
@@ -2078,11 +2160,11 @@ public class Project { | |||
*/ | |||
public Object get(Object key) { | |||
//System.out.println("AntRefTable.get " + key); | |||
Object o=super.get(key); | |||
if( o instanceof UnknownElement ) { | |||
Object o = super.get(key); | |||
if (o instanceof UnknownElement) { | |||
// Make sure that | |||
((UnknownElement)o).maybeConfigure(); | |||
o=((UnknownElement)o).getTask(); | |||
((UnknownElement) o).maybeConfigure(); | |||
o = ((UnknownElement) o).getTask(); | |||
} | |||
return o; | |||
} | |||
@@ -2091,28 +2173,28 @@ public class Project { | |||
private static class AntTaskTable extends LazyHashtable { | |||
Project project; | |||
Properties props; | |||
boolean tasks=false; | |||
boolean tasks = false; | |||
public AntTaskTable( Project p, boolean tasks ) { | |||
this.project=p; | |||
this.tasks=tasks; | |||
public AntTaskTable(Project p, boolean tasks) { | |||
this.project = p; | |||
this.tasks = tasks; | |||
} | |||
public void addDefinitions( Properties props ) { | |||
this.props=props; | |||
public void addDefinitions(Properties props) { | |||
this.props = props; | |||
} | |||
protected void initAll( ) { | |||
if( initAllDone ) return; | |||
protected void initAll() { | |||
if (initAllDone ) return; | |||
project.log("InitAll", Project.MSG_DEBUG); | |||
if( props==null ) return; | |||
if (props==null ) return; | |||
Enumeration enum = props.propertyNames(); | |||
while (enum.hasMoreElements()) { | |||
String key = (String) enum.nextElement(); | |||
Class taskClass=getTask( key ); | |||
if( taskClass!=null ) { | |||
if (taskClass!=null ) { | |||
// This will call a get() and a put() | |||
if( tasks ) | |||
if (tasks ) | |||
project.addTaskDefinition(key, taskClass); | |||
else | |||
project.addDataTypeDefinition(key, taskClass ); | |||
@@ -2122,19 +2204,19 @@ public class Project { | |||
} | |||
protected Class getTask(String key) { | |||
if( props==null ) return null; // for tasks loaded before init() | |||
if (props==null ) return null; // for tasks loaded before init() | |||
String value=props.getProperty(key); | |||
if( value==null) { | |||
if (value==null) { | |||
//project.log( "No class name for " + key, Project.MSG_VERBOSE ); | |||
return null; | |||
} | |||
try { | |||
Class taskClass=null; | |||
if( project.getCoreLoader() != null && | |||
if (project.getCoreLoader() != null && | |||
!("only".equals(project.getProperty("build.sysclasspath")))) { | |||
try { | |||
taskClass=project.getCoreLoader().loadClass(value); | |||
if( taskClass != null ) return taskClass; | |||
if (taskClass != null ) return taskClass; | |||
} catch( Exception ex ) { | |||
} | |||
} | |||
@@ -2153,11 +2235,11 @@ public class Project { | |||
// Hashtable implementation | |||
public Object get( Object key ) { | |||
Object orig=super.get( key ); | |||
if( orig!= null ) return orig; | |||
if( ! (key instanceof String) ) return null; | |||
if (orig!= null ) return orig; | |||
if (! (key instanceof String) ) return null; | |||
project.log("Get task " + key, Project.MSG_DEBUG ); | |||
Object taskClass=getTask( (String) key); | |||
if( taskClass != null) | |||
if (taskClass != null) | |||
super.put( key, taskClass ); | |||
return taskClass; | |||
} | |||
@@ -55,6 +55,7 @@ | |||
package org.apache.tools.ant; | |||
import java.util.Enumeration; | |||
import java.io.IOException; | |||
/** | |||
* Base class for all tasks. | |||
@@ -312,6 +313,22 @@ public abstract class Task extends ProjectComponent { | |||
handleOutput(line); | |||
} | |||
/** | |||
* Handle an input request by this task | |||
* | |||
* @param buffer the buffer into which data is to be read. | |||
* @param offset the offset into the buffer at which data is stored. | |||
* @param length the amount of data to read | |||
* | |||
* @return the number of bytes read | |||
* | |||
* @exception IOException if the data cannot be read | |||
*/ | |||
protected int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
return getProject().defaultInput(buffer, offset, length); | |||
} | |||
/** | |||
* Handles an error line by logging it with the INFO priority. | |||
* | |||
@@ -397,6 +414,9 @@ public abstract class Task extends ProjectComponent { | |||
/** | |||
* Has this task been marked invalid? | |||
* | |||
* @return true if this task is no longer valid. A new task should be | |||
* configured in this case. | |||
* | |||
* @since Ant 1.5 | |||
*/ | |||
protected final boolean isInvalid() { | |||
@@ -55,6 +55,7 @@ | |||
package org.apache.tools.ant; | |||
import java.util.Vector; | |||
import java.io.IOException; | |||
/** | |||
* Wrapper class that holds all the information necessary to create a task | |||
@@ -124,7 +125,7 @@ public class UnknownElement extends Task { | |||
getWrapper().setProxy(realThing); | |||
if (realThing instanceof Task) { | |||
Task task=(Task)realThing; | |||
Task task = (Task) realThing; | |||
task.setProject(project); | |||
task.setRuntimeConfigurableWrapper(getWrapper()); | |||
@@ -135,7 +136,7 @@ public class UnknownElement extends Task { | |||
// For Script to work. Ugly | |||
// The reference is replaced by RuntimeConfigurable | |||
this.getOwningTarget().replaceChild(this, (Task)realThing); | |||
this.getOwningTarget().replaceChild(this, (Task) realThing); | |||
} | |||
handleChildren(realThing, getWrapper()); | |||
@@ -156,6 +157,26 @@ public class UnknownElement extends Task { | |||
} | |||
} | |||
/** | |||
* Handle an input request by this element | |||
* | |||
* @param buffer the buffer into which data is to be read. | |||
* @param offset the offset into the buffer at which data is stored. | |||
* @param length the amount of data to read | |||
* | |||
* @return the number of bytes read | |||
* | |||
* @exception IOException if the data cannot be read | |||
*/ | |||
protected int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (realThing instanceof Task) { | |||
return ((Task) realThing).handleInput(buffer, offset, length); | |||
} else { | |||
return super.handleInput(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Handles output sent to System.out by this task or its real task. | |||
* | |||
@@ -214,7 +235,7 @@ public class UnknownElement extends Task { | |||
// the task will not be reused ( a new init() will be called ) | |||
// Let GC do its job | |||
realThing=null; | |||
realThing = null; | |||
} | |||
/** | |||
@@ -241,8 +262,7 @@ public class UnknownElement extends Task { | |||
*/ | |||
protected void handleChildren(Object parent, | |||
RuntimeConfigurable parentWrapper) | |||
throws BuildException | |||
{ | |||
throws BuildException { | |||
if (parent instanceof TaskAdapter) { | |||
parent = ((TaskAdapter) parent).getProxy(); | |||
} | |||
@@ -259,15 +279,15 @@ public class UnknownElement extends Task { | |||
//ProjectComponentHelper helper=ProjectComponentHelper.getProjectComponentHelper(); | |||
//realChild = helper.createProjectComponent( child, getProject(), null, | |||
// child.getTag()); | |||
realChild=makeTask(child, childWrapper, false); | |||
realChild = makeTask(child, childWrapper, false); | |||
if (realChild == null ) { | |||
if (realChild == null) { | |||
throw getNotFoundException("task", child.getTag()); | |||
} | |||
// XXX DataTypes will be wrapped or treated like normal components | |||
if( realChild instanceof Task ) { | |||
Task task=(Task)realChild; | |||
if (realChild instanceof Task) { | |||
Task task = (Task) realChild; | |||
((TaskContainer) parent).addTask(task); | |||
task.setLocation(child.getLocation()); | |||
// UnknownElement always has an associated target | |||
@@ -277,7 +297,8 @@ public class UnknownElement extends Task { | |||
// What ? Add data type ? createElement ? | |||
} | |||
} else { | |||
realChild = ih.createElement(getProject(), parent, child.getTag()); | |||
realChild | |||
= ih.createElement(getProject(), parent, child.getTag()); | |||
} | |||
childWrapper.setProxy(realChild); | |||
@@ -296,6 +296,18 @@ public class Ant extends Task { | |||
} | |||
} | |||
/** | |||
* @see Task#handleInput(byte[], int, int) | |||
*/ | |||
public int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (newProject != null) { | |||
return newProject.demuxInput(buffer, offset, length); | |||
} else { | |||
return super.handleInput(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Pass output sent to System.out to the new project. | |||
* | |||
@@ -443,7 +455,8 @@ public class Ant extends Task { | |||
* requested. | |||
*/ | |||
private void addReferences() throws BuildException { | |||
Hashtable thisReferences = (Hashtable) getProject().getReferences().clone(); | |||
Hashtable thisReferences | |||
= (Hashtable) getProject().getReferences().clone(); | |||
Hashtable newReferences = newProject.getReferences(); | |||
Enumeration e; | |||
if (references.size() > 0) { | |||
@@ -56,6 +56,7 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Task; | |||
import java.io.IOException; | |||
/** | |||
* Call another target in the same project. | |||
@@ -185,6 +186,15 @@ public class CallTarget extends Task { | |||
} | |||
} | |||
public int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (callee != null) { | |||
return callee.handleInput(buffer, offset, length); | |||
} else { | |||
return super.handleInput(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Pass output sent to System.out to the new project. | |||
* | |||
@@ -416,6 +416,15 @@ public class Java extends Task { | |||
} | |||
} | |||
public int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (redirector.getInputStream() != null) { | |||
return redirector.handleInput(buffer, offset, length); | |||
} else { | |||
return super.handleInput(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Pass output sent to System.out to specified output file. | |||
* | |||
@@ -79,37 +79,92 @@ import org.apache.tools.ant.util.TeeOutputStream; | |||
* @since Ant 1.6 | |||
*/ | |||
public class Redirector { | |||
/** | |||
* The file receiveing standard output. Will also receive standard error | |||
* unless standard error is redirected or logError is true. | |||
*/ | |||
private File out; | |||
/** | |||
* The file to which standard error is being redirected | |||
*/ | |||
private File error; | |||
/** | |||
* The file from which standard input is being taken. | |||
*/ | |||
private File input; | |||
/** | |||
* Indicates if standard error should be logged to Ant's log system | |||
* rather than the output. This has no effect if standard error is | |||
* redirected to a file or property. | |||
*/ | |||
private boolean logError = false; | |||
/** | |||
* Buffer used to capture output for storage into a property | |||
*/ | |||
private ByteArrayOutputStream baos = null; | |||
/** | |||
* Buffer used to capture error output for storage into a property | |||
*/ | |||
private ByteArrayOutputStream errorBaos = null; | |||
/** The name of the property into which output is to be stored */ | |||
private String outputProperty; | |||
/** The name of the property into which error output is to be stored */ | |||
private String errorProperty; | |||
/** String from which input is taken */ | |||
private String inputString; | |||
/** Flag which indicates if error and output files are to be appended. */ | |||
private boolean append = false; | |||
/** The task for which this redirector is working */ | |||
private Task managingTask; | |||
/** The stream for output data */ | |||
private OutputStream outputStream = null; | |||
/** The stream for error output */ | |||
private OutputStream errorStream = null; | |||
private InputStream inputStream = null; | |||
/** The stream for input */ | |||
private InputStream inputStream = null; | |||
/** Stream which are used for line oriented output */ | |||
private PrintStream outPrintStream = null; | |||
/** Stream which is used for line oriented error output */ | |||
private PrintStream errorPrintStream = null; | |||
/** | |||
* Create a redirector instance for the given task | |||
* | |||
* @param managingTask the task for which the redirector is to work | |||
*/ | |||
public Redirector(Task managingTask) { | |||
this.managingTask = managingTask; | |||
} | |||
/** | |||
* Set the input to use for the task | |||
* | |||
* @param input the file from which input is read. | |||
*/ | |||
public void setInput(File input) { | |||
this.input = input; | |||
} | |||
/** | |||
* Set the string to use as input | |||
* | |||
* @param inputString the string which is used as the input source | |||
*/ | |||
public void setInputString(String inputString) { | |||
this.inputString = inputString; | |||
} | |||
@@ -118,6 +173,8 @@ public class Redirector { | |||
/** | |||
* File the output of the process is redirected to. If error is not | |||
* redirected, it too will appear in the output | |||
* | |||
* @param out the file to which output stream is written | |||
*/ | |||
public void setOutput(File out) { | |||
this.out = out; | |||
@@ -127,14 +184,18 @@ public class Redirector { | |||
* Controls whether error output of exec is logged. This is only useful | |||
* when output is being redirected and error output is desired in the | |||
* Ant log | |||
* | |||
* @param logError if true the standard error is sent to the Ant log system | |||
* and not sent to output. | |||
*/ | |||
public void setLogError(boolean logError) { | |||
this.logError = logError; | |||
} | |||
/** | |||
* File the error stream of the process is redirected to. | |||
* Set the file to which standard error is to be redirected. | |||
* | |||
* @param error the file to which error is to be written | |||
*/ | |||
public void setError(File error) { | |||
this.error = error; | |||
@@ -143,6 +204,9 @@ public class Redirector { | |||
/** | |||
* Property name whose value should be set to the output of | |||
* the process. | |||
* | |||
* @param outputProperty the name of the property to be set with the | |||
* task's output. | |||
*/ | |||
public void setOutputProperty(String outputProperty) { | |||
this.outputProperty = outputProperty; | |||
@@ -152,6 +216,8 @@ public class Redirector { | |||
* Whether output should be appended to or overwrite an existing file. | |||
* Defaults to false. | |||
* | |||
* @param append if true output and error streams are appended to their | |||
* respective files, if specified. | |||
*/ | |||
public void setAppend(boolean append) { | |||
this.append = append; | |||
@@ -161,11 +227,21 @@ public class Redirector { | |||
* Property name whose value should be set to the error of | |||
* the process. | |||
* | |||
* @param errorProperty the name of the property to be set | |||
* with the error output. | |||
*/ | |||
public void setErrorProperty(String errorProperty) { | |||
this.errorProperty = errorProperty; | |||
} | |||
/** | |||
* Set a property from a ByteArrayOutputStream | |||
* | |||
* @param baos contains the property value. | |||
* @param propertyName the property name. | |||
* | |||
* @exception IOException if the value cannot be read form the stream. | |||
*/ | |||
private void setPropertyFromBAOS(ByteArrayOutputStream baos, | |||
String propertyName) throws IOException { | |||
@@ -183,6 +259,10 @@ public class Redirector { | |||
} | |||
/** | |||
* Create the input, error and output streams based on the | |||
* configuration options. | |||
*/ | |||
public void createStreams() { | |||
if (out == null && outputProperty == null) { | |||
outputStream = new LogOutputStream(managingTask, Project.MSG_INFO); | |||
@@ -265,6 +345,11 @@ public class Redirector { | |||
/** | |||
* Create the StreamHandler to use with our Execute instance. | |||
* | |||
* @return the execute stream handler to manage the input, output and | |||
* error streams. | |||
* | |||
* @throws BuildException if the execute stream handler cannot be created. | |||
*/ | |||
public ExecuteStreamHandler createHandler() throws BuildException { | |||
createStreams(); | |||
@@ -272,8 +357,9 @@ public class Redirector { | |||
} | |||
/** | |||
* Pass output sent to System.out to specified output file. | |||
* Pass output sent to System.out to specified output. | |||
* | |||
* @param line the data to be output | |||
*/ | |||
protected void handleOutput(String line) { | |||
if (outPrintStream == null) { | |||
@@ -282,9 +368,31 @@ public class Redirector { | |||
outPrintStream.println(line); | |||
} | |||
/** | |||
* Handle an input request | |||
* | |||
* @param buffer the buffer into which data is to be read. | |||
* @param offset the offset into the buffer at which data is stored. | |||
* @param length the amount of data to read | |||
* | |||
* @return the number of bytes read | |||
* | |||
* @exception IOException if the data cannot be read | |||
*/ | |||
protected int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (inputStream == null) { | |||
return managingTask.getProject().defaultInput(buffer, offset, | |||
length); | |||
} else { | |||
return inputStream.read(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Pass output sent to System.out to specified output file. | |||
* Process data due to a flush operation. | |||
* | |||
* @param line the data being flushed. | |||
*/ | |||
protected void handleFlush(String line) { | |||
if (outPrintStream == null) { | |||
@@ -294,8 +402,9 @@ public class Redirector { | |||
} | |||
/** | |||
* Pass output sent to System.err to specified output file. | |||
* Process error output | |||
* | |||
* @param line the error output data. | |||
*/ | |||
protected void handleErrorOutput(String line) { | |||
if (errorPrintStream == null) { | |||
@@ -305,8 +414,9 @@ public class Redirector { | |||
} | |||
/** | |||
* Pass output sent to System.err to specified output file. | |||
* Handle a flush operation on the error stream | |||
* | |||
* @param line the error information being flushed. | |||
*/ | |||
protected void handleErrorFlush(String line) { | |||
if (errorPrintStream == null) { | |||
@@ -315,15 +425,45 @@ public class Redirector { | |||
errorPrintStream.print(line); | |||
} | |||
/** | |||
* Get the output stream for the redirector | |||
* | |||
* @return the redirector's output stream or null if no output | |||
* has been configured | |||
*/ | |||
public OutputStream getOutputStream() { | |||
return outputStream; | |||
} | |||
/** | |||
* Get the error stream for the redirector | |||
* | |||
* @return the redirector's error stream or null if no output | |||
* has been configured | |||
*/ | |||
public OutputStream getErrorStream() { | |||
return errorStream; | |||
} | |||
/** | |||
* Get the input stream for the redirector | |||
* | |||
* @return the redirector's input stream or null if no output | |||
* has been configured | |||
*/ | |||
public InputStream getInputStream() { | |||
return inputStream; | |||
} | |||
/** | |||
* Complete redirection. | |||
* | |||
* This opertaion will close any streams and create any specified | |||
* property values. | |||
* | |||
* @throws IOException if the outptu properties cannot be read from their | |||
* output streams. | |||
*/ | |||
public void complete() throws IOException { | |||
System.out.flush(); | |||
System.err.flush(); | |||
@@ -713,6 +713,21 @@ public class JUnitTask extends Task { | |||
} | |||
} | |||
/** | |||
* @see Task#handleInput(byte[], int, int) | |||
* | |||
* @since Ant 1.6 | |||
*/ | |||
protected int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
if (runner != null) { | |||
return runner.handleInput(buffer, offset, length); | |||
} else { | |||
return super.handleInput(buffer, offset, length); | |||
} | |||
} | |||
/** | |||
* Pass output sent to System.out to the TestRunner so it can | |||
* collect ot for the formatters. | |||
@@ -410,6 +410,11 @@ public class JUnitTestRunner implements TestListener { | |||
} | |||
} | |||
protected int handleInput(byte[] buffer, int offset, int length) | |||
throws IOException { | |||
return -1; | |||
} | |||
protected void handleErrorOutput(String line) { | |||
if (systemError != null) { | |||
systemError.println(line); | |||
@@ -56,9 +56,10 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.BuildFileTest; | |||
import java.util.Random; | |||
/** | |||
* A simple task that prints to System.out and System.err and then catches | |||
* the output which it then check. If the output does not match, an | |||
* the output which it then checks. If the output does not match, an | |||
* exception is thrown | |||
* | |||
* @since 1.5 | |||