Package com.sun.enterprise.util

Source Code of com.sun.enterprise.util.FlusherThread

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.enterprise.util;

//JDK imports
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.FileReader;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.lang.IllegalArgumentException;
/**
  @author  Kedar
  @version 1.0
*/

public class ProcessExecutor
{
    public static final long kDefaultTimeoutMillis = 600000;
    public static final long kSleepTime = 2000;
    private static final long DEFAULT_TIMEOUT_SEC = 600;
    private static final String NEWLINE = System.getProperty("line.separator");
    private long mTimeoutMilliseconds = 0;
    protected String[] mCmdStrings = null;
    protected File mOutFile = null;
    protected File mErrFile = null;
    private OutputStream mOutStream = null;
    private OutputStream mErrStream = null;

    private File mWorkingDir = null; //working directory   
    private String[] mEnv = null; //environment
    private String[] mInputLines = null; // strings to set in process's InputStream (like from redirection)
    private int mExitValue = -1;
    private Process mSubProcess=null; // used to get handle to child process for ProcessManager funtionality
    private boolean mVerboseMode = false;
    private boolean retainExecutionLogs  = false;
    private String lastExecutionOutputString = null;
    private String lastExecutionErrorString = null;
    private static boolean bDebug=false;

    /**
    Creates new ProcessExecutor
  */
  public ProcessExecutor(String[] cmd)
  {
    this(cmd, DEFAULT_TIMEOUT_SEC, null);
  }
 
  /**
    Creates new ProcessExecutor
  */
  public ProcessExecutor(String[] cmd, String[] inputLines)
  {
    this(cmd, DEFAULT_TIMEOUT_SEC, inputLines);
  }

  /**
    Creates new ProcessExecutor
  */
        public ProcessExecutor(String[] cmd, long timeoutSeconds)
  {
    this(cmd, timeoutSeconds, null);
        }
   
        public ProcessExecutor(String[] cmd, long timeoutSeconds, String[] inputLines)
        {
            this(cmd, timeoutSeconds, inputLines, null, null);
        }
       
  /**
    Creates a new <code> ProcessExecutor </code> that executes the given
    command.
    @param cmd String that has command name and its command line arguments
    @param timeoutSeconds long integer timeout to be applied in seconds. After this time
    if the process to execute does not end, it will be destroyed.
  */
 
        public ProcessExecutor(String[] cmd, long timeoutSeconds, String[] inputLines,
            String[] env, File workingDir)
  {
            mCmdStrings        = cmd;
            mInputLines             = inputLines;
            mEnv                    = env;
            mWorkingDir             = workingDir;
            char fwdSlashChar       = '/';
            char backSlashChar      = '\\';
           
            if (System.getProperty("Debug") != null) {
                // turn on debug, this option was added to help developers
                // debug the their code
                bDebug=true;
            }                       
           
            for(int i=0; i<mCmdStrings.length; i++)
            {
                if (OS.isUnix())
                {
                    mCmdStrings[i] = mCmdStrings[i].replace(backSlashChar, fwdSlashChar);
                }
                else
                {
                    mCmdStrings[i] = mCmdStrings[i].replace(fwdSlashChar, backSlashChar);
                }
            }
            mTimeoutMilliseconds = (long) timeoutSeconds * 1000;
        }
 
  /** This is the setting after the fact that an instance of ProcessExecutor
   * is created. This is to be used in case the output and error of the last
   * execute call has to be retained for latter analysis.
   * @param s boolean representing whether to retain, true means the buffers
   * will be retained, false otherwise.
   */
  public void setExecutionRetentionFlag(final boolean s) {
    this.retainExecutionLogs = s;
  }
  public boolean getExecutionRetentionFlag() {
    return ( this.retainExecutionLogs );
  }
  /** Returns the last LAST_BYTES bytes in the error stream of last execution as a String, if
   * the ProcessExecutor was configured properly. It may return null if the
   * retentionFlag is set to false.
   */
  public String getLastExecutionError() {
    return ( this.lastExecutionErrorString );
  }
  /** Returns the last LAST_BYTES bytes in the output stream of last execution as a String, if
   * the ProcessExecutor was configured properly. It may return null if the
   * retentionFlag is set to false.
   */
  public String getLastExecutionOutput() {
    return ( this.lastExecutionOutputString );
  }
  private void init() throws ExecException
  {
    try{
    mOutFile = File.createTempFile("stdout", null);
    mOutFile.deleteOnExit();
    mErrFile = File.createTempFile("stderr", null);
    mErrFile.deleteOnExit();
    }
    catch (IllegalArgumentException iae){
    deleteTempFiles();
    throw new ExecException("Internal error (util.ProcessExecutor.init()): "+iae.getMessage());
    }
    catch (IOException ioe){
    deleteTempFiles();
    throw new ExecException(cannotCreateTempFiles());
    }
  }

    private final static String cannotCreateTempFiles(){
  return "Could not create temporary files - check "
  + System.getProperty("java.io.tmpdir")
  + " to see if its writeable and not-full";
    }


    private void deleteTempFiles(){
        if (mOutStream != null) {
            try {
                mOutStream.flush();
                mOutStream.close();
            } catch (IOException ioe) {
                // Ignore
            }
        }
       
        if (mErrStream != null) {
            try {
                mErrStream.flush();
                mErrStream.close();
            } catch (IOException ioe) {
                // Ignore
            }
        }
  if (mOutFile != null) mOutFile.delete();
  if (mErrFile != null) mErrFile.delete();
    }
 
    public void execute() throws ExecException
    {
        execute(false);
    }

   
  /*
    Executes the command. Redirects the standard output and error streams
    safely to files. This makes the subprocess NOT block or wait on
    buffers getting flushed. This is done in a threaded manner.
    Note that the subprocess will be killed if it does not end in given
    timeout.
  
    @throws ExecException if anything goes wrong in subprocess, or subprocess
    terminates abruptly.
  */
 
  public String[] execute(boolean bReturnOutputLines) throws ExecException
  {
        return execute(bReturnOutputLines, true);
    }
   
   
    /**
     * Allows a subclass to control the error message returned when a non-zero exit code is
     * returned from a failed execution
     * @return
     */   
    protected String getExceptionMessage()
    {
        /* read the error message from error file */
        String errorMessage = getFileBuffer(mErrFile);                               
        if (errorMessage.length() == 0) {
            errorMessage = "The Process Output: " + getLatestOutput(mOutFile);
        }
        return "abnormal subprocess termination: Detailed Message:" + errorMessage;
    }
   
    /*
    Executes the command. Redirects the standard output and error streams
    safely to files. This makes the subprocess NOT block or wait on
    buffers getting flushed. This is done in a threaded manner.
    Note that the subprocess will be killed if it does not end in given
    timeout.
  
    @throws ExecException if anything goes wrong in subprocess, or subprocess
    terminates abruptly.
  */
 
  public String[] execute(boolean bReturnOutputLines, boolean bStartUpTimeLimit) throws ExecException
        {
            init();
            InputStream inputStream = null;
            try
            {
               
                if (bDebug) {
                    System.out.println("\n**** Executing command:");
                    for(int ii=0; ii < mCmdStrings.length; ii++) {
                        System.out.println(mCmdStrings[ii]);
                    }
                }
               
                mSubProcess = Runtime.getRuntime().exec(mCmdStrings, mEnv, mWorkingDir);
                if(mInputLines != null)
                    addInputLinesToProcessInput(mSubProcess);
                if(!bReturnOutputLines)
                    mOutStream = redirectProcessOutput(mSubProcess);
                else
                    inputStream = mSubProcess.getInputStream(); //attach to input stream for later reading
                mErrStream = redirectProcessError(mSubProcess);
               
                // see if process should startup in a limited ammount of time
                // processes used by ProcessManager don't return
                if (bStartUpTimeLimit) {
                    long  timeBefore = System.currentTimeMillis();
                    boolean timeoutReached    = false;
                    boolean isSubProcessFinished  = false;
                    boolean shouldBeDone    = false;
                    while (! shouldBeDone)
                    {
                        sleep(kSleepTime);
                        long timeAfter = System.currentTimeMillis();
                        timeoutReached = (timeAfter - timeBefore) >= mTimeoutMilliseconds;
                        try
                        {
                            mExitValue            = mSubProcess.exitValue();
                            isSubProcessFinished  = true;
                        }
                        catch(IllegalThreadStateException itse)
                        {
                            isSubProcessFinished = false;
                            //ignore exception
                        }
                        shouldBeDone = timeoutReached || isSubProcessFinished;
                    }
                    if (!isSubProcessFinished)
                    {
                        mSubProcess.destroy();
                        mExitValue = -255;
                        throw new ExecException("Subprocess timed out after "+mTimeoutMilliseconds +"mS");
                    }
                    else
                    {
                        mExitValue = mSubProcess.exitValue();
                        if (debug()) {
                            System.out.println("Subprocess command line = " + a2s(mCmdStrings));
                            System.out.println("Subprocess exit value = " + mExitValue);
                        }
                        if (mExitValue != 0)
                        {
                            mExitValue = mSubProcess.exitValue();
                            if (mExitValue != 0)
                            {  
                                throw new ExecException(getExceptionMessage());
                            }
                        }
                    }
                }
            }
            catch(SecurityException se)
            {
                throw new ExecException(se.getMessage());
            }
            catch(IOException ioe)
            {
              throw new ExecException(ioe.getMessage());
            }
            finally {

                // retain buffers before deleting them
                retainBuffers();

                // only delete files if the time is limited
                // for processes that don't return, the temp files will remain
                if (bStartUpTimeLimit) {
                    deleteTempFiles();
                }
            }

            if(bReturnOutputLines) {
                return getInputStrings(inputStream);
            } else {
                return null;
            }
           
        }

    /**
     * Get the exit value of the process executed. If this method is called
     * before process execution is complete (i.e. before execute() method has
     * returned, it will return -1. If sub process is terminated at timeout,
     * the method will return -255
     */
    public int getProcessExitValue() {
        return mExitValue;
    }

    private void addInputLinesToProcessInput(Process subProcess) throws ExecException {
  if(mInputLines==null)
            return;
       
        PrintWriter out = null;
        try
        {
            out = new PrintWriter(new BufferedWriter(
                new OutputStreamWriter(subProcess.getOutputStream())));

            for(int i=0; i<mInputLines.length; i++)
            {
                if(bDebug) {
                    System.out.println("InputLine ->" + mInputLines[i] + "<-");
                }
                out.println(mInputLines[i]);
            }
            out.flush();
        }
        catch (Exception e)
        {
            throw new ExecException(e.getMessage());
        }
        finally
        {
            try
            {
                out.close();
            }
            catch (Throwable t)
            {
        }
        }
    }

    private String[] getInputStrings(InputStream inputStream) throws ExecException
  {
    if(inputStream==null)
            return null;
        BufferedReader in = null;
        ArrayList list = new ArrayList();
        String    str;
        try
    {
      in = new BufferedReader( new InputStreamReader(inputStream));
      while((str=in.readLine())!=null)
                list.add(str);
            if(list.size()<1)
                return null;
            return (String[])list.toArray(new String[list.size()]);
           
    }
    catch (Exception e)
    {
      throw new ExecException(e.getMessage());
    }
        finally
        {
            try
            {
                in.close();
            }
            catch (Throwable t)
            {
            }
        }
  }

    private OutputStream redirectProcessOutput(Process subProcess) throws ExecException
  {
    OutputStream out = null;
                try
    {
      InputStream    in  = subProcess.getInputStream();
            // Redirect stderr for verbose mode
            if(mVerboseMode) {
                // send output to stderr
                out=System.err;
            } else {
                // send to temp file
                out=new FileOutputStream(mOutFile);
            }
           
      new FlusherThread(in, out).start();
    }
    catch (Exception e)
    {
      throw new ExecException(e.getMessage());
    }
                return out;
  }
 
  private OutputStream redirectProcessError(Process subProcess) throws ExecException
  {
                OutputStream out = null;
    try
    {
      InputStream    in  = subProcess.getErrorStream();
            // Redirect stderr for verbose mode
            if(mVerboseMode) {
                // send output to stderr
                out=System.err;
            } else {
                // send to temp file
                out=new FileOutputStream(mErrFile);
            }
      new FlusherThread(in, out).start();
    }
    catch (Exception e)
    {
      throw new ExecException(e.getMessage());
    }
                return out;
  }

    public void setVerbose(boolean verbose) {
        mVerboseMode=verbose;
    }
   
  private void sleep (long millis)
  {
    try
    {
      Thread.sleep(millis);
    }
    catch(InterruptedException ie)
    {
      //ignore exception
    }
  }
   
    /** Returns the contents of a file as a String. It never returns a null. If
     * the file is empty, an empty string is returned.
     * @param file the file to read
    */
    protected String getFileBuffer(File file) {
        final StringBuffer sb = new StringBuffer();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append(NEWLINE);
            }
        }
        catch(Exception e) {
            //squelch the exception
        }
        finally {
            try {
                reader.close();
            }
            catch(Exception e) {}
        }
        return ( sb.toString() );
    }
  protected String getLatestOutput(final File f) {
    return ( new RAFileReader(f).readLastBytesAsString() );
  }
 
  public void retainBuffers() {
    if (this.retainExecutionLogs) {
      this.lastExecutionErrorString  = this.getLatestOutput(this.mErrFile);
      this.lastExecutionOutputString  = this.getLatestOutput(this.mOutFile);
    }
  }
 
  private boolean debug() {
    final String td = System.getProperty("java.io.tmpdir");
    final String n = "as_debug_process_executor"; // a debug hook
    final File f = new File(td, n);
    return ( f.exists() );
  }
  private String a2s(String[] a) {
    final StringBuffer s = new StringBuffer();
    if (a != null) {
      for (int i = 0 ; i < a.length ; i++) {
        s.append(a[i]);
        s.append(" ");
      }
    }
    return ( s.toString() );
  }
  private static class RAFileReader {
    final File file;
    final int LAST_BYTES  = 16384;
    final String RMODE    = "r"; //read

    RAFileReader(final File file) {
      this.file= file;
    }

    String readLastBytesAsString() {
      final int n        = getNumberOfBytes(LAST_BYTES);
      final StringBuffer sb  = new StringBuffer();
      final long ln      = file.length(); //if SecurityManager is not present, this is safe.
      if (ln == 0)
        return ( sb.toString() ); //nothing to read, file may not exist, is protected, is a directory etc.
      assert (n <= ln) : ("Asked to read number of bytes more than size of file");
      final long s  = ln - n;
      return ( readWithoutCheck(s) );
    }

    private String readWithoutCheck(final long seekPos) {
      final StringBuffer sb  = new StringBuffer();
      RandomAccessFile rf    = null;
      long ln    = 0L;
      int lines  = 0;
      try {
        rf = new RandomAccessFile(file, RMODE);
        ln = rf.length();
        rf.seek(seekPos);
        String tmp = rf.readLine();
        while (tmp != null) {
          lines++;
          sb.append(tmp);
          //sb.append(Character.LINE_SEPARATOR);
          sb.append('\n'); // adding a newline character is going to add one extra byte
          tmp = rf.readLine();
        }
      }
      catch (Exception e) {
        //e.printStackTrace(); //ignore
      }
      finally {
        try {
          if (rf != null)
            rf.close();
        }
        catch(Exception e) {}//ignore;
      }
      //System.out.println("ln-seekPos = " + (ln - seekPos) );
      //System.out.println("bytes = " + sb.toString().getBytes().length);
      //System.out.println("lines = " + lines);
      //assert ((ln - seekPos) == (sb.toString().getBytes().length + lines)) : "Wrong number of bytes read";
      return ( sb.toString() );
    }

    private int getNumberOfBytes(final int max) {
      final long ln  = file.length();
      return ( max >= ln ? (int)ln : max );
    }
  }   

    // used for ProcessManager to watchdog subProcess
    public Process getSubProcess() {
        return mSubProcess;
    }

  public static void main(String args[])
    {
        testProcessError();
    }
   
    /* This method tests the condition of process throwing an error.
     * On Unixlike systems this throws an error in error file. On non-unixlike
     * Systems it will throw IOException for CreateProcess, which is desired */
    private static void testProcessError() {
        ProcessExecutor executor = new ProcessExecutor(
            new String[]{"/usr/bin/ls", "-wrongPARAMS123"});
        try {
            executor.execute();
        }
        catch (ExecException ee) {
            System.out.println(ee.getMessage());
        }
    }
}


    /**
     * inner class to flush runtime.exec process so it doesn't hang
     */
    class FlusherThread extends Thread {
        InputStream mInStream  = null;
        OutputStream mOutStream  = null;

        public static final int kSize = 1024;

        FlusherThread(InputStream in, OutputStream out) {
            mInStream = in;
            mOutStream = out;
        }

        public void run() {
        // check for null stream
        if (mInStream == null) return;

        // transfer bytes from input to output stream
        try {
            int byteCnt=0;
            byte[] buffer=new byte[4096];
            while ((byteCnt=mInStream.read(buffer)) != -1) {
                if (mOutStream != null && byteCnt > 0) {
                mOutStream.write(buffer, 0, byteCnt);
                mOutStream.flush();
            }
            yield();
            }
        } catch (IOException e) {
            // ignore
        } finally {
            try {
                mOutStream.close();
            } catch (IOException ioe) {
            // ignore
            }
        }       
    }
}
TOP

Related Classes of com.sun.enterprise.util.FlusherThread

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.
ref="/class/com/sun/enterprise/admin/servermgmt/services/SMFService.html" title="Examples of com.sun.enterprise.admin.servermgmt.services.SMFService">com.sun.enterprise.admin.servermgmt.services.SMFService
  • com.sun.enterprise.admin.servermgmt.SMFService
  • com.sun.enterprise.cli.commands.StartDomainCommand
  • com.sun.enterprise.ee.admin.hadbmgmt.BackDoor
  • com.sun.enterprise.ee.admin.servermgmt.EEInstancesManager
  • com.sun.enterprise.ee.nodeagent.ProcessInstanceExternal
  • com.sun.enterprise.instance.ServerManager
  • 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.