Package com.sos.VirtualFileSystem.FTP

Source Code of com.sos.VirtualFileSystem.FTP.SOSVfsFtp

/********************************************************* 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.FTP;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ProtocolCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

import com.sos.JSHelper.Basics.JSJobUtilities;
import com.sos.JSHelper.Exceptions.JobSchedulerException;
import com.sos.JSHelper.Options.SOSOptionHostName;
import com.sos.JSHelper.Options.SOSOptionPortNumber;
import com.sos.JSHelper.Options.SOSOptionTransferMode;
import com.sos.VirtualFileSystem.DataElements.SOSFileList;
import com.sos.VirtualFileSystem.DataElements.SOSFileListEntry;
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.ISOSShellOptions;
import com.sos.VirtualFileSystem.Interfaces.ISOSVFSHandler;
import com.sos.VirtualFileSystem.Interfaces.ISOSVfsFileTransfer;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFile;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFileSystem;
import com.sos.VirtualFileSystem.Interfaces.ISOSVirtualFolder;
import com.sos.VirtualFileSystem.Options.SOSConnection2OptionsAlternate;
import com.sos.VirtualFileSystem.Options.SOSConnection2OptionsSuperClass;
import com.sos.VirtualFileSystem.common.SOSVfsBaseClass;
import com.sos.i18n.Msg;
import com.sos.i18n.Msg.BundleBaseName;
import com.sos.i18n.annotation.I18NMessage;
import com.sos.i18n.annotation.I18NMessages;
import com.sos.i18n.annotation.I18NResourceBundle;

@I18NResourceBundle(baseName = "SOSVirtualFileSystem", defaultLocale = "en")
public class SOSVfsFtp extends SOSVfsBaseClass implements ISOSVfsFileTransfer, ISOSVFSHandler, ISOSVirtualFileSystem, ISOSConnection {
  private final String          conClassName      = "SOSVfsFtp";
  private Logger              logger          = Logger.getLogger(SOSVfsFtp.class);

  private SOSFtpServerReply        objFTPReply        = null;

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

  @I18NMessages(value = { @I18NMessage("Disconnected from host '%1$s' on port '%2$d'."), //
      @I18NMessage(value = "Disconnected from host '%1$s' on port '%2$d'.", //
      locale = "en_UK", //
      explanation = "Disconnected from host '%1$s' on port '%2$d'." //
      ), //
      @I18NMessage(value = "Verbindung zum Rechner '%1$s' �ber Port-Nummer '%2$d' beendet.", //
      locale = "de", //
      explanation = "Disconnected from host '%1$s' on port '%2$d'." //
      ), //
      @I18NMessage(value = "Disconnected from host '%1$s' on port '%2$d'.", locale = "es", //
      explanation = "Disconnected from host '%1$s' on port '%2$d'." //
      ), //
      @I18NMessage(value = "Disconnected from host '%1$s' on port '%2$d'.", locale = "fr", //
      explanation = "Disconnected from host '%1$s' on port '%2$d'." //
      ), //
      @I18NMessage(value = "Disconnected from host '%1$s' on port '%2$d'.", locale = "it", //
      explanation = "Disconnected from host '%1$s' on port '%2$d'." //
      ) //
  }, msgnum = "SOSVfs-I-0109", msgurl = "SOSVfs-I-0109")
  /*!
   * \var SOSVfs_I_0109
   * \brief Disconnected from host '%1$s' on port '%2$d'.
   */
  public static final String        SOSVfs_I_0109      = "SOSVfs_I_0109";

  @I18NMessages(value = { @I18NMessage("Connection to host '%1$s' on port '%2$d' not possible, error is '%3$s'"), //
      @I18NMessage(value = "Connection to host '%1$s' on port '%2$d' not possible, error is '%3$s'", //
      locale = "en_UK", //
      explanation = "Connection to host '%1$s' on port '%2$d' not possible" //
      ), //
      @I18NMessage(value = "Verbindung zum Rechner '%1$s' �ber Port-Nummer '%2$d' nicht m�glich. Fehler: %3$s", //
      locale = "de", //
      explanation = "Connection to host '%1$s' on port '%2$d' not possible, error is '%3$s'" //
      ), //
      @I18NMessage(value = "Connection to host '%1$s' on port '%2$d' not possible, error is '%3$s'", locale = "es", //
      explanation = "Connection to host '%1$s' on port '%2$d' not possible" //
      ), //
      @I18NMessage(value = "Connection to host '%1$s' on port '%2$d' not possible, error is '%3$s'", locale = "fr", //
      explanation = "Connection to host '%1$s' on port '%2$d' not possible" //
      ), //
      @I18NMessage(value = "Connection to host '%1$s' on port '%2$d' not possible, error is '%3$s'", locale = "it", //
      explanation = "Connection to host '%1$s' on port '%2$d' not possible" //
      ) //
  }, msgnum = "SOSVfs-E-0107", msgurl = "SOSVfs-E-0107")
  /*!
   * \var SOSVfs_E_0107
   * \brief Connection to host '%1$s' on port '%2$d' not possible
   */
  public static final String        SOSVfs_E_0107      = "SOSVfs_E_0107";

  @I18NMessages(value = { @I18NMessage("..server reply [%1$s] (with param '%2$s') is '%3$s'."), //
      @I18NMessage(value = "..server reply [%1$s] (with param '%2$s') is '%3$s'.", //
      locale = "en_UK", //
      explanation = "..server reply [%1$s] (with param '%2$s') is '%3$s'." //
      ), //
      @I18NMessage(value = "..Antwort des Rechners nach Kommando '%1$s' (mit Parameter '%2$s') lautet: '%3$s'.", //
      locale = "de", //
      explanation = "..server reply [%1$s] (with param '%2$s') is '%3$s'." //
      ), //
      @I18NMessage(value = "..server reply [%1$s] (with param '%2$s') is '%3$s'.", locale = "es", //
      explanation = "..server reply [%1$s] (with param '%2$s') is '%3$s'." //
      ), //
      @I18NMessage(value = "..server reply [%1$s] (with param '%2$s') is '%3$s'.", locale = "fr", //
      explanation = "..server reply [%1$s] (with param '%2$s') is '%3$s'." //
      ), //
      @I18NMessage(value = "..server reply [%1$s] (with param '%2$s') is '%3$s'.", locale = "it", //
      explanation = "..server reply [%1$s] (with param '%2$s') is '%3$s'." //
      ) //
  }, msgnum = "SOSVfs-E-0106", msgurl = "SOSVfs-E-0106")
  /*!
   * \var SOSVfs_D_0106
   * \brief ..server reply [%1$s] (with param '%2$s') is '%3$s'.
   */
  public static final String        SOSVfs_E_0106      = "SOSVfs_E_0106";

  @I18NMessages(value = {
      @I18NMessage("processing aborted, '%1$s' returns an exception, see stacktrace on stderr"), //
      @I18NMessage(value = "processing aborted, '%1$s' returns an exception, see stacktrace on stderr", //
      locale = "en_UK", //
      explanation = "%1$s returns an exception, see stacktrace on stderr" //
      ), //
      @I18NMessage(value = "Verarbeitung wird abgebrochen, '%1$s' verursacht einen Ausnahmefehler (exception) und beendet sich. Weitere Informationen im StackTrace.", //
      locale = "de", //
      explanation = "%1$s returns an exception" //
      ), //
      @I18NMessage(value = "%1$s returns an exception, see stacktrace on stderr", locale = "es", //
      explanation = "%1$s returns an exception" //
      ), //
      @I18NMessage(value = "%1$s returns an exception, see stacktrace on stderr", locale = "fr", //
      explanation = "%1$s returns an exception" //
      ), //
      @I18NMessage(value = "%1$s returns an exception, see stacktrace on stderr", locale = "it", //
      explanation = "%1$s returns an exception" //
      ) //
  }, msgnum = "SOSVfs-E-0105", msgurl = "SOSVfs-E-0105")
  /*!
   * \var SOSVfs_E_0105
   * \brief %1$s returns an exception
   */
  public static final String        SOSVfs_E_0105      = "SOSVfs_E_0105";

  @I18NMessages(value = { @I18NMessage("Try to connect to host '%1$s' at Port '%2$d'."), //
      @I18NMessage(value = "Try to connect to host '%1$s' at Port '%2$d'.", locale = "en_UK", //
      explanation = "Try to connect to host '%1$s' at Port '%2$d'." //
      ), //
      @I18NMessage(value = "Starte einen Verbindungsaufbau mit Rechner '%1$s' �ber Port-Nummer '%2$d'.", locale = "de", //
      explanation = "Try to connect to host '%1$s' at Port '%2$d'." //
      ) //
  }, msgnum = "SOSVfs-D-0101", msgurl = "SOSVfs-D-0101")
  /*!
   * \var SOSVfs-I-0101
   * \brief Try to connect to host '%1$s' at Port '%2$d'.
   */
  public static final String        SOSVfs_D_0101      = "SOSVfs-D-0101";

  @I18NMessages(value = { @I18NMessage("Connected to '%1$s' at Port '%2$d'."), //
      @I18NMessage(value = "Connected to '%1$s' at Port '%2$d'.", locale = "en_UK", //
      explanation = "Connected to '%1$s' at Port '%2$d'." //
      ), //
      @I18NMessage(value = "Verbunden mit Rechner '%1$s' �ber Port-Nummer '%2$d'.", locale = "de", //
      explanation = "Verbunden mit Rechner '%1$s' �ber Port-Nummer '%2$d'." //
      ) //
  }, msgnum = "SOSVfs-D-0102", msgurl = "SOSVfs-D-0102")
  /*!
   * \var SOSVfs_D_0102
   * \brief Connected to '%1$s' at Port '%2$d'.
   */
  public static final String        SOSVfs_D_0102      = "SOSVfs_D_0102";

  @I18NMessages(value = { @I18NMessage("host '%1$s' at Port '%2$d' is already connected."), //
      @I18NMessage(value = "host '%1$s' at Port '%2$d' is already connected.", locale = "en_UK", //
      explanation = "host '%1$s' at Port '%2$d' is already connected." //
      ), //
      @I18NMessage(value = "Der Rechner '%1$s' an Port-Nummer '%2$d' ist bereits verbunden.", locale = "de", //
      explanation = "Der Rechner '%1$s' an Port-Nummer '%2$d' ist bereits verbunden." //
      ) //
  }, msgnum = "SOSVfs-D-0103", msgurl = "SOSVfs-D-0103")
  /*!
   * \var SOSVfs_D_0103
   * \brief host '%1$s' at Port '%2$d' is already connected.
   */
  public static final String        SOSVfs_D_0103      = "SOSVfs_D_0103";

  private Vector<String>          vecDirectoryListing    = null;
  private FTPClient            objFTPClient      = null;
  @Deprecated
  private ISOSConnectionOptions      objConnectionOptions  = null;
  private SOSConnection2OptionsAlternate  objConnection2Options  = null;
  private String              strCurrentPath      = EMPTY_STRING;
  private String              strReply        = EMPTY_STRING;
  private ProtocolCommandListener      listener        = null;
  private String              host          = EMPTY_STRING;
  private int                port          = 0;
  private String              gstrUser        = EMPTY_STRING;
  private SOSOptionHostName        objHost          = null;
  private SOSOptionPortNumber        objPort          = null;

  protected boolean            utf8Supported      = false;
  protected boolean            restSupported      = false;
  protected boolean            mlsdSupported      = false;
  protected boolean            modezSupported      = false;
  protected boolean            dataChannelEncrypted  = false;

  /**
   *
   * \brief SOSVfsFtp
   *
   * \details
   *
   */
  public SOSVfsFtp() {
  }

  private String HostID(String pstrText) {

    return "(" + gstrUser + "@" + host + ":" + port + ") " + pstrText;
  }

  /*
   * @param host the remote ftp server
   * @param port the port number of the remote server
   * @throws java.net.SocketException
   * @throws java.io.IOException
   * @throws java.net.UnknownHostException
   * @see org.apache.commons.net.SocketClient#connect(java.lang.String, int)
   */
  public void connect(String phost, int pport) {
    final String conMethodName = conClassName + "::connect";

    try {
      host = phost;
      port = pport;
      String strM = String.format(objMsg.getMsg(SOSVfs_D_0101), host, port);
      logger.debug(strM);
      if (isConnected() == false) {
        Client().connect(host, port);
        logger.debug(String.format(objMsg.getMsg(SOSVfs_D_0102), host, port));
        LogReply();
      }
      else {
        logger.warn(String.format(objMsg.getMsg(SOSVfs_D_0102), host, port));
      }
    }
    catch (Exception e) {
      e.printStackTrace(System.err);
      // RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
  }

  /*
   * @param host the remote ftp server
   * @param port the port number of the remote server
   * @throws java.net.SocketException
   * @throws java.io.IOException
   * @throws java.net.UnknownHostException
   * @see org.apache.commons.net.SocketClient#connect(java.lang.String)
   */
  @SuppressWarnings("unused")
  private void connect(String hostname) throws SocketException, IOException, UnknownHostException {
    if (isConnected() == false)
      Client().connect(hostname);
  }

  /**
   * Creates a new subdirectory on the FTP server in the current directory .
   * @param pathname The pathname of the directory to create.
   * @return True if successfully completed, false if not.
   * @throws java.lang.IOException
   */
  public void mkdir(String pathname) {
    final String conMethodName = conClassName + "::mkdir";

    try {
      Client().makeDirectory(pathname);
      logger.debug(HostID(String.format(objMsg.getMsg(SOSVfs_E_0106), conMethodName, pathname, getReplyString())));
    }
    catch (IOException e) {
      String strM = HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName));
      e.printStackTrace(System.err);
      throw new RuntimeException(strM, e);
    }
  }

  /**
   * Removes a directory on the FTP server (if empty).
   * @param pathname The pathname of the directory to remove.
   * @return True if successfully completed, false if not.
   * @throws java.lang.IOException
   */
  public void rmdir(String pathname) throws IOException {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::rmdir";

    Client().removeDirectory(pathname);
    logger.debug(HostID(String.format(objMsg.getMsg(SOSVfs_E_0106), conMethodName, pathname, getReplyString())));
  }

  /**
   * turn passive transfer mode on.
   *
   * @return The reply code received from the server.
   */
  public int passive() {
    final String conMethodName = conClassName + "::passive";

    try {
      int i = Client().pasv();
      if (isPositiveCommandCompletion() == false) {
        throw new RuntimeException(HostID(String.format(objMsg.getMsg(SOSVfs_E_0106), conMethodName, "", getReplyString())));
      }
      else {
        this.logger.debug(HostID(String.format(objMsg.getMsg(SOSVfs_E_0106), conMethodName, "", getReplyString())));
      }
      return i;
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return 0;
  }

  /**
   * return a listing of the contents of a directory in short format on
   * the remote machine
   * @param pathname on remote machine
   * @return a listing of the contents of a directory on the remote machine
   *
   * @exception Exception
   * @see #dir()
   */
  public Vector<String> nList(String pathname) {
    return getFilenames(pathname);
  } // nList

  private Vector<String> getFilenames(String pathname) {
    return getFilenames(pathname, false);
  }

  /**
   * return a listing of the contents of a directory in short format on
   * the remote machine (without subdirectory)
   *
   * @param pathname on remote machine
   * @return a listing of the contents of a directory on the remote machine
   * @throws IOException
   *
   * @exception Exception
   * @see #dir()
   */
  private Vector<String> getFilenames(String pstrPathName, boolean flgRecurseSubFolders) {
    String strCurrentDirectory = null;
    // TODO vecDirectoryListing = null; pr�fen, ob notwendig
    vecDirectoryListing = null;
    if (vecDirectoryListing == null) {
      vecDirectoryListing = new Vector<String>();
      String[] fileList = null;
      strCurrentDirectory = DoPWD();
      String lstrPathName = pstrPathName.trim();
      if (lstrPathName.length() <= 0) {
        lstrPathName = ".";
      }
      if (lstrPathName.equals(".")) {
        lstrPathName = strCurrentDirectory;
      }
      if (1 == 1) {
        try {
          fileList = listNames(lstrPathName);
          // fileList = listNames(pstrPathName);
        }
        catch (IOException e) {
          e.printStackTrace(System.err);
        }
      }
      // else {
      // FTPFile[] objFtpFiles = Client().listFiles(lstrPathName);
      // if (objFtpFiles != null) {
      // int i = 0;
      // for (FTPFile ftpFile : objFtpFiles) {
      // fileList[i++] = ftpFile.getName();
      // }
      // }
      // }
      if (fileList == null) {
        return vecDirectoryListing;
      }
      for (String strCurrentFile : fileList) {
        if (isNotHiddenFile(strCurrentFile)) {
          if (flgRecurseSubFolders == false) {
            if (strCurrentFile.startsWith(strCurrentDirectory) == false)
              strCurrentFile = strCurrentDirectory + "/" + strCurrentFile;
            vecDirectoryListing.add(strCurrentFile);
          }
          else {
            DoCD(strCurrentFile); // is this file-entry a subfolder?
            if (isNegativeCommandCompletion()) {
              if (strCurrentFile.startsWith(strCurrentDirectory) == false)
                strCurrentFile = strCurrentDirectory + "/" + strCurrentFile;
              vecDirectoryListing.add(strCurrentFile);
            }
            else {
              DoCD(strCurrentDirectory);
              if (flgRecurseSubFolders) {
                Vector<String> vecNames = getFilenames(strCurrentFile);
                if (vecNames != null) {
                  vecDirectoryListing.addAll(vecNames);
                }
              }
            }
          }
        }
      }
    }
    logger.debug("strCurrentDirectory = " + strCurrentDirectory);
    if (strCurrentDirectory != null) {
      DoCD(strCurrentDirectory);
      DoPWD();
    }
    return vecDirectoryListing;
  } // nList

  public boolean isDirectory(final String pstrPathName) {
    boolean flgResult = false;
    if (isNotHiddenFile(pstrPathName)) {
      if (strCurrentPath.length() <= 0) {
        strCurrentPath = getCurrentPath();
      }
      DoCD(pstrPathName); // is this file-entry a subfolder?
      if (isNegativeCommandCompletion()) {
      }
      else { // yes, it's a subfolder. undo the cd now
        DoCD(strCurrentPath);
        flgResult = true;
      }
    }
    return flgResult;
  }

  public String DoPWD() {
    final String conMethodName = conClassName + "::DoPWD";
    String lstrCurrentPath = "";
    try {
      logger.debug("Try pwd.");
      lstrCurrentPath = getCurrentPath();
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return lstrCurrentPath;
  } // private int DoPWD

  private String getCurrentPath() {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::getCurrentPath";

    String lstrCurrentPath = strCurrentPath;
    try {
      Client().pwd();
      lstrCurrentPath = getReplyString();
      logger.debug(HostID(String.format(objMsg.getMsg(SOSVfs_E_0106), conMethodName, "", lstrCurrentPath)));
      // Windows reply from pwd is : 257 "/kb" is current directory.
      // Unix reply from pwd is : 257 "/home/kb"
      int idx = lstrCurrentPath.indexOf('"'); // Unix?
      if (idx >= 0) {
        lstrCurrentPath = lstrCurrentPath.substring(idx + 1, lstrCurrentPath.length() - idx + 1);
        idx = lstrCurrentPath.indexOf('"');
        if (idx >= 0) {
          lstrCurrentPath = lstrCurrentPath.substring(0, idx);
        }
      }
      LogReply();
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return lstrCurrentPath;
  }

  @SuppressWarnings("unused")
  private int DoCDUP() {
    final String conMethodName = conClassName + "::DoCDUP";

    try {
      logger.debug("Try cdup .");
      Client().cdup();
      LogReply();
      DoPWD();
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return 0;
  } // private int DoPWD

  private int DoCD(final String strFolderName) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::DoCD";
    int x = 0;
    try {
      logger.debug("Try cd with '" + strFolderName + "'.");
      x = cd(strFolderName);
      LogReply();
    }
    catch (IOException e) {
    }
    return x;
  } // private int DoCD

  private boolean LogReply() {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::LogReply";
    strReply = getReplyString();
    logger.debug(HostID(strReply));
    return true;
  } // private boolean LogReply

  public boolean isNegativeCommandCompletion() {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::isNegativeCommandCompletion";
    int x = Client().getReplyCode();
    return (x > 300);
  } // private boolean isNegativeCommandCompletion

  public void CompletePendingCommand() {
    final String conMethodName = conClassName + "::CompletePendingCommand";

    try {
      if (Client().completePendingCommand() == false) {
        logout();
        disconnect();
        RaiseException(HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }

    if (isNegativeCommandCompletion()) {
      throw new JobSchedulerException("..error occurred 'NegativeCommandCompletion' on the FTP server: " + getReplyString());
    }

  }

  private boolean isPositiveCommandCompletion() {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::isPositiveCommandCompletion";
    int x = Client().getReplyCode();
    return (x <= 300);
  } // private boolean isPositiveCommandCompletion

  public boolean isNotHiddenFile(final String strFileName) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::isNotHiddenFile";
    if (strFileName.equalsIgnoreCase("..") == false && strFileName.equalsIgnoreCase(".") == false) {
      return true; // not a hidden file
    }
    return false; // it is a hidden-file
  } // private boolean isNotHiddenFile

  /**
   * return a listing of the contents of a directory in short format on
   * the remote machine
   * @param pathname on remote machine
   * @return a listing of the contents of a directory on the remote machine
   *
   * @exception Exception
   * @see #dir()
   */
  @Override
  public Vector<String> nList(String pathname, final boolean flgRecurseSubFolder) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::nList";

    try {
      return getFilenames(pathname, flgRecurseSubFolder);
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return null; // useless, but required by syntax-check
  } // nList

  /**
   * return a listing of the contents of a directory in short format on
   * the remote machine
   *
   * @return a listing of the contents of a directory on the remote machine
   *
   * @exception Exception
   * @see #nList( String )
   * @see #dir()
   * @see #dir( String )
   */
  @Override
  public Vector<String> nList() throws Exception {
    return getFilenames();
  } // nList

  /**
   * return a listing of the contents of a directory in short format on
   * the remote machine (without subdirectory)
   *
   * @return a listing of the contents of a directory on the remote machine
   *
   * @exception Exception
   * @see #nList( String )
   * @see #dir()
   * @see #dir( String )
   */
  private Vector<String> getFilenames() throws Exception {
    return getFilenames("", false);
  } // getFilenames

  private Vector<String> getFilenames(boolean flgRecurseSubFolders) throws Exception {
    return getFilenames("", flgRecurseSubFolders);
  } // getFilenames

  /**
   * return a listing of the contents of a directory in short format on
   * the remote machine
   *
   * @return a listing of the contents of a directory on the remote machine
   *
   * @exception Exception
   * @see #nList( String )
   * @see #dir()
   * @see #dir( String )
   */
  @Override
  public Vector<String> nList(boolean recursive) throws Exception {
    return getFilenames(recursive);
  } // nList

  /**
   * return a listing of the files in a directory in long format on
   * the remote machine
   * @param pathname on remote machine
   * @return a listing of the contents of a directory on the remote machine
   * @exception Exception
   * @see #nList()
   * @see #nList( String )
   * @see #dir()
   */
  public SOSFileList dir(String pathname) {
    Vector<String> strList = getFilenames(pathname);
    String[] strT = (String[]) strList.toArray(new String[strList.size()]);
    SOSFileList objFileList = new SOSFileList(strT);
    return objFileList;
  }

  /**
   * return a listing of a directory in long format on
   * the remote machine
   *
   * @param pathname on remote machine
   * @return a listing of the contents of a directory on the remote machine
   * @exception Exception
   * @see #nList()
   * @see #nList( String )
   * @see #dir()
   */
  @Override
  public SOSFileList dir(String pathname, int flag) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::dir";

    SOSFileList fileList = new SOSFileList();
    FTPFile[] listFiles = null;
    try {
      listFiles = Client().listFiles(pathname);
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    for (int i = 0; i < listFiles.length; i++) {
      if (flag > 0 && listFiles[i].isDirectory()) {
        fileList.addAll(this.dir(pathname + "/" + listFiles[i].toString(), ((flag >= 1024) ? flag : flag + 1024)));
      }
      else {
        if (flag >= 1024) {
          fileList.add(pathname + "/" + listFiles[i].toString());
        }
        else {
          fileList.add(listFiles[i].toString());
        }
      }
    }
    return fileList;
  }

  /**
   * return a listing of the files of the current directory in long format on
   * the remote machine
   * @return a listing of the contents of the current directory on the remote machine
   * @exception Exception
   * @see #nList()
   * @see #nList( String )
   * @see #dir( String )
   */
  public SOSFileList dir() {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::dir";

    try {
      return dir(".");
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return null;
  }

  /**
   * @return The entire text from the last FTP response as a String.
   */
  public String getResponse() {
    return this.getReplyString();
  }

  /**
   * return the size of remote-file on the remote machine on success, otherwise -1
   * @param remoteFile the file on remote machine
   * @return the size of remote-file on remote machine
   */
  public long size(String remoteFile) throws Exception {
    Client().sendCommand("SIZE " + remoteFile);
    LogReply();
    if (Client().getReplyCode() == FTPReply.CODE_213)
      return Long.parseLong(trimResponseCode(this.getReplyString()));
    else
      return -1L; // file not found or size not available
  }

  /**
   * trim the response code at the beginning
   * @param response
   * @return the response string without response code
   * @throws Exception
   */
  private String trimResponseCode(String response) throws Exception {
    if (response.length() < 5)
      return response;
    return response.substring(4).trim();
  }

  /**
   * Retrieves a named file from the ftp server.
   *
   * @param localFile The name of the local file.
   * @param remoteFile The name of the remote file.
   * @exception Exception
   * @see #getFile( String, String )
   */
  public void get(String remoteFile, String localFile) {
    final String conMethodName = conClassName + "::get";

    FileOutputStream out = null;
    boolean rc = false;
    try {
      out = new FileOutputStream(localFile);
      rc = Client().retrieveFile(remoteFile, out);
      if (rc == false) {
        RaiseException(HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    finally {
      closeObject(out);
    }
  } // get

  private void closeObject(OutputStream objO) {
    try {
      if (objO != null) {
        objO.flush();
        objO.close();
        objO = null;
      }
    }
    catch (Exception e) {
    }
  }

  private void closeInput(InputStream objO) {
    try {
      if (objO != null) {
        objO.close();
        objO = null;
      }
    }
    catch (IOException e) {
    }
  }

  /**
   * Retrieves a named file from the ftp server.
   *
   * @param localFile The name of the local file.
   * @param remoteFile The name of the remote file.
   * @return  The total number of bytes retrieved.
   * @see #get( String, String )
   * @exception Exception
   */
  @Override
  public long getFile(String remoteFile, String localFile) {
    final boolean flgAppendLocalFile = false;
    return this.getFile(remoteFile, localFile, flgAppendLocalFile);
  }

  /**
   * Retrieves a named file from the ftp server.
   *
   * @param localFile The name of the local file.
   * @param remoteFile The name of the remote file.
   * @param append Appends the remote file to the local file.
   * @return  The total number of bytes retrieved.
   * @see #get( String, String )
   * @exception Exception
   */
  @Override
  public long getFile(String remoteFile, String localFile, boolean append) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::getFile";

    InputStream in = null;
    OutputStream out = null;
    long totalBytes = 0;
    try {
      // TODO get filesize and report as a message
      in = Client().retrieveFileStream(remoteFile);
      if (in == null) {
        throw new JobSchedulerException("Could not open stream for " + remoteFile + ". Perhaps the file does not exist. Reply from ftp server: "
            + getReplyString());
      }
      if (isPositiveCommandCompletion() == false) {
        throw new JobSchedulerException("..error occurred in getFile() [retrieveFileStream] on the FTP server for file [" + remoteFile + "]: "
            + getReplyString());
      }
      // TODO Buffersize must be an Option
      byte[] buffer = new byte[4096];
      out = new FileOutputStream(new File(localFile), append);
      // TODO get progress info
      int bytes_read = 0;
      synchronized (this) {
        while ((bytes_read = in.read(buffer)) != -1) {
          // TODO create progress message
          out.write(buffer, 0, bytes_read);
          out.flush();
          totalBytes += bytes_read;
        }
      }
      closeInput(in);
      closeObject(out);
      this.CompletePendingCommand();
      // TODO create completed Message
      if (totalBytes > 0)
        return totalBytes;
      else
        return -1L;
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    finally {
      closeInput(in);
      closeObject(out);
    }
    return totalBytes;
  }

  /**
   * Stores a file on the server using the given name.
   * @param localFile The name of the local file.
   * @param remoteFile The name of the remote file.
   * @return True if successfully completed, false if not.
   * @exception Exception
   * @see #putFile( String, String )
   */
  @Override
  public void put(String localFile, String remoteFile) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::put";

    FileInputStream in = null;
    boolean rc = false;
    try {
      in = new FileInputStream(localFile);
      // TODO get progress info
      rc = Client().storeFile(remoteFile, in);
      if (rc == false) {
        RaiseException("put returns a negative returncode");
      }
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    finally {
      closeInput(in);
    }
  }

  /**
   * Stores a file on the server using the given name.
   *
   * @param localFile The name of the local file.
   * @param remoteFile The name of the remote file.
   * @return The total number of bytes written.
   *
   * @exception Exception
   * @see #put( String, String )
   */
  @Override
  // ISOSVfsFileTransfer
  public long putFile(String localFile, String remoteFile) throws Exception {
    OutputStream outputStream = Client().storeFileStream(remoteFile);
    if (isNegativeCommandCompletion()) {
      RaiseException("..error occurred in get storeFileStream() on the FTP server for file [" + remoteFile + "]: " + getReplyString());
    }
    long i = putFile(localFile, outputStream);
    logger.debug(String.format("file '%1$s' transfered to '%2$s'", localFile, remoteFile));
    return i;
  } // putFile

  /**
   * written to store a file on the server using the given name.
   *
   * @param localfile The name of the local file.
   * @param an OutputStream through which data can be
   * @return The total number of bytes written.
   * @exception Exception
   */
  @SuppressWarnings("null")
  @Override
  public long putFile(String localFile, OutputStream out) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::putFile";

    if (out == null)
      RaiseException("OutputStream null value.");
    FileInputStream in = null;
    long lngTotalBytesWritten = 0;
    try {
      // TODO Buffersize must be an Option
      byte[] buffer = new byte[4096];
      in = new FileInputStream(new File(localFile));
      // TODO get progress info
      int bytesWritten;
      synchronized (this) {
        while ((bytesWritten = in.read(buffer)) != -1) {
          out.write(buffer, 0, bytesWritten);
          lngTotalBytesWritten += bytesWritten;
        }
      }
      closeInput(in);
      closeObject(out);
      this.CompletePendingCommand();
      // if (Client().completePendingCommand() == false) {
      // logout();
      // disconnect();
      // RaiseException("Filetransfer failed. completePendingCommand() returns false");
      // }
      // if (isNegativeCommandCompletion()) {
      // RaiseException("..error occurred in putFile() on the FTP server for file [" + localFile + "]: " + getReplyString());
      // }
      return lngTotalBytesWritten;
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    finally {
      closeInput(in);
      closeObject(out);
    }
    return lngTotalBytesWritten;
  } // putFile

  private void RaiseException(final Exception e, final String pstrM) {
    if (flgStackTracePrinted == false) {
      e.printStackTrace(System.err);
      logger.error(pstrM);
      flgStackTracePrinted = true;
    }
    throw new JobSchedulerException(pstrM, e);
  }

  private void RaiseException(final String pstrM) {
    logger.error(pstrM);
    throw new JobSchedulerException(pstrM);
  }

  public FTPClient getClient() {
    return Client();
  }

  /**
   * append a local file to the remote one on the server
   *
   * @param localFile The name of the local file.
   * @param remoteFile The name of the remote file.
   *
   * @return The total number of bytes appended.
   *
   * @exception Exception
   * @see #put( String, String )
   * @see #putFile( String, String )
   */
  @Override
  public long appendFile(String localFile, String remoteFile) {
    final String conMethodName = conClassName + "::appendFile";

    long i = 0;
    try {
      i = putFile(localFile, Client().appendFileStream(remoteFile));
      logger.info("bytes appended : " + i);
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return i;
  } // appendFile

  /**
   * Using ASCII mode for file transfers
   * @return True if successfully completed, false if not.
   * @throws IOException If an I/O error occurs while either sending a
   * command to the server or receiving a reply from the server.
   */
  public void ascii() {
    final String conMethodName = conClassName + "::ascii";

    try {
      boolean flgResult = Client().setFileType(FTP.ASCII_FILE_TYPE);
      if (flgResult == false) {
        throw new JobSchedulerException("setFileType not possible, due to : " + getReplyString());
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
  }

  /**
   * Using Binary mode for file transfers
   * @return True if successfully completed, false if not.
   * @throws IOException If an I/O error occurs while either sending a
   * command to the server or receiving a reply from the server.
   */
  public void binary() {
    final String conMethodName = conClassName + "::binary";

    try {
      boolean flgResult = Client().setFileType(FTP.BINARY_FILE_TYPE);
      if (flgResult == false) {
        throw new JobSchedulerException("setFileType not possible, due to : " + getReplyString());
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
  }

  /**
   *
   * @param directory The new working directory.
   * @return The reply code received from the server.
   * @throws IOException If an I/O error occurs while either sending a
   * command to the server or receiving a reply from the server.
   */
  public int cd(String directory) throws IOException {
    return Client().cwd(directory);
  }

  /**
   * Deletes a file on the FTP server.
   * @param The pathname of the file to be deleted.
   * @return True if successfully completed, false if not.
   * @throws IOException If an I/O error occurs while either sending a
   * command to the server or receiving a reply from the server.
   */
  public void delete(String pathname) throws IOException {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::delete";

    Client().deleteFile(pathname);
    logger.info(String.format("File deleted : %1$s, reply is %2$s", pathname, getReplyString()));
  }

  @Override
  public void login(String strUserName, String strPassword) {
    final String conMethodName = conClassName + "::login";
    try {
      logger.debug(String.format("Try to login with user '%1$s'.", strUserName));
      Client().login(strUserName, strPassword);
      // TODO pr�fen, ob wirklich eingeloggt
      logger.debug(HostID(String.format("user '%1$s' logged in.", strUserName)));
      LogReply();
      try {
        postLoginOperations();
      }
      catch (Exception e) {
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    LogReply();
  } // private boolean login

  /**
   * Performs some post-login operations, such trying to detect server support
   * for utf8.
   *
   */
  private void postLoginOperations() throws Exception {
    // synchronized (lock) {

//    if (objOptions.CheckServerFeatures.value() == true) { // JIRA SOSFTP-92
      Client().sendCommand("FEAT");
      LogReply();
//    }
    if (objFTPReply.getCode() == FTPReply.SYSTEM_STATUS) {
      String[] lines = objFTPReply.getMessages();
      for (int i = 1; i < lines.length - 1; i++) {
        String feat = lines[i].trim().toUpperCase();
        // REST STREAM supported?
        if ("REST STREAM".equalsIgnoreCase(feat)) {
          restSupported = true;
          continue;
        }
        // UTF8 supported?
        if ("UTF8".equalsIgnoreCase(feat)) {
          utf8Supported = true;
          Client().setControlEncoding("UTF-8");
          continue;
        }
        // MLSD supported?
        if ("MLSD".equalsIgnoreCase(feat)) {
          mlsdSupported = true;
          continue;
        }
        // MODE Z supported?
        if ("MODE Z".equalsIgnoreCase(feat) || feat.startsWith("MODE Z ")) {
          modezSupported = true;
          continue;
        }
      }
    }
    // Turn UTF 8 on (if supported).
    if (utf8Supported) {
      Client().sendCommand("OPTS UTF8 ON");
      LogReply();
    }
    // Data channel security.
//    if (security == SECURITY_FTPS || security == SECURITY_FTPES) {
//      Client().sendCommand("PBSZ 0");
//      LogReply();
//      Client().sendCommand("PROT P");
//      LogReply();
//
//      if (objFTPReply.isSuccessCode()) {
//        dataChannelEncrypted = true;
//      }
//    }
  }

  @Override
  public boolean changeWorkingDirectory(String pathname) {
    final String conMethodName = conClassName + "::changeWorkingDirectory";

    try {
      Client().cwd(pathname);
      logger.debug("..ftp server reply [directory exists] [" + pathname + "]: " + getReplyString());
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return true;
  }

  @Override
  public void disconnect() {
    final String conMethodName = conClassName + "::disconnect";

    try {
      if (Client().isConnected()) {
        Client().disconnect();
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
  }

  @Override
  public String getReplyString() {
    String strT = Client().getReplyString();
    objFTPReply = new SOSFtpServerReply(strT);
    return strT;
  }

  @Override
  public boolean isConnected() {
    return Client().isConnected();
  }

  @Override
  public String[] listNames(String pathname) throws IOException {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::listNames";
    String strA[] = Client().listNames(pathname);
    for (int i = 0; i < strA.length; i++) {
      strA[i] = strA[i].replaceAll("\\\\", "/");
    }
    logger.debug(String.format("reply from FTP-Server is %1$s, code = %2$d", Client().getReplyString(), Client().getReplyCode()));
    return strA;
  }

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

    try {
      if (this.Client().isConnected() == true) {
        this.Client().logout();
        String strHost = host;
        if (objHost != null) {
          strHost = objHost.Value();
        }
        logger.debug(String.format("logout from host '%1$s', reply '%2$s'", strHost, getReplyString()));
      }
      else {
        logger.info("not connected, logout useless.");
      }
    }
    catch (IOException e) { // no error-handling needed, due to end-of session
      logger.warn("problems during logout. " + e.getMessage());
    }
  }

  public void rename(String from, String to) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::rename";

    try {
      this.Client().rename(from, to);
    }
    catch (IOException e) {
      e.printStackTrace();
      RaiseException(e, "rename failed");
    }
    logger.info(String.format("rename file '%1$s' to '%2$s'.", from, to));
  }

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

  @Override
  public void ExecuteCommand(String strCmd) throws Exception {
    final String conMethodName = conClassName + "::ExecuteCommand";

    objFTPClient.sendCommand(strCmd);
    logger.debug(HostID(String.format(objMsg.getMsg(SOSVfs_E_0106), conMethodName, strCmd, getReplyString())));
  }

  @Override
  public String createScriptFile(String pstrContent) throws Exception {
    notImplemented();
    return null;
  }

  @Override
  public Integer getExitCode() {
    notImplemented();
    return null;
  }

  @Override
  public String getExitSignal() {
    notImplemented();
    return null;
  }
  @SuppressWarnings("unused")
  private ISOSAuthenticationOptions  objAO  = null;

  @Override
  public ISOSConnection Authenticate(ISOSAuthenticationOptions pobjAO) throws Exception {
    String user = pobjAO.getUser().Value();
    String Passwd = pobjAO.getPassword().Value();
    this.login(user, Passwd);
    objAO = pobjAO;
    return this;
  }

  @Override
  public void CloseConnection() throws Exception {
    if (Client().isConnected()) {
      Client().disconnect();
      LogReply();
      logger.debug(String.format(objMsg.getMsg(SOSVfs_I_0109), host, port));
    }
  }

  private FTPClient Client() {
    if (objFTPClient == null) {
      objFTPClient = new FTPClient();
      FTPClientConfig conf = new FTPClientConfig();
      // conf.setServerLanguageCode("fr");
      // objFTPClient.configure(conf);
      /**
       * This listener is to write all commands and response from commands to system.out
       *
       */
      // TODO create a hidden debug-option to activate this listener
      if (objConnection2Options != null) {
        if (objConnection2Options.ProtocolCommandListener.value() == true) {
          listener = new PrintCommandListener(new PrintWriter(System.out));
          objFTPClient.addProtocolCommandListener(listener);
        }
      }

      listener = new PrintCommandListener(new PrintWriter(System.out));
      // TODO implement as an additional Option-setting
      String strAddFTPProtocol = System.getenv("AddFTPProtocol");
      if (strAddFTPProtocol != null && strAddFTPProtocol.equalsIgnoreCase("true")) {
        objFTPClient.addProtocolCommandListener(listener);
      }

    }
    return objFTPClient;
  }

  /**
   *
   * \brief Connect
   *
   * \details
   *
   * \return
   *
   * @return
   */
  @Override
  public ISOSConnection Connect() {
    final String conMethodName = conClassName + "::Connect";

    String strH = host = objConnectionOptions.getHost().Value();
    int intP = port = objConnectionOptions.getPort().value();

    logger.debug(objMsg.getMsg(String.format(SOSVfs_D_0101), strH, intP));
    try {
      this.connect(strH, intP);
      logger.debug(String.format(objMsg.getMsg(SOSVfs_D_0102), strH, intP));
    }
    catch (RuntimeException e) {
      logger.info(String.format(objMsg.getMsg(SOSVfs_E_0107), host, port, e.getMessage()));
      String strAltHost = host = objConnectionOptions.getalternative_host().Value();
      int intAltPort = port = objConnectionOptions.getalternative_port().value();

      if (isNotEmpty(strAltHost) && intAltPort > 0) {
        logger.debug(objMsg.getMsg(String.format(SOSVfs_D_0101), strAltHost, intAltPort));
        this.connect(strAltHost, intAltPort);
        logger.debug(String.format(objMsg.getMsg(SOSVfs_D_0102), strAltHost, intAltPort));
      }
      else {
        logger.info(String.format(objMsg.getMsg(SOSVfs_E_0107), host, port, e.getMessage()));
        RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
      }
    }
    return this;
  }

  /**
   *
   * \brief Connect
   *
   * \details
   *
   * \return
   *
   * @param pobjConnectionOptions
   * @return
   */
  public ISOSConnection Connect(SOSConnection2OptionsAlternate pobjConnectionOptions) {
    final String conMethodName = conClassName + "::Connect";
    objConnection2Options = pobjConnectionOptions;
    try {
      objHost = objConnection2Options.getHost();
      objPort = objConnection2Options.getport();
      this.connect(objHost.Value(), objPort.value());
      if (Client().isConnected() == false) {
        SOSConnection2OptionsSuperClass objAlternate = objConnection2Options.Alternatives();
        objHost = objAlternate.host;
        objPort = objAlternate.port;
        logger.info(String.format("try alternate host due to connection-error", host));
        this.connect(objHost.Value(), objPort.value());
        if (Client().isConnected() == false) {
          objHost = null;
          objPort = null;
          host = "";
          port = -1;
          RaiseException("Connection not possible");
        }
      }
      // TODO find the "Microsoft FTP Server" String from the reply and set the HostType accordingly
      // TODO respect Proxy-Server. implement handling of
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return this;
  }

  @Deprecated
  @Override
  public ISOSConnection Connect(ISOSConnectionOptions pobjConnectionOptions) throws Exception {
    final String conMethodName = conClassName + "::Connect";

    objConnectionOptions = pobjConnectionOptions;
    try {
      String host = objConnectionOptions.getHost().Value();
      int port = objConnectionOptions.getPort().value();
      // TODO try alternate host, if this connection is not possible
      this.connect(host, port);
      // TODO find the "Microsoft FTP Server" String from the reply and set the HostType accordingly
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return this;
  }

  @Override
  public ISOSConnection Connect(String pstrHostName, int pintPortNumber) throws Exception {
    this.connect(pstrHostName, pintPortNumber);
    if (objConnectionOptions != null) {
      objConnectionOptions.getHost().Value(pstrHostName);
      objConnectionOptions.getPort().value(pintPortNumber);
    }
    return this;
  }

  @Override
  public void CloseSession() throws Exception {
    this.logout();
  }

  @Override
  public ISOSSession OpenSession(ISOSShellOptions pobjShellOptions) throws Exception {
    notImplemented();
    return null;
  }

  @Override
  public ISOSVirtualFile TransferMode(SOSOptionTransferMode pobjFileTransferMode) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::TransferMode";

    String strMode = pobjFileTransferMode.getDescription();
    if (pobjFileTransferMode.isAscii()) {
      this.ascii();
    }
    else {
      this.binary();
    }
    logger.debug(String.format("using %1$s mode for file transfer", strMode));
    logger.debug(String.format("ftp server reply [%1$s]: %2$s", strMode, getReplyString()));

    return null;
  }

  public SOSFileListEntry getNewVirtualFile(final String pstrFileName) {
    SOSFileListEntry objF = new SOSFileListEntry(pstrFileName);
    objF.VfsHandler(this);
    return objF;
  }

  @Override
  public ISOSVirtualFolder mkdir(SOSFolderName pobjFolderName) {
    this.mkdir(pobjFolderName.Value());
    return null;
  }

  @Override
  public boolean rmdir(SOSFolderName pobjFolderName) throws IOException {
    this.rmdir(pobjFolderName.Value());
    return true;
  }

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

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

  @Override
  public SOSFileList dir(SOSFolderName pobjFolderName) {
    this.dir(pobjFolderName.Value());
    return null;
  }

  @Override
  public StringBuffer getStdErr() throws Exception {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public StringBuffer getStdOut() throws Exception {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public boolean remoteIsWindowsShell() {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public void setJSJobUtilites(JSJobUtilities pobjJSJobUtilities) {
    // TODO Auto-generated method stub
  }

  @Override
  public ISOSVirtualFile getFileHandle(String pstrFilename) {
    final String conMethodName = conClassName + "::getFileHandle";
    ISOSVirtualFile objFtpFile = new SOSVfsFtpFile(pstrFilename);
    logger.debug(String.format("%2$s: getFileHandle for %1$s ", pstrFilename, conMethodName));
    objFtpFile.setHandler(this);
    return objFtpFile;
  }

  @Override
  public String[] getFilelist(String folder, String regexp, int flag, boolean withSubFolder) {
    // TODO vecDirectoryListing = null; pr�fen, ob notwendig
    vecDirectoryListing = null;
    if (vecDirectoryListing == null) {
      vecDirectoryListing = nList(folder, withSubFolder);
    }
    Vector<String> strB = new Vector<String>();
    Pattern pattern = Pattern.compile(regexp, 0);
    for (String strFile : vecDirectoryListing) {
      /**
       * the file_spec has to be compared to the filename only ... excluding the path
       */
      String strFileName = new File(strFile).getName();
      Matcher matcher = pattern.matcher(strFileName);
      if (matcher.find() == true) {
        strB.add(strFile);
      }
    }
    return strB.toArray(new String[strB.size()]);
  }

  @Override
  public OutputStream getAppendFileStream(String strFileName) {
    final String conMethodName = conClassName + "::getAppendFileStream";
    OutputStream objO = null;
    try {
      objO = Client().appendFileStream(strFileName);
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return objO;
  }

  @Override
  public long getFileSize(String strFileName) {
    final String conMethodName = conClassName + "::getFileSize";
    long lngFileSize = 0;
    try {
      lngFileSize = this.size(strFileName);
    }
    catch (Exception e) {
      e.printStackTrace();
      RaiseException(e, "Problem with " + conMethodName);
    }
    // TODO Auto-generated method stub
    return lngFileSize;
  }

  @Override
  public InputStream getInputStream(String strFileName) {
    final String conMethodName = conClassName + "::getInputStream";
    InputStream objI = null;
    try {
      if (modezSupported == true) {
      }
      objI = Client().retrieveFileStream(strFileName);
      if (objI == null) {
        LogReply();
      }
    }
    catch (IOException e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return objI;
  }

  @Override
  public String getModificationTime(String strFileName) {
    final String conMethodName = conClassName + "::getModificationTime";

    String strT = null;
    // Es gibt Probleme bei der standalone-compilation mit javac. unter eclipse l�uft es fehlerfrei
    try {
      // strT = Client().getModificationTime(strFileName);
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    return strT;
  }

  @Override
  public OutputStream getOutputStream(String strFileName) {
    OutputStream objO = null;
    try {
      objO = Client().storeFileStream(strFileName);
      LogReply();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
    return objO;
  }

  @Override
  public void close() {
    final String conMethodName = conClassName + "::close";

    try {
      /**
       * don't do that, because if no command is pending this will lead into
       * a huge waittime and an exception.
       */
      // this.CompletePendingCommand();
      // Client().completePendingCommand();
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
  }

  @Override
  public void closeInput() {
  }

  @Override
  public void closeOutput() {
    final String conMethodName = conClassName + "::closeOutput";

    try {
      // this.getOutputStream(strFileName);
      // Client().completePendingCommand();
      this.CompletePendingCommand();
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
  }

  @Override
  public void flush() {
  }

  @Override
  public int read(byte[] bteBuffer) {
    return 0;
  }

  @Override
  public int read(byte[] bteBuffer, int intOffset, int intLength) {
    return 0;
  }

  @Override
  public void write(byte[] bteBuffer, int intOffset, int intLength) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::write";
  }

  @Override
  public void write(byte[] bteBuffer) {
  }

  @Override
  public void openInputFile(String pstrFileName) {
  }

  @Override
  public void openOutputFile(String pstrFileName) {
  }

  @Override
  public Vector<ISOSVirtualFile> getFiles(String string) {
    return null;
  }

  @Override
  public Vector<ISOSVirtualFile> getFiles() {
    return null;
  }

  public void putFile(ISOSVirtualFile objVirtualFile) {
    final String conMethodName = conClassName + "::putFile";

    String strName = objVirtualFile.getName();
    // strName = new File(strName).getAbsolutePath();
    // if (strName.startsWith("c:") == true) {
    // strName = strName.substring(3);
    // }
    ISOSVirtualFile objVF = (ISOSVirtualFile) this.getFileHandle(strName);
    OutputStream objOS = objVF.getFileOutputStream();
    InputStream objFI = objVirtualFile.getFileInputStream();
    // TODO Buffersize must be defined via Options-Class
    int lngBufferSize = 1024;
    byte[] buffer = new byte[lngBufferSize];
    int intBytesTransferred;
    long totalBytes = 0;
    try {
      synchronized (this) {
        while ((intBytesTransferred = objFI.read(buffer)) != -1) {
          objOS.write(buffer, 0, intBytesTransferred);
          totalBytes += intBytesTransferred;
        }
        objFI.close();
        objOS.flush();
        objOS.close();
      }
    }
    catch (Exception e) {
      RaiseException(e, HostID(String.format(objMsg.getMsg(SOSVfs_E_0105), conMethodName)));
    }
    finally {
    }
  }

  @Override
  /* ISOSVfsFiletransfer */
  public void ControlEncoding(String pstrControlEncoding) {
    @SuppressWarnings("unused")
    final String conMethodName = conClassName + "::ControlEncoding";

    if (pstrControlEncoding.length() > 0) {
      objFTPClient.setControlEncoding(pstrControlEncoding);
      LogReply();
    }
  }
}
TOP

Related Classes of com.sos.VirtualFileSystem.FTP.SOSVfsFtp

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.