blob: 472149432395548a6b9625c1c84596afca3741ee [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.etch.interoptester;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.etch.util.Assertion;
import org.apache.etch.util.core.xml.XmlParser.TagElement;
/**
* Program models a program to be run as part of a test. The program has
* positional parameters, environment, stdin, stdout, stderr, and timeout.
*/
public class Program
{
/**
* @param itest
* @param r
* @return the parsed Program.
*/
public static Program parse( InteropTestIntf itest, TagElement r )
{
Assertion.check( r.matches( null, "program" ), "tag is program" );
String name = r.getAttr( null, "name" );
if (name == null || name.length() == 0)
throw new IllegalArgumentException( "program tag has no name" );
Program p = new Program( itest, name );
p.parseBody( r );
return p;
}
/**
* @param itest
* @param name
*/
private Program( InteropTestIntf itest, String name )
{
this.itest = itest;
this.name = name;
}
private final InteropTestIntf itest;
private final String name;
/**
* @return the containing InteropTestIntf.
*/
public InteropTestIntf itest()
{
return itest;
}
/**
* @return the name of this Program.
*/
public String name()
{
return name;
}
/**
* @param r
*/
public void parseBody( TagElement r )
{
new ChildWalker()
{
public boolean tag( TagElement te )
{
if (te.matches( null, "params" ))
{
parseParams( te );
return true;
}
if (te.matches( null, "tokens" ))
{
parseTokens( te );
return true;
}
if (te.matches( null, "environment" ))
{
parseEnvironment( te );
return true;
}
if (te.matches( null, "stdin" ))
{
parseStdin( te );
return true;
}
if (te.matches( null, "stdout" ))
{
parseStdout( te );
return true;
}
if (te.matches( null, "stderr" ))
{
parseStderr( te );
return true;
}
if (te.matches( null, "stdouttag" ))
{
parseStdoutTag( te );
return true;
}
if (te.matches( null, "stderrtag" ))
{
parseStderrTag( te );
return true;
}
if (te.matches( null, "timeout" ))
{
parseTimeout( te );
return true;
}
return false;
}
}.walk( r );
}
private void parseParams( TagElement r )
{
new ChildWalker()
{
public boolean tag( TagElement te )
{
if (te.matches( null, "param" ))
{
parseParam( te );
return true;
}
return false;
}
}.walk( r );
}
private void parseParam( TagElement te )
{
Param p = Param.parse( te );
params.put( p.name(), p );
}
private final Map<String, Param> params = new HashMap<String, Param>();
private void parseTokens( TagElement r )
{
new ChildWalker()
{
public boolean tag( TagElement te )
{
if (te.matches( null, "token" ))
{
parseToken( te );
return true;
}
return false;
}
}.walk( r );
}
private void parseToken( TagElement r )
{
tokens.add( Token.parse( r ) );
}
private final List<Token> tokens = new ArrayList<Token>();
private void parseEnvironment( TagElement r )
{
new ChildWalker()
{
public boolean tag( TagElement te )
{
if (te.matches( null, "env" ))
{
parseEnv( te );
return true;
}
return false;
}
}.walk( r );
}
private void parseEnv( TagElement r )
{
Env e = Env.parse( r );
envs.put( e.name(), e );
}
private final Map<String, Env> envs = new HashMap<String, Env>();
private void parseStdin( TagElement r )
{
// TODO Auto-generated method stub
throw new UnsupportedOperationException( "parseStdin" );
}
private void parseStdout( TagElement r )
{
// TODO Auto-generated method stub
throw new UnsupportedOperationException( "parseStdout" );
}
private void parseStderr( TagElement r )
{
// TODO Auto-generated method stub
throw new UnsupportedOperationException( "parseStderr" );
}
private void parseStdoutTag( TagElement r )
{
stdoutTag = r.getCdataValue();
}
private String stdoutTag = "out";
private void parseStderrTag( TagElement r )
{
stderrTag = r.getCdataValue();
}
private String stderrTag = "err";
private void parseTimeout( TagElement r )
{
// TODO Auto-generated method stub
throw new UnsupportedOperationException( "parseTimeout" );
}
/**
* @param overrides
* @return a RunningProg which allows the running program to be controlled.
* @throws Exception
*/
public RunningProg start( Map<String, String> overrides ) throws Exception
{
Map<String, String> substs = processOverrides( "start", overrides );
List<String> tkns = processTokens( substs );
Map<String, String> nvs = processEnvs( substs );
//System.out.printf( "Program.start: tokens %s envs %s\n", tkns, nvs );
DefaultRunningProg rp = new DefaultRunningProg( tkns, nvs, stdoutTag, stderrTag );
try
{
rp.start();
return rp;
}
catch ( Exception e )
{
e.printStackTrace();
try
{
rp.stop();
}
catch ( InterruptedException e1 )
{
e1.printStackTrace();
}
throw new Exception( "process did not start" );
}
}
/**
* @param overrides
* @throws Exception
*/
public void run( Map<String, String> overrides ) throws Exception
{
Map<String, String> substs = processOverrides( "run", overrides );
List<String> tkns = processTokens( substs );
Map<String, String> nvs = processEnvs( substs );
//System.out.printf( "Program.run: tokens %s envs %s\n", tkns, nvs );
DefaultRunningProg rp = new DefaultRunningProg( tkns, nvs, stdoutTag, stderrTag );
try
{
rp.start();
}
catch ( Exception e )
{
e.printStackTrace();
try
{
rp.stop();
}
catch ( InterruptedException e1 )
{
e1.printStackTrace();
}
throw new Exception( "process did not start" );
}
try
{
Integer sts = rp.join();
if (sts == null || sts != 0)
throw new Exception( "process died with bad status: "+sts );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
private Map<String, String> processOverrides( String who,
Map<String, String> overrides )
{
//System.out.println( "Program."+who+": name "+name+", overrides = "+overrides );
Map<String, String> substs = Param.processOverrides( "program", params,
overrides );
//System.out.println( "Program."+who+": name "+name+", substs = "+substs );
return substs;
}
private List<String> processTokens( Map<String, String> substs )
{
List<String> ntokens = new ArrayList<String>();
for (Token t: tokens)
ntokens.add( t.value( substs ) );
return ntokens;
}
private Map<String, String> processEnvs( Map<String, String> substs )
{
Map<String, String> nenvs = new HashMap<String, String>();
for (Env e: envs.values())
nenvs.put( e.name(), e.value( substs ) );
return nenvs;
}
/**
* @author wert
*
*/
public static class ProcessStreamReader extends Thread
{
/**
* @param is input stream to read until eof.
* @param tag
* @param ps
* @throws Exception
*/
public ProcessStreamReader( InputStream is, PrintStream ps, String tag ) throws Exception
{
rdr = new BufferedReader( new InputStreamReader( is ) );
this.ps = ps;
this.tag = tag;
}
private final BufferedReader rdr;
private final PrintStream ps;
private final String tag;
@Override
public void run()
{
try
{
String s;
while ((s = rdr.readLine()) != null)
{
synchronized (ps)
{
ps.printf( "[%s] %s\n", tag, s );
}
}
}
catch ( Exception e )
{
e.printStackTrace();
}
finally
{
try
{
rdr.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
}
}
}
}