Package com.sos.VirtualFileSystem.SSH

Source Code of com.sos.VirtualFileSystem.SSH.SOSSSH2GanymedImpl$RemoteConsumer

/********************************************************* begin of preamble
**
** Copyright (C) 2003-2010 Software- und Organisations-Service GmbH.
** All rights reserved.
**
** This file may be used under the terms of either the
**
**   GNU General Public License version 2.0 (GPL)
**
**   as published by the Free Software Foundation
**   http://www.gnu.org/licenses/gpl-2.0.txt and appearing in the file
**   LICENSE.GPL included in the packaging of this file.
**
** or the
** 
**   Agreement for Purchase and Licensing
**
**   as offered by Software- und Organisations-Service GmbH
**   in the respective terms of supply that ship with this file.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
** IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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.
********************************************************** end of preamble*/
package com.sos.VirtualFileSystem.SSH;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Vector;

import org.apache.log4j.Logger;

import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.HTTPProxyData;
import ch.ethz.ssh2.SFTPException;
import ch.ethz.ssh2.SFTPv3Client;
import ch.ethz.ssh2.SFTPv3FileAttributes;
import ch.ethz.ssh2.SFTPv3FileHandle;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;

import com.sos.JSHelper.Basics.JSJobUtilities;
import com.sos.VirtualFileSystem.DataElements.SOSFileList;
import com.sos.VirtualFileSystem.DataElements.SOSFolderName;
import com.sos.VirtualFileSystem.Interfaces.ISOSAuthenticationOptions;
import com.sos.VirtualFileSystem.Interfaces.ISOSConnection;
import com.sos.VirtualFileSystem.Interfaces.ISOSConnectionOptions;
import com.sos.VirtualFileSystem.Interfaces.ISOSSession;
import com.sos.VirtualFileSystem.Interfaces.ISOSShell;
import com.sos.VirtualFileSystem.Interfaces.ISOSShellOptions;
import com.sos.VirtualFileSystem.Interfaces.ISOSVFSHandler;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFileSystem;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFolder;
import com.sos.VirtualFileSystem.Options.SOSConnection2OptionsAlternate;
import com.sos.VirtualFileSystem.common.SOSVfsBaseClass;
import com.sos.i18n.annotation.I18NResourceBundle;

/**
* \class SOSSSH2GanymedImpl
*
* \brief SOSSSH2GanymedImpl -
*
* \details
*
* \section SOSSSH2GanymedImpl.java_intro_sec Introduction
*
* \section SOSSSH2GanymedImpl.java_samples Some Samples
*
* \code
*   .... code goes here ...
* \endcode
*
* <p style="text-align:center">
* <br />---------------------------------------------------------------------------
* <br /> APL/Software GmbH - Berlin
* <br />##### generated by ClaviusXPress (http://www.sos-berlin.com) #########
* <br />---------------------------------------------------------------------------
* </p>
* \author KB
* @version $Id: SOSSSH2GanymedImpl.java 14789 2011-07-08 15:51:52Z sos $16.05.2010
* \see reference
*
* Created on 16.05.2010 19:17:53
*/

@I18NResourceBundle(baseName = "SOSVirtualFileSystem", defaultLocale = "en")
public class SOSSSH2GanymedImpl extends SOSVfsBaseClass implements JSJobUtilities, ISOSShell, ISOSVFSHandler, ISOSVirtualFileSystem, ISOSConnection, ISOSSession {

  private final String  conClassName  = "SOSSSH2GanymedImpl";

  private Logger      logger      = Logger.getLogger(SOSSSH2GanymedImpl.class);

  private JSJobUtilities objJSJobUtilities = this;
 
  public SOSSSH2GanymedImpl() {
    //
  }
  private ISOSConnectionOptions    objCO          = null;
  private ISOSAuthenticationOptions  objAO          = null;
  private ISOSShellOptions      objSO          = null;

  boolean                isAuthenticated      = false;
  boolean                isConnected        = false;

  /** Line currently being displayed on the shell **/
  protected String          strCurrentLine      = "";

  /** ssh connection object */
  protected Connection        sshConnection      = null;

  /** ssh session object */
  protected Session          sshSession        = null;

  /** Inputstreams for stdout and stderr **/
  protected InputStream        ipsStdOut;
  protected InputStream        ipsStdErr;

  private boolean            flgIsRemoteOSWindows  = false;
  private SFTPv3Client        sftpClient        = null;

  private RemoteConsumer        stdoutConsumer      = null;
  private RemoteConsumer        stderrConsumer      = null;

  /** Output from stdout and stderr **/
  protected StringBuffer        strbStdoutOutput = new StringBuffer();
  protected StringBuffer        strbStderrOutput = new StringBuffer();

  /** timestamp of the last text from stdin or stderr **/
  protected long            lngLastTime        = 0;

  private OutputStream        stdin;
  private OutputStreamWriter      stdinWriter        = null;

  private Integer            intExitStatus        = null;
  private String            strExitSignal        = null;

  private Vector<String>        vecFilesToDelete    = new Vector<String>();

  private Vector<String> getFilesToDelete() {

    if (vecFilesToDelete == null) {
      vecFilesToDelete = new Vector<String>();
    }
    return vecFilesToDelete;
  }

  public ISOSConnection Connect(final String pstrHostName, final int pintPortNumber) throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::Connect";

    try {
      isConnected = false;
      this.setSshConnection(new Connection(pstrHostName, pintPortNumber));

    }
    catch (Exception e) {
      if (this.getSshConnection() != null)
        try {
          this.getSshConnection().close();
          this.setSshConnection(null);
        }
        catch (Exception ex) {
        }
      throw new Exception(e.getMessage());
    }

    return this;
  }

  /**
   *
   * \brief Connect
   *
   * \details
   *
   * \return
   *
   * @return
   * @throws Exception
   */
  public ISOSConnection Connect() throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::Connect";

    try {
      isConnected = false;
      this.setSshConnection(new Connection(objCO.getHost().Value(), objCO.getPort().value()));

      if (objCO.getProxy_host().IsNotEmpty()) {
        HTTPProxyData objProxy = null;
        if (objCO.getProxy_user().IsEmpty()) {
          objProxy = new HTTPProxyData(objCO.getProxy_host().Value(), objCO.getProxy_port().value());
        }
        else {
          objProxy = new HTTPProxyData(objCO.getProxy_host().Value(), objCO.getProxy_port().value(), objCO.getProxy_user().Value(),
              objCO.getProxy_password().Value());
        }
        this.getSshConnection().setProxyData(objProxy);
      }
      this.getSshConnection().connect();
      isConnected = true;

      logger.debug(String.format("connected to %1$s using Port %2$d", objCO.getHost().Value(), objCO.getPort().value()));
    }
    catch (Exception e) {
      try {
        this.setSshConnection(null);
      }
      catch (Exception ex) {
      }
      throw e;
    }

    return this;
  }

  /**
   * Check existence of a file or directory
   *
   * @param psftpClient
   * @param filename
   * @return true, if file exists
   * @throws Exception
   */
  protected boolean sshFileExists(SFTPv3Client psftpClient, String filename) {

    try {
      SFTPv3FileAttributes attributes = psftpClient.stat(filename);

      if (attributes != null) {
        return (attributes.isRegularFile() || attributes.isDirectory());
      }
      else {
        return false;
      }

    }
    catch (Exception e) {
      return false;
    }
  }

  /**
   * Checks if file is a directory
   *
   * @param psftpClient
   * @param filename
   * @return true, if filename is a directory
   */
  protected boolean isDirectory(SFTPv3Client psftpClient, String filename) {
    try {
      return psftpClient.stat(filename).isDirectory();
    }
    catch (Exception e) {
    }
    return false;
  }

  /**
   * Returns the file size of a file
   *
   * @param sftpClient
   * @param filename
   * @return the size of the file
   * @throws Exception
   */
  protected long getFileSize(SFTPv3Client psftpClient, String filename) throws Exception {
    return psftpClient.stat(filename).size.longValue();
  }

  /**
   * Check existence of a file or directory
   *
   * @param sftpClient
   * @param filename
   * @return integer representation of file permissions
   * @throws Exception
   */
  protected int sshFilePermissions(SFTPv3Client psftpClient, String filename) {

    try {
      SFTPv3FileAttributes attributes = psftpClient.stat(filename);

      if (attributes != null) {
        return attributes.permissions.intValue();
      }
      else {
        return 0;
      }

    }
    catch (Exception e) {
      return 0;
    }
  }

  /**
   * normalize / to \ and remove trailing slashes from a path
   *
   * @param path
   * @return normalized path
   * @throws Exception
   */
  @SuppressWarnings("unused")
  private String normalizePath(String path) throws Exception {

    String normalizedPath = path.replaceAll("\\\\", "/");
    while (normalizedPath.endsWith("\\") || normalizedPath.endsWith("/")) {
      normalizedPath = normalizedPath.substring(0, normalizedPath.length() - 1);
    }

    return normalizedPath;
  }

  /**
   * @return Returns the sshConnection.
   */
  protected Connection getSshConnection() {
    return sshConnection;
  }

  protected void setSshConnection(Connection psshConnection) {
    if (psshConnection == null) {
      isConnected = false;
      if (sftpClient != null) {
        if (this.getFilesToDelete() != null) {
          for (String strFileNameToDelete : vecFilesToDelete) {
            try {
              this.deleteFile(strFileNameToDelete);
            }
            catch (Exception e) {
              e.printStackTrace();
            }
          }
          vecFilesToDelete = null;
        }
        sftpClient.close();
        sftpClient = null;
        logger.debug("sftpClient closed.");
      }

      if (stderrConsumer != null) {
        stderrConsumer.end();
        stderrConsumer = null;
        logger.debug("stderrConsumer closed.");
      }

      if (stdoutConsumer != null) {
        stdoutConsumer.end();
        stdoutConsumer = null;
        logger.debug("stdoutConsumer closed.");
      }

      if (sshSession != null) {
        sshSession.close();
        sshSession = null;
        logger.debug("sshSession closed.");

      }

      if (this.sshConnection != null) {
        sshConnection.close();
        logger.debug("sshConnection closed.");
      }
    }
    this.sshConnection = psshConnection;
  }

  /**
   * @return Returns the sshSession.
   */
  public Session getSshSession() {
    return sshSession;
  }

  /**
   * @param sshSession The sshSession to set.
   */
  public void setSshSession(Session psshSession) {
    this.sshSession = psshSession;
  }

  /**
   *
   * \brief createCommandScript
   *
   * \details
   *
   * \return File
   *
   * @param isWindows
   * @return
   * @throws Exception
   */
  public String createScriptFile(final String pstrContent) throws Exception {
    try {
      String commandScript = pstrContent;
//      logger.info("pstrContent = " + pstrContent);
      if (flgIsRemoteOSWindows == false) {
        commandScript = commandScript.replaceAll("(?m)\r", "");
      }
      logger.info("commandScript = " + pstrContent);
      commandScript = objJSJobUtilities.replaceSchedulerVars(flgIsRemoteOSWindows, commandScript);
      String suffix = (flgIsRemoteOSWindows ? ".cmd" : ".sh");
      File resultFile = File.createTempFile("sos", suffix);
      BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(resultFile)));
      out.write(commandScript);
      out.flush();
      out.close();
      resultFile.deleteOnExit();
      putFile(resultFile);

      String strFileName2Return = resultFile.getName();
      if (flgIsRemoteOSWindows == false) {
        strFileName2Return = "./" + strFileName2Return;
      }
      this.getFilesToDelete().add(strFileName2Return);
      return strFileName2Return;
    }
    catch (Exception e) {
      e.printStackTrace();
      throw e;
    }
  }

  @Override
  public ISOSConnection getConnection() {
    return this;
  }

  @Override
  public ISOSSession getSession() {
    return this;
  }

  @Override
  public ISOSConnection Connect(ISOSConnectionOptions pobjConnectionOptions) throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::Connect";
    this.objCO = pobjConnectionOptions;
    if (objCO != null) {
      this.Connect();
    }
    return this;
  }

  @Override
  public void CloseConnection() throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::CloseConnection";

    this.setSshConnection(null);
  }

  /**
   *
   * \brief Authenticate
   *
   * \details
   *
   * \return
   *
   * @param pobjAO
   * @return
   * @throws Exception
   */
  @Override
  public ISOSConnection Authenticate(ISOSAuthenticationOptions pobjAO) throws Exception {

    final String conMethodName = conClassName + "::Authenticate";

    if (pobjAO == null) {
      throw new Exception (conClassName + ": Instance for Options is null but mandatory");
    }
    objAO = pobjAO;

    String strUserID = objAO.getUser().Value();
    String strPW = objAO.getPassword().Value();

    if (objAO.getAuth_method().isPublicKey()) {
      objAO.getAuth_file().CheckMandatory(true);
      File authenticationFile = objAO.getAuth_file().JSFile();
      isAuthenticated = getSshConnection().authenticateWithPublicKey(strUserID, authenticationFile, strPW);
    }
    else
      if (objAO.getAuth_method().isPassword()) {
        isAuthenticated = getSshConnection().authenticateWithPassword(strUserID, strPW);
      }

    if (isAuthenticated == false) {
      throw new Exception(conMethodName + ": " + "authentication failed " + objAO.toString());
    }

    logger.info(String.format("user %1$s logged in", strUserID));
    return this;
  }

  @Override
  public ISOSVFSHandler getHandler() {
    return this;
  }

  /**
   *
   * \brief remoteIsWindowsShell
   *
   * \details
   *
   * \return boolean
   *
   * @return
   */
  public boolean remoteIsWindowsShell() {
    Session objSSHSession = null;
    flgIsRemoteOSWindows = false;

    try {
      // TODO the testcommand should be defined by an option
      String checkShellCommand = "echo %ComSpec%";
      logger.debug("Opening new session...");
      objSSHSession = this.getSshConnection().openSession();
      logger.debug("Executing command " + checkShellCommand);
      objSSHSession.execCommand(checkShellCommand);

      logger.debug("output to stdout for remote command: " + checkShellCommand);
      ipsStdOut = new StreamGobbler(objSSHSession.getStdout());
      ipsStdErr = new StreamGobbler(objSSHSession.getStderr());
      BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(ipsStdOut));
      String stdOut = "";
      while (true) {
        String line = stdoutReader.readLine();
        if (line == null)
          break;
        logger.debug(line);
        stdOut += line;
      }
      logger.debug("output to stderr for remote command: " + checkShellCommand);
      BufferedReader stderrReader = new BufferedReader(new InputStreamReader(ipsStdErr));
      while (true) {
        String line = stderrReader.readLine();
        if (line == null)
          break;
        logger.debug(line);
      }
      // TODO The expected result-string for testing the os should be defined by an option
      if (stdOut.indexOf("cmd.exe") > -1) {
        logger.debug("Remote shell is a Windows shell.");
        flgIsRemoteOSWindows = true;
        return true;
      }
      else {
        logger.debug("Remote shell is a Linux/Unix shell.");
      }
    }
    catch (Exception e) {
      logger.debug("Failed to check if remote system is windows shell: " + e);
    }
    finally {
      if (objSSHSession != null)
        try {
          objSSHSession.close();
        }
        catch (Exception e) {
          logger.debug("Failed to close session: ", e);
        }
    }
    return false;
  }

  /**
   *
   * \brief transferCommandScript
   *
   * \details
   *
   * \return File
   *
   * @param pfleCommandFile
   * @param isWindows
   * @return
   * @throws Exception
   */
  public void putFile(File pfleCommandFile) throws Exception {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::putFile";
    String suffix = (flgIsRemoteOSWindows ? ".cmd" : ".sh");
    String strFileName = pfleCommandFile.getName();

    try {
      boolean exists = true;
      // check if File already exists
      while (exists) {
        try {
          FtpClient().stat(strFileName);
        }
        catch (SFTPException e) {
          logger.debug("Error code when checking file existence: " + e.getServerErrorCode());
          exists = false;
        }
        if (exists) {
          logger.debug("file with that name already exists, trying another name...");
          /**
           * \todo
           * TODO Tempfile-NamePrefix variable via options
           */
          File resultFile = File.createTempFile("sos", suffix);
          resultFile.delete();
          pfleCommandFile.renameTo(resultFile);
          pfleCommandFile = resultFile;
        }
      }

      // set execute permissions for owner
      SFTPv3FileHandle fileHandle = this.getFileHandle(strFileName, new Integer(0700));

      FileInputStream fis = null;
      long offset = 0;
      try {
        fis = new FileInputStream(pfleCommandFile);
        // TODO BufferSize as an Option
        byte[] buffer = new byte[1024];
        while (true) {
          int len = fis.read(buffer, 0, buffer.length);
          if (len <= 0)
            break;
          sftpClient.write(fileHandle, offset, buffer, 0, len);
          offset += len;
        }
        fis.close();
        fis = null;
      }
      catch (Exception e) {
        e.printStackTrace();
        throw e;
      }
      finally {
        if (fis != null)
          try {
            fis.close();
            fis = null;
          }
          catch (Exception ex) {
          }
      }

      logger.debug("canonical path: " + sftpClient.canonicalPath(strFileName));
      sftpClient.closeFile(fileHandle);

      fileHandle = null;
    }
    catch (Exception e) {
      e.printStackTrace();
      throw e;
    }
  }

  public SFTPv3FileHandle getFileHandle(final String pstrFileName, final Integer pintPermissions) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::setFilePermissions";

    SFTPv3FileAttributes attr = new SFTPv3FileAttributes();
    attr.permissions = pintPermissions;
    SFTPv3FileHandle fileHandle = this.FtpClient().createFileTruncate(pstrFileName, attr);
    return fileHandle;
  } // private void setFilePermissions

  public void setFilePermissions(final String pstrFileName, final Integer pintPermissions) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::setFilePermissions";

    SFTPv3FileAttributes attr = new SFTPv3FileAttributes();
    attr.permissions = pintPermissions;
    @SuppressWarnings("unused")
    SFTPv3FileHandle fileHandle = this.FtpClient().createFileTruncate(pstrFileName, attr);
  } // private void setFilePermissions

//  @Override
//  public ISOSVirtualFile getFile(String pstrFileName) throws Exception {
//    // TODO Auto-generated method stub
//    return null;
//  }

  /**
   *
   * \brief deleteCommandScript
   *
   * \details
   *
   * \return void
   *
   * @param pstrCommandFile
   * @throws Exception
   */
  public void deleteFile(String pstrCommandFile) throws Exception {
    try {
      if (isNotEmpty(pstrCommandFile)) {
        this.FtpClient().rm(pstrCommandFile);
        logger.debug("File deleted : " + pstrCommandFile);
      }
    }
    catch (Exception e) {
      logger.error("Failed to delete remote command script: ", e);
    }
  }

  private SFTPv3Client FtpClient() throws Exception {
    if (sftpClient == null) {
      sftpClient = new SFTPv3Client(this.getSshConnection());
    }
    return sftpClient;
  }

  public void CloseSession() throws Exception {

  }

  /**
   *
   * \brief OpenSession
   *
   * \details
   *
   * \return
   *
   * @param pobjShellOptions
   * @return
   * @throws Exception
   */
  public ISOSSession OpenSession(ISOSShellOptions pobjShellOptions) {

    this.objSO = pobjShellOptions;
    if (objSO == null) {
      throw new RuntimeException("no shell-options specified but mandatory");
    }

    try {
      this.setSshSession(this.getSshConnection().openSession());
      if (objSO.getSimulate_shell().value() == true) {
        long loginTimeout = objSO.getSimulate_shell_login_timeout().value();
        String strPromptTrigger = objSO.getSimulate_shell_prompt_trigger().Value();

        logger.debug("Requesting PTY...");
        this.getSshSession().requestDumbPTY();
        logger.debug("Starting shell...");
        this.getSshSession().startShell();
        ipsStdOut = getSshSession().getStdout();
        ipsStdErr = getSshSession().getStderr();
        stdoutConsumer = new RemoteConsumer(getStdOutBuffer(), true, ipsStdOut);
        stderrConsumer = new RemoteConsumer(getStdErrBuffer(), false, ipsStdErr);
        stdoutConsumer.start();
        stderrConsumer.start();
        stdin = getSshSession().getStdin();
        stdinWriter = new OutputStreamWriter(stdin);
        logger.debug("Waiting for login prompt...");
        boolean loggedIn = false;
        while (loggedIn == false) {
          if (lngLastTime > 0) {
            loggedIn = Check4TimeOutOrPrompt(loginTimeout, strPromptTrigger);
          }
        }
      }
      else {
        if (objSO.getIgnore_hangup_signal().value() == false) {
          sshSession.requestPTY("vt100");
        }
      }
    }
    catch (Exception e) {
      throw new RuntimeException(e);
    }

    return this;
  }

  /**
   *
   * \brief Check4TimeOutOrPrompt
   *
   * \details
   *
   * \return boolean
   *
   * @param plngTimeOut
   * @param pstrPromptTrigger
   * @return
   */
  private boolean Check4TimeOutOrPrompt(final long plngTimeOut, final String pstrPromptTrigger) {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::Check4TimeOutOrPrompt";

    long currentTimeMillis = System.currentTimeMillis();
    if (plngTimeOut > 0 && lngLastTime + plngTimeOut < currentTimeMillis) {// kommt nichts mehr
      return true;
    }
    if (pstrPromptTrigger.length() > 0 && strCurrentLine.indexOf(pstrPromptTrigger) != -1) {
      logger.debug("Found login prompt " + pstrPromptTrigger);
      strCurrentLine = "";
      return true;
    }

    return false;
  } // private boolean Check4TimeOutOrPrompt

  /**
   *
   * \brief ExecuteCommand
   *
   * \details
   * A single command is executed by this method.
   * a command can be executed in a "simulated"-shell or as a single ssh-session.
   *
   * if it is executed as a single ssh-session the method must wait until the
   * ssh-server was sent an EOF signal, because to get the exit-code and exit-status of
   * the command is not poossible.
   *
   * @param pstrCmd
   * @throws Exception
   */
  public void ExecuteCommand(final String pstrCmd) throws Exception {

    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::ExecuteCommand";

    intExitStatus = null;
    strExitSignal = null;
    String strCmd = pstrCmd;

    if (objSO.getSimulate_shell().value() == true) {
      long lngInactivityTimeout = objSO.getSimulate_shell_inactivity_timeout().value();
      String strPromptTrigger = objSO.getSimulate_shell_prompt_trigger().Value();

      stdinWriter.write(strCmd + "\n");
      stdinWriter.flush();
      boolean prompt = false;
      while (prompt == false) {
        prompt = Check4TimeOutOrPrompt(lngInactivityTimeout, strPromptTrigger);
      }
      strCurrentLine = "";
      logger.debug("output to stdout for remote command: " + strCmd);
      logger.debug(getStdOutBuffer().toString());
      strbStdoutOutput = new StringBuffer();
    }
    else {
      if (flgIsRemoteOSWindows == false) {
        strCmd = "echo $$ && " + strCmd;
      }

      this.getSshSession().execCommand(strCmd);

      logger.info("output to stdout for remote command: " + strCmd);

      ipsStdOut = new StreamGobbler(this.getSshSession().getStdout());
      ipsStdErr = new StreamGobbler(this.getSshSession().getStderr());
      BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(ipsStdOut));
      strbStdoutOutput = new StringBuffer();
      while (true) {
        String line = stdoutReader.readLine();
        if (line == null)
          break;
        logger.info(line);
        getStdOutBuffer().append(line + "\n");
      }

      logger.info("output to stderr for remote command: " + strCmd);
      BufferedReader stderrReader = new BufferedReader(new InputStreamReader(ipsStdErr));
      strbStderrOutput = new StringBuffer();
      while (true) {
        String line = stderrReader.readLine();
        if (line == null)
          break;
        logger.info(line);
        strbStderrOutput.append(line + "\n");
      }
      /**
       * give the command (e.g. session) some time to end.
       * otherwise it is not possible to get valid exit-infos.
       */
      // TODO waitForCondition as an Option
      @SuppressWarnings("unused")
      int res = getSshSession().waitForCondition(ChannelCondition.EOF, 30 * 1000);

    } //     if (objSO.getSimulate_shell().value() == true)

    String strWhatSignal = "";
    try {
      strWhatSignal = "exit status";
      intExitStatus = this.getSshSession().getExitStatus();
      strWhatSignal = "exit signal";
      strExitSignal = this.getSshSession().getExitSignal();
    }
    catch (Exception e) {
      logger.info(String.format("could not retrieve %1$s, possibly not supported by remote ssh server", strWhatSignal));
    }
  }

  @Override
  public Integer getExitCode() {
    return intExitStatus;
  }

  @Override
  public String getExitSignal() {
    return strExitSignal;
  }

//  @Override
  public StringBuffer getStdErrBuffer() throws Exception {
    if (strbStderrOutput == null) {
      strbStderrOutput = new StringBuffer();
    }
    return strbStderrOutput;
  }

//  @Override
  public StringBuffer getStdOutBuffer() throws Exception {
    if (strbStdoutOutput == null) {
      strbStdoutOutput = new StringBuffer();
    }
    return strbStdoutOutput;
  }

  /**
   * This thread consumes output from the remote server puts it into fields of
   * the main class
   */
  class RemoteConsumer extends Thread {
    private StringBuffer  sbuf;
    private boolean      writeCurrentline  = false;
    private InputStream    stream;
    boolean          end          = false;

    RemoteConsumer(StringBuffer buffer, boolean writeCurr, InputStream str) {
      if (buffer == null) {
        buffer = new StringBuffer();
      }
      this.sbuf = buffer;
      this.writeCurrentline = true;
      this.stream = str;
    }

    /**
     *
     * \brief addText
     *
     * \details
     *
     * \return void
     *
     * @param data
     * @param len
     */
    private void addText(byte[] data, int len) {
      lngLastTime = System.currentTimeMillis();
      String outstring = new String(data).substring(0, len);
      sbuf.append(outstring);
      if (writeCurrentline) {
        int newlineIndex = outstring.indexOf("\n");
        if (newlineIndex > -1) {
          String stringAfterNewline = outstring.substring(newlineIndex);
          strCurrentLine = stringAfterNewline;
        }
        else {
          strCurrentLine += outstring;
        }
      }
    }

    /**
     *
     * \brief run
     *
     * \details
     *
     * \return
     *
     */
    public void run() {
      byte[] buff = new byte[64];

      try {
        while (!end) {
          buff = new byte[8];
          int len = stream.read(buff);
          if (len == -1)
            return;
          addText(buff, len);
        }
      }
      catch (Exception e) {
      }
    }

    /**
     *
     * \brief end
     *
     * \details
     *
     * \return void
     *
     */
    public synchronized void end() {
      end = true;
    }
  } // RemoteConsumer

//  @Override
//  public boolean FileExists(String filename) throws Exception {
//
//    return this.sshFileExists(this.FtpClient(), filename);
//  }
//
//  @Override
//  public Integer getFilePermissions(final String pstrFileName) throws Exception {
//    return this.sshFilePermissions(this.FtpClient(), pstrFileName);
//  }
//
//  @Override
//  public long getFileSize(final String pstrFileName) throws Exception {
//
//    return this.getFileSize(this.FtpClient(), pstrFileName);
//  }
//
//  @Override
//  public boolean isDirectory(final String pstrFileName) throws Exception {
//
//    return this.isDirectory(this.FtpClient(), pstrFileName);
//  }
//
//  @Override
//  public void putFile(String pstrFileName) throws Exception {
//    this.putFile(new File(pstrFileName));
//  }

  @Override
  public SOSFileList dir(SOSFolderName pobjFolderName) {
    // TODO Auto-generated method stub
    return null;
  }

//  @Override
//  public SOSFileList dir() {
//    // TODO Auto-generated method stub
//    return null;
//  }

  @Override
  public ISOSVirtualFolder mkdir(SOSFolderName pobjFolderName) throws IOException {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public boolean rmdir(SOSFolderName pobjFolderName) throws IOException {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public String myReplaceAll(String source, String what, String replacement) {
    return source;
  }

  @Override
  public String replaceSchedulerVars(boolean isWindows, String pstrString2Modify) {
    logger.debug("replaceSchedulerVars as Dummy-call executed. No Instance of JobUtilites specified.");
    return pstrString2Modify;
  }

  @Override
  public void setJSParam(String pstrKey, String pstrValue) {
   
  }

//  @Override
//  public void setParameters(Variable_set pVariableSet) {
//   
//  }
 
  @Override
  public void setJSJobUtilites (JSJobUtilities pobjJSJobUtilities) {
    if (pobjJSJobUtilities == null) {
      objJSJobUtilities = this;
    }
    else {
      objJSJobUtilities = pobjJSJobUtilities;
    }
    logger.debug("objJSJobUtilities = " + objJSJobUtilities.getClass().getName());

  }

  @Override
  public void setJSParam(String pstrKey, StringBuffer pstrValue) {
    setJSParam(pstrKey, pstrValue.toString());
   
  }

  @Override
  public StringBuffer getStdErr() throws Exception {
    return getStdErrBuffer();
  }

  @Override
  public StringBuffer getStdOut() throws Exception {
    return getStdOutBuffer();
  }

//  @Override
//  public ISOSVirtualFile TransferMode(SOSOptionTransferMode pobjFileTransferMode) throws Exception {
//    // TODO Auto-generated method stub
//    return null;
//  }

  @Override
  public SOSFileList dir(String pathname, int flag) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public ISOSConnection Connect(SOSConnection2OptionsAlternate pobjConnectionOptions) throws Exception {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public String getCurrentNodeName() {
    return "";
  }
 

}
TOP

Related Classes of com.sos.VirtualFileSystem.SSH.SOSSSH2GanymedImpl$RemoteConsumer

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.