Package qat.agent

Source Code of qat.agent.ExecProcess

package qat.agent;
/**
* This class handles the execution of a single process, and manages it's output stream collection etc.
*
* @author webhiker
* @version 2.3, 17 June 1999
*/
// standard Java imports
import java.lang.Thread;
import java.lang.System;
import java.lang.Math;
import java.io.*;
import java.lang.Runtime;
import java.lang.Process;
import java.lang.IllegalThreadStateException;
import java.lang.Thread;
import java.util.Properties;
import java.util.Enumeration;
import java.util.Date;

// qa tester imports
import qat.agent.ReaderThread;
import qat.common.ConsoleServer;
import qat.common.TestObject;
import qat.common.Utils;

/**
* This class is responsible for executing a single TestObject, and starting new threads to read it's standard output
* and error output streams.
* It allows for killing of the started TestObject at anytime by calling the cancel() method.
*/
public class ExecProcess extends Object {
    private static final int NOT_YET_SET          = -9999;
    public  static final int TIMEDOUT_STATE       = -9998;
    private static final int ILLEGAL_THREAD_STATE = -5;
    private static final int NULL_POINTER         = -6;
    private static final int OTHER_EXCEPTION      = -7;
    private TestObject test;
    private Process process;
    private Date startTime;
    private ReaderThread stdin;
    private ReaderThread stderr;
    private int exitValue;
    private int debugLevel; // this is the level of detail we will use for debug message. 0 = none, 10 = max
    private PrintStream stdout;
    private boolean showOutput;
    private boolean interrupted;
    private String parentDetails;
    private boolean isDaemon; 
    /**
     * This constructs a new ExecProcess with the specified TestObject
     * @param t - the TestObject that will be executed when the start() method is called.
     * @param so - the PrintWriter to use for output.
     * @param level - the detail of debug message we want.
     * @param mode - if true, the output is displayed to stdout
     * @param parentDetails - some details about the parent so we can print it
     * to the trace files.
     */
    public ExecProcess(TestObject t, PrintStream so, int level, boolean mode, String parentDetails) {
  setDaemon(false);
  setInterrupted(false);
  test = t;
  setProcess(null);
  stdout = so;
  debugLevel = level;
  showOutput = mode;
  this.parentDetails = parentDetails;
    }
    /**
     * This method returns the TestObject associated with this Object.
     * @return the TestObject associated with this object.
     */
    public TestObject getTestObject() {
  return test;
    }
    /**
     * This method should not be called directly, but rather via ObjectName.start() to
     * ensure the thread is started correctly.
     */
    public void start() {
  exitValue = NOT_YET_SET;
  // make sure we allow only one instance of this process to run
  if (getProcess()!=null) {
      System.out.println("Internal error in ExecProcess - already have a process running!");
      return;
  }
  // take a snapshot of the current time, so we can calculate the timeout value
  startTime = new Date();
  // build the environment string list from our TestObject properties
  String commandArgs[] = test.getExecuteCommand();   

  File workDir = new File(test.getWorkDirectory());

  // build the environment string list from our TestObject properties
  String environment[] = new String[test.getExecuteEnvironment().size()];
  Enumeration e = test.getExecuteEnvironment().propertyNames();
  for (int i = 0; i < environment.length; i++) {
      environment[i] = (String)e.nextElement();
      environment[i] = environment[i]+"="+ test.getExecuteEnvironment().getProperty(environment[i])
  }
  PrintWriter out=null;
  try {
      // create and write the environment file
      out = new PrintWriter(new FileOutputStream(test.getEnvFileName()));
       
      debugMsg("Command arguments :"+commandArgs.length,out,1);
      debugMsg("-------------------",out,1);
      for (int i = 0; i < commandArgs.length; i++) {
    debugMsg(" Argument "+i+" :"+commandArgs[i],out,1);
      }
      debugMsg("",out,1);
       
      debugMsg("Agent details :",out,1);
      debugMsg("---------------",out,1);
      debugMsg(parentDetails,out,1);
      debugMsg("",out,1);
       
      debugMsg("Process environment :",out,1);
      debugMsg("---------------------",out,1);
      for (int i = 0; i < environment.length; i++)
    debugMsg(environment[i],out,1);
      debugMsg("Working directory : " + workDir,out,1);
      debugMsg("",out,1);

      // patch to inherit env if we don't specify one
      if (environment.length==0)
    environment = null;

      setProcess(Runtime.getRuntime().exec(commandArgs, environment, workDir));
       
      // only store traces if it's not a daemon process
      if (!isDaemon()) {
    // now process the output and erroutput streams of this process by starting two threads
    // which monitor these streams
    stderr = new ReaderThread("StdErr",getProcess().getErrorStream(),showOutput, test.getStdErrFileName());
    debugMsg("Starting errout thread",out,5);
    stderr.start();
    stdin  = new ReaderThread("StdOutput",getProcess().getInputStream(),showOutput, test.getStdOutFileName());
    debugMsg("Starting stdout thread",out,5);
    stdin.start();
      }
      debugMsg("Process started at :"+(new Date()).toString(),out,1);
  }
  catch (IOException ex) {
      ConsoleServer.debugStackTrace(ex);
      debugMsg("IOException starting process :"+ex.getMessage(),out,5);
      interrupt();
  }
  catch (Throwable ex) {
      ConsoleServer.debugStackTrace(ex);
      debugMsg("Fatal error starting process :"+ex.getMessage(),out,5);
      interrupt();
      // delete this temporary files if they were created, since
      // it's an abnormal behaviour to get an error here
      if (test.getStdOutFileName().exists())
    test.getStdOutFileName().delete();
      if (test.getStdErrFileName().exists())
    test.getStdErrFileName().delete();
      if (test.getEnvFileName().exists())
    test.getEnvFileName().delete();
  }
   
  finally {
      try {
    out.flush();
    out.close();
      }
      catch (Exception ex) {
    ConsoleServer.debugMsg("Error closing trace file :"+ex.getMessage(),2);
      }
  }
    }
   
    private Process getProcess() {
  return this.process;
    }
   
    private void setProcess(Process p) {
  this.process = p;
    }
 
    /**
     * This function returns the exit value of the running process if it has finished
     * else it returns a negative value.
     * This method will not block if the process is still running.
     * @return the absolute value of the exit value of the process, or a negative int to indicate other
     * thread states (ILLEGAL_THREAD_STATE, NULL_POINTER, OTHER_EXCEPTION)
     */
    public synchronized int checkExitValue() {
  try {
      return Math.abs(getProcess().exitValue());
  }
  catch (IllegalThreadStateException  e) {
      return ILLEGAL_THREAD_STATE;
  }
  catch (NullPointerException  e) {
      return NULL_POINTER;
  }
  catch (Exception e) {
      return OTHER_EXCEPTION;
  }
    }
 
    /**
     * This function returns the exit value of the running process. If the process is not finished, this method
     * will block until it finishes, or the TestObject timeout value is reached.
     * If the test times-out, it is explicitly killed, as if a ACTION_TESTOBJECT_KILL message was sent by the harness.
     * @return the exit value of the process.
     */
    public synchronized int getExitValue() {
  if (exitValue>=0) {
      ConsoleServer.debugMsg("Process already finished ("+exitValue+") - returning previous exit code",9);
      return exitValue;
  }
  else {
      while ((!wasInterrupted())&&
       ((exitValue = checkExitValue())<0)&&
       (!testTimedOut())&&
       (exitValue>=OTHER_EXCEPTION)) {
    ConsoleServer.debugMsg("Checking process exit value ("+exitValueString(exitValue)+") - will timeout in "+getTimeLeft()+" seconds",9);
    Utils.safeSleep(1);
      }
      // check if it timed out
      if (testTimedOut())
    exitValue = TIMEDOUT_STATE;
      return exitValue;
  }
    }
 
    /**
     * If the val is an internal QAT code, return a string version of the code,
     * else just return the integer value as a String.
     */
    private String exitValueString(int val) {
  if (val < 0) {
      switch (val) {
      case NOT_YET_SET         :return "NOT_YET_SET";
      case ILLEGAL_THREAD_STATE:return "NOT_FINISHED";
      case TIMEDOUT_STATE      :return "TIMEDOUT_STATE";
      case NULL_POINTER        :return "NULL_POINTER";
      case OTHER_EXCEPTION     :return "OTHER_EXCEPTION";
      }
  }
  return Integer.toString(val);
    }
 
    /**
     * Returns true if we need to stop this process.
     */
    private boolean wasInterrupted() {
  return interrupted;
    }
 
    private void setInterrupted(boolean i) {
  interrupted = i;
    }
 
    private long getTimeLeft() {
  return ((startTime.getTime()+1000*test.getTimeout())-(new Date()).getTime())/1000;
    }
 
    /**
     * Will return false until the test has timed out, and then it will return true.
     * A test is considered as timed out if it runs longer than the value of TestObject.geTimeout() which
     * is measured in seconds.
     */
    private boolean testTimedOut() {
  Date now = new Date();
  if ((test.getTimeout()!=0)&&(now.after(new Date(startTime.getTime()+1000*test.getTimeout())))) {
      return true;
  }
  else {
      return false;
  }
    }
    /**
     * This will kill the TestObject execution and free all the resource associated with this
     * TestObject execution.
     */
    public void interrupt() {
  setInterrupted(true);
   
  if (exitValue==NOT_YET_SET)
      exitValue = checkExitValue();
   
  destroy();
   
  if (stdin != null) {
      stdin.interrupt();
      stdin = null;
  }
  if (stderr != null) {
      stderr.interrupt();
      stderr = null;
  }
    }
 
    /**
     * Outputs a debug message if the debug level corresponds to the level
     * of debug the agent is set to.
     */
    private void debugMsg(String msg, PrintWriter out, int level) {
  ConsoleServer.debugMsg(msg,level);
  try {
      out.println(msg);
  }
  catch (Exception e) {
      ConsoleServer.debugMsg("Error recording trace file :"+e,2);
  }
    }
 
    public boolean isDaemon() {
  return isDaemon;
    }
 
    public void setDaemon(boolean isDaemon) {
  this.isDaemon = isDaemon;
    }
 
    public void destroy() {
  Process proc = getProcess();
  if (proc != null)
      proc.destroy();
    }

    }
TOP

Related Classes of qat.agent.ExecProcess

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.