Package com.sos.VirtualFileSystem.SSH

Source Code of com.sos.VirtualFileSystem.SSH.SOSSSH2TriLeadImpl$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 sos.spooler.Variable_set;

import com.sos.JSHelper.Basics.JSJobUtilities;
import com.sos.JSHelper.Exceptions.JobSchedulerException;
import com.sos.VirtualFileSystem.DataElements.SOSFileList;
import com.sos.VirtualFileSystem.DataElements.SOSFolderName;
import com.sos.VirtualFileSystem.FTP.SOSVfsFtp;
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.Msg;
import com.sos.i18n.Msg.BundleBaseName;
import com.sos.i18n.annotation.I18NResourceBundle;
import com.trilead.ssh2.ChannelCondition;
import com.trilead.ssh2.Connection;
import com.trilead.ssh2.HTTPProxyData;
import com.trilead.ssh2.SFTPException;
import com.trilead.ssh2.SFTPv3Client;
import com.trilead.ssh2.SFTPv3FileAttributes;
import com.trilead.ssh2.SFTPv3FileHandle;
import com.trilead.ssh2.Session;
import com.trilead.ssh2.StreamGobbler;

/**
* \class SOSSSH2SuperClass
*
* \brief SOSSSH2SuperClass -
* \details
*
* \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: SOSSSH2TriLeadImpl.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 SOSSSH2TriLeadImpl extends SOSVfsBaseClass implements ISOSShell, ISOSVFSHandler, ISOSVirtualFileSystem, ISOSConnection, ISOSSession {

  private final String  conClassName  = "SOSSSH2TriLeadImpl";

  private Logger      logger      = Logger.getLogger(SOSSSH2TriLeadImpl.class);
  final private String  strEndOfLine  = System.getProperty("line.separator");

  protected Msg      objMsg      = new Msg(new BundleBaseName(this.getClass().getAnnotation(I18NResourceBundle.class).baseName()));

  public SOSSSH2TriLeadImpl() {
    //
  }
  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;
  protected StringBuffer        strbStderrOutput;

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

  private OutputStream        stdin;
  private OutputStreamWriter      stdinWriter        = null;

  private Integer            exitStatus        = null;
  private String            exitSignal        = 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;
      String strHostName = objCO.getHost().Value();
      int intPortNo = objCO.getPort().value();
      this.setSshConnection(new Connection(strHostName, intPortNo));

      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(objMsg.getMsg(SOSVfsFtp.SOSVfs_D_0102), strHostName, intPortNo));
    }
    catch (Exception e) {
      try {
        this.setSshConnection(null);
      }
      catch (Exception ex) {
      }
      throw e;
    }

    return this;
  }

  /**
   * Check existence of a file or directory
   *
   * @param sftpClient
   * @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 sftpClient
   * @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 pstrPathName
   * @return normalized path
   * @throws Exception
   */
  @SuppressWarnings("unused")
  private String normalizePath(String pstrPathName) throws Exception {

    String normalizedPath = pstrPathName.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) {
    String conClosedMsg = "'%1$s' closed";

    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(String.format(conClosedMsg, "sftpClient"));
      }

      if (stderrConsumer != null) {
        stderrConsumer.end();
        stderrConsumer = null;
        logger.debug(String.format(conClosedMsg, "stderrConsumer"));
      }

      if (stdoutConsumer != null) {
        stdoutConsumer.end();
        stdoutConsumer = null;
        logger.debug(String.format(conClosedMsg, "stdoutConsumer"));
      }

      if (sshSession != null) {
        sshSession.close();
        sshSession = null;
        logger.debug(String.format(conClosedMsg, "sshSession"));
      }

      if (this.sshConnection != null) {
        sshConnection.close();
        logger.debug(String.format(conClosedMsg, "sshConnection"));
      }
    }
    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;
  }

  /**
   * \todo
   * TODO Variable_set mu� hier raus und in den Adapter f�r den JobScheduler
   *
   */
  private Variable_set  params  = null;

  /**
   *
   * \brief setJSParam
   *
   * \details
   *
   * \return SOSSSH2SuperClass
   *
   * @param pstrKey
   * @param pstrValue
   * @return
   */
  public SOSSSH2TriLeadImpl setJSParam(final String pstrKey, final String pstrValue) {

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

    if (params != null) {
      params.set_var(pstrKey, pstrValue);
    }

    return this;
  } // private SOSSSH2SuperClass setJSParam

  public SOSSSH2TriLeadImpl setParameters(Variable_set pVariableSet) {

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

    this.params = pVariableSet;

    return this;
  } // private void setParameters

  /**
   *
   * \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);
      // TODO solve via callback
      replaceSchedulerVars(flgIsRemoteOSWindows, commandScript);
      File resultFile = File.createTempFile("sos-sshscript", getScriptFileNameSuffix());
      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;
    }
  }

  /**
   *
   * \brief replaceSchedulerVars
   *
   * \details
   *
   * \return void
   *
   * @param isWindows
   */
  protected String replaceSchedulerVars(boolean isWindows, final String pstrString2Modify) {
    String strTemp = pstrString2Modify;
    if (params != null) {
      logger.debug("Replacing task and order parameters...");
      String[] paramNames = params.names().split(";");
      for (int i = 0; i < paramNames.length; i++) {
        String name = paramNames[i];
        SignalDebug("Replacing parameter " + name);
        String regex = "(?i)";
        /**
         * \todo
         * TODO os-abh�ngigkeit besser herstellen als hier gemacht
         *
         * TODO Es ist doch eigentlich viel besser, wenn die Variablen
         * (zus�tzlich) als Environment-variablen gesetzt werden.
         */
        if (isWindows) {
          regex += "%SCHEDULER_PARAM_" + name + "%";
        }
        else {
          regex += "\\$\\{?SCHEDULER_PARAM_" + name + "\\}?";
        }
        strTemp = myReplaceAll(strTemp, regex, params.value(name));
      }
    }
    return strTemp;
  }

  /**
   *
   * \brief myReplaceAll
   *
   * \details
   *
   * \return String
   *
   * @param source
   * @param what
   * @param replacement
   * @return
   */
  public String myReplaceAll(String source, String what, String replacement) {

    String newReplacement = replacement.replaceAll("\\$", "\\\\\\$");
    return source.replaceAll("(?m)" + what, newReplacement);
  }

  @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";

    objAO = pobjAO;

    if (objAO.getAuth_method().isPublicKey()) {
      /**
       * \todo
       * TODO File-Handling in der Option-Klasse abhandeln. Return vom Type JSFile einbauen
       */
      File authenticationFile = new File(objAO.getAuth_file().Value());
      if (authenticationFile.exists() == false)
        throw new JobSchedulerException("SOS-SSH-E-010: authentication file does not exist: " + authenticationFile.getCanonicalPath());
      if (authenticationFile.canRead() == false)
        throw new JobSchedulerException("SOS-SSH-E-020: authentication file not accessible: " + authenticationFile.getCanonicalPath());

      isAuthenticated = this.getSshConnection().authenticateWithPublicKey(objAO.getUser().Value(), authenticationFile, objAO.getPassword().Value());
    }
    else
      if (objAO.getAuth_method().isPassword()) {
        isAuthenticated = getSshConnection().authenticateWithPassword(objAO.getUser().Value(), objAO.getPassword().Value());
      }

    if (isAuthenticated == false) {
      throw new JobSchedulerException(String.format("SOS-SSH-E-030: %1$s:  authentication failed %2$s", conMethodName, objAO.toString()));
    }

    logger.info(String.format("SOS-SSH-I-040: user %1$s logged in", objAO.getUser().Value()));
    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;
      }
    }
    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;
  }

  private String getScriptFileNameSuffix() {

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

    String strSuffix = (flgIsRemoteOSWindows ? ".cmd" : ".sh");

    return strSuffix;
  } // private String getScriptFileNameSuffix

  /**
   *
   * \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 = getScriptFileNameSuffix();
    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 fleResultFile = File.createTempFile("sos", suffix);
          fleResultFile.delete();
          pfleCommandFile.renameTo(fleResultFile);
          pfleCommandFile = fleResultFile;
        }
      }

      // 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;
    }
  }

  /**
   *
   * \brief getFileHandle
   *
   * \details
   *
   * \return SFTPv3FileHandle
   *
   * @param pstrFileName
   * @param pintPermissions
   * @return
   * @throws Exception
   */
  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

  /**
   *
   * \brief setFilePermissions
   *
   * \details
   *
   * \return void
   *
   * @param pstrFileName
   * @param pintPermissions
   * @throws Exception
   */
  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

  /**
   *
   * \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;
  }

  /**
   *
   * \brief CloseSession
   *
   * \details
   *
   * \return
   *
   * @throws Exception
   */
  public void CloseSession() throws Exception {

  }

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

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

    long loginTimeout = objSO.getSimulate_shell_login_timeout().value();
    String strPromptTrigger = objSO.getSimulate_shell_prompt_trigger().Value();

    this.setSshSession(this.getSshConnection().openSession());
    if (objSO.getSimulate_shell().value() == true) {
      logger.debug("Requesting PTY...");
      this.getSshSession().requestDumbPTY();
      logger.debug("Starting shell...");
      this.getSshSession().startShell();
      ipsStdOut = getSshSession().getStdout();
      ipsStdErr = getSshSession().getStderr();
      stdoutConsumer = new RemoteConsumer(strbStdoutOutput, true, ipsStdOut);
      stderrConsumer = new RemoteConsumer(strbStderrOutput, false, ipsStdErr);
      stdoutConsumer.start();
      stderrConsumer.start();
      stdin = getSshSession().getStdin();
      stdinWriter = new OutputStreamWriter(stdin);
      logger.debug("Waiting for login prompt...");
      boolean loggedIn = false;
      while (!loggedIn) {
        if (lngLastTime > 0) {
          loggedIn = Check4TimeOutOrPrompt(loginTimeout, strPromptTrigger);
        }
      }
    }
    else {
      if (objSO.getIgnore_hangup_signal().value() == false) {
        // TODO Terminaltype must be an option
        sshSession.requestPTY("vt100");
      }
    }

    return this;
  }

  private boolean Check4TimeOutOrPrompt(final long plngLoginTimeOut, final String pstrPromptTrigger) {

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

    long now = System.currentTimeMillis();
    if (plngLoginTimeOut > 0 && lngLastTime + plngLoginTimeOut < now) {// 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
   * Executes a command which is given as parameter.
   * \return
   *
   * @param pstrCmd
   * @throws Exception
   */
  public void ExecuteCommand(final String pstrCmd) throws Exception {

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

    exitStatus = null;
    exitSignal = null;
    String strCmd = pstrCmd;

    long loginTimeout = objSO.getSimulate_shell_login_timeout().value();
    String strPromptTrigger = objSO.getSimulate_shell_prompt_trigger().Value();

    if (objSO.getSimulate_shell().value() == true) {
      stdinWriter.write(strCmd + strEndOfLine);
      stdinWriter.flush();
      boolean prompt = false;
      while (!prompt) {
        prompt = Check4TimeOutOrPrompt(loginTimeout, strPromptTrigger);
      }
      strCurrentLine = "";
      logger.debug("output to stdout for remote command: " + strCmd);
      logger.debug(strbStdoutOutput.toString());
      strbStdoutOutput = new StringBuffer();
    }
    else {
      if (flgIsRemoteOSWindows == false) {
        strCmd = "echo $$ && " + strCmd;
      }

      this.getSshSession().execCommand(strCmd);

      logger.debug("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;
        SignalInfo(line);
        // logger.debug(line);
        strbStdoutOutput.append(line + strEndOfLine);

      }

      logger.debug("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.debug(line);
        strbStderrOutput.append(line + strEndOfLine);
      }
    }

    // give the session some time to end
    // TODO waitForCondition as an Option
    @SuppressWarnings("unused")
    int res = getSshSession().waitForCondition(ChannelCondition.EOF, 30 * 1000);

    try {
      exitStatus = this.getSshSession().getExitStatus();
    }
    catch (Exception e) {
      logger.info("could not retrieve exit status, possibly not supported by remote ssh server");
    }

    try {
      exitSignal = this.getSshSession().getExitSignal();
    }
    catch (Exception e) {
      logger.info("could not retrieve exit signal, possibly not supported by remote ssh server");
    }

  }

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

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

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

  @Override
  public StringBuffer getStdOut() throws Exception {
    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) {
      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(strEndOfLine);
        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 SOSFileList dir(SOSFolderName pobjFolderName) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public SOSFileList dir(String pathname, int flag) {
    // 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 void setJSJobUtilites(JSJobUtilities pobjJSJobUtilities) {
    // TODO Auto-generated method stub

  }

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

Related Classes of com.sos.VirtualFileSystem.SSH.SOSSSH2TriLeadImpl$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.