/********************************************************* 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.SFTP;
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.net.SocketException;
import java.net.UnknownHostException;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.SOSOptionInFileName;
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.FTP.SOSVfsFtpFile;
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.annotation.I18NResourceBundle;
import com.trilead.ssh2.Connection;
import com.trilead.ssh2.SFTPv3Client;
import com.trilead.ssh2.SFTPv3DirectoryEntry;
import com.trilead.ssh2.SFTPv3FileAttributes;
import com.trilead.ssh2.SFTPv3FileHandle;
import com.trilead.ssh2.Session;
@I18NResourceBundle(baseName = "SOSVirtualFileSystem", defaultLocale = "en")
public class SOSVfsSFtp extends SOSVfsBaseClass implements ISOSVfsFileTransfer, ISOSVFSHandler, ISOSVirtualFileSystem, ISOSConnection {
private final String conClassName = "SOSVfsSFtp";
private Logger logger = Logger.getLogger(SOSVfsSFtp.class);
private Vector<String> vecDirectoryListing = null;
/** key file: ~/.ssh/id_rsa or ~/.ssh/id_dsa */
protected String authenticationFilename = "";
/** ssh connection object */
protected Connection sshConnection = null;
/** ssh session object */
protected Session sshSession = null;
/** SFTP Client **/
protected SFTPv3Client objFTPClient = 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 isConnected = false;
// keep Track of current directory for ftp emulation
private String currentDirectory = "";
protected String reply = "OK";
private char[] authenticationFile = null;
/**
*
* \brief SOSVfsFtp
*
* \details
*
*/
public SOSVfsSFtp() {
}
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) {
try {
host = phost;
port = pport;
logger.debug(String.format("Try to connect to host '%1$s' at Port '%2$d'.", host, port));
if (isConnected() == false) {
sshConnection = new Connection(host, port);
sshConnection.connect();
isConnected = true;
logger.debug(String.format("Connected to '%1$s' at Port '%2$d'.", host, port));
LogReply();
}
else {
logger.warn(String.format("host '%1$s' at Port '%2$d' is already connected.", host, port));
}
}
catch (Exception e) {
String strM = HostID("connect returns an exception");
// e.printStackTrace(System.err);
logger.error(strM, e);
// throw new RuntimeException(strM, e);
}
}
@SuppressWarnings("unused")
private void connect(String hostname) throws SocketException, IOException, UnknownHostException {
if (isConnected() == false)
this.connect(hostname, 22);
}
/**
* 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) {
try {
Client().mkdir(pathname, 484);
reply = "mkdir OK";
logger.debug(HostID("..ftp server reply [mkdir] [" + pathname + "]: " + getReplyString()));
}
catch (IOException e) {
throw new RuntimeException(HostID("makeDirectory returns an exception"), e);
}
}
/**
* Removes a directory on the FTP server (if empty).
* @param pathname The pathname of the directory to remove.
* @throws java.lang.IOException
*/
public void rmdir(String pathname) throws IOException {
Client().rm(pathname);
reply = "rm OK";
}
/**
* turn passive transfer mode on.
*
* @return The reply code received from the server.
*/
public int passive() {
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;
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)) {
DoCD(strCurrentFile); // is this file-entry a subfolder?
if (isNegativeCommandCompletion() == false) {
if (strCurrentDirectory.trim().length() > 0 && 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 String DoPWD() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::DoPWD";
String lstrCurrentPath = "";
try {
// logger.debug("Try pwd.");
lstrCurrentPath = getCurrentPath();
}
catch (Exception e) {
logger.error(HostID("Problems with pwd"), e);
}
return lstrCurrentPath;
} // private int DoPWD
private String getCurrentPath() {
String lstrCurrentPath = strCurrentPath;
// try {
// Client().pwd();
// lstrCurrentPath = getReplyString();
// logger.debug(String.format("reply from pwd is : %1$s", 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) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
return lstrCurrentPath;
}
// private int DoCDUP() {
//
// final String conMethodName = conClassName + "::DoCDUP";
//
// try {
// logger.debug("Try cdup .");
//
// Client().cdup();
// LogReply();
// DoPWD();
//
// }
// catch (IOException e) {
// logger.error("Problems with CDUP", e);
// }
//
// 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();
if (strReply.trim().length() > 0) {
logger.debug(strReply);
}
return true;
} // private boolean LogReply
public boolean isNegativeCommandCompletion() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::isNegativeCommandCompletion";
int x = 0;
// TODO separate Routine draus machen
// try {
// if (Client().completePendingCommand() == false) {
// logout();
// disconnect();
// RaiseException("File transfer failed. completePendingCommand() returns false");
// }
// }
// catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// int x = getReplyCode();
return (x > 300);
} // private boolean isNegativeCommandCompletion
public void CompletePendingCommand() {
// try {
// if (Client().completePendingCommand() == false) {
// logout();
// disconnect();
// RaiseException("File transfer failed. completePendingCommand() returns false");
// }
// }
// catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// RaiseException("File transfer failed. completePendingCommand() raised an exception");
// }
}
private boolean isPositiveCommandCompletion() {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::isPositiveCommandCompletion";
int x = 0;
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) {
try {
return getFilenames(pathname, flgRecurseSubFolder);
}
catch (Exception e) {
throw new JobSchedulerException("getfilenames in nLixt returns an exception", e);
}
} // 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) {
SOSFileList fileList = new SOSFileList();
String[] listFiles = null;
try {
listFiles = this.listNames(pathname);
}
catch (IOException e) {
RaiseException(e, "listfiles in dir returns an exception");
}
if (listFiles != null) {
for (int i = 0; i < listFiles.length; i++) {
if (flag > 0 && isDirectory(listFiles[i])) {
fileList.addAll(this.dir(pathname + "/" + listFiles[i], ((flag >= 1024) ? flag : flag + 1024)));
}
else {
if (flag >= 1024) {
fileList.add(pathname + "/" + listFiles[i].toString());
}
else {
fileList.add(listFiles[i].toString());
}
}
}
}
return fileList;
}
/**
* Checks if file is a directory
*
* @param filename
* @return true, if filename is a directory
*/
@Override
public boolean isDirectory(String filename) {
try {
return Client().stat(filename).isDirectory();
}
catch (Exception e) {
}
return false;
}
public String[] listNames(String pathname) throws IOException {
pathname = resolvePathname(pathname);
try {
if (pathname.length() == 0)
pathname = ".";
if (!fileExists(pathname))
return null;
if (!isDirectory(pathname)) {
File remoteFile = new File(pathname);
reply = "ls OK";
return new String[] { remoteFile.getName() };
}
Vector files = Client().ls(pathname);
String[] rvFiles = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
SFTPv3DirectoryEntry entry = (SFTPv3DirectoryEntry) files.get(i);
rvFiles[i] = entry.filename;
}
reply = "ls OK";
return rvFiles;
}
catch (Exception e) {
reply = e.toString();
return null;
}
}
/**
* 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() {
try {
return dir(".");
}
catch (Exception e) {
throw new RuntimeException("dir returns an exception", e);
}
}
/**
* @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 {
remoteFile = resolvePathname(remoteFile);
try {
return Client().stat(remoteFile).size.longValue();
}
catch (com.trilead.ssh2.SFTPException e) {
return -1;
}
catch (Exception e) {
throw new Exception("Error occured checking size: " + e, e);
}
}
/**
* trim the response code at the beginning
* @param response
* @return the response string without response code
* @throws Exception
*/
@SuppressWarnings("unused")
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) {
// FileOutputStream out = null;
// boolean rc = false;
// try {
// out = new FileOutputStream(localFile);
// rc = Client().retrieveFile(remoteFile, out);
// if (rc == false) {
// throw new JobSchedulerException("retrieveFile returns a negative return-code");
// }
// }
// catch (IOException e) {
// throw new JobSchedulerException("get returns an exception", e);
// }
// finally {
// closeObject(out);
// }
// } // get
public long getFile(String remoteFile, String localFile, boolean append) throws Exception {
String sourceLocation = resolvePathname(remoteFile);
SFTPv3FileHandle sftpFileHandle = null;
FileOutputStream fos = null;
File transferFile = null;
long remoteFileSize = -1;
try {
transferFile = new File(localFile);
remoteFileSize = size(remoteFile);
sftpFileHandle = objFTPClient.openFileRO(sourceLocation);
fos = null;
long offset = 0;
try {
fos = new FileOutputStream(transferFile, append);
byte[] buffer = new byte[32768];
while (true) {
int len = objFTPClient.read(sftpFileHandle, offset, buffer, 0, buffer.length);
if (len <= 0)
break;
fos.write(buffer, 0, len);
offset += len;
}
fos.flush();
fos.close();
fos = null;
}
catch (Exception e) {
throw new Exception("error occurred get file [" + transferFile.getAbsolutePath() + "]: " + e.getMessage());
}
finally {
if (fos != null)
try {
fos.close();
fos = null;
}
catch (Exception ex) {
} // gracefully ignore this error
}
objFTPClient.closeFile(sftpFileHandle);
sftpFileHandle = null;
if (remoteFileSize > 0 && remoteFileSize != transferFile.length())
throw new Exception("remote file size [" + remoteFileSize + "] and local file size [" + transferFile.length()
+ "] are different. Number of bytes written to local file: " + offset);
return transferFile.length();
}
catch (Exception e) {
throw e;
}
finally {
try {
objFTPClient.closeFile(sftpFileHandle);
}
catch (Exception e) {
}
}
}
public long readFile(String pstrFilename) throws Exception {
SFTPv3FileHandle sftpFileHandle = null;
try {
String sourceLocation = resolvePathname(pstrFilename);
long remoteFileSize = size(sourceLocation);
sftpFileHandle = openFileRO(pstrFilename);
long offset = 0;
try {
byte[] buffer = new byte[32768];
while (true) {
int len = objFTPClient.read(sftpFileHandle, offset, buffer, 0, buffer.length);
if (len <= 0)
break;
offset += len;
}
}
catch (Exception e) {
throw new JobSchedulerException("error occurred reading file [" + pstrFilename + "]: " + e.getMessage());
}
// if (remoteFileSize > 0 && remoteFileSize != transferFile.length())
// throw new Exception("remote file size [" + remoteFileSize + "] and local file size [" + transferFile.length()
// + "] are different. Number of bytes written to local file: " + offset);
return remoteFileSize;
}
catch (Exception e) {
throw e;
}
finally {
try {
objFTPClient.closeFile(sftpFileHandle);
sftpFileHandle = null;
}
catch (Exception e) {
throw e;
}
}
}
// private SFTPv3FileHandle getHandle (final String pstrFileName) {
// @SuppressWarnings("unused")
// final String conMethodName = conClassName + "::getHandle";
//
// String sourceLocation = resolvePathname(pstrFileName);
//
// SFTPv3FileHandle sftpFileHandle = null;
// try {
// sftpFileHandle = objFTPClient.openFileRO(sourceLocation);
// }
// catch (IOException e) {
// e.printStackTrace();
// }
//
// return sftpFileHandle;
// }
public SFTPv3FileHandle openFileRO(String pstrFilename) throws Exception {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::openFileRO";
String sourceLocation = resolvePathname(pstrFilename);
SFTPv3FileHandle sftpFileHandle = null;
try {
sftpFileHandle = objFTPClient.openFileRO(sourceLocation);
}
catch (Exception e) {
throw new JobSchedulerException("error occurred opening file [" + sourceLocation + "]: " + e.getMessage());
}
finally {
}
return sftpFileHandle;
}
public SFTPv3FileHandle openFileWR(String pstrFilename) throws Exception {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::openFileWR";
SFTPv3FileHandle sftpFileHandle = null;
String sourceLocation = resolvePathname(pstrFilename);
try {
sftpFileHandle = objFTPClient.createFileTruncate(sourceLocation);
}
catch (Exception e) {
throw new JobSchedulerException("error occurred opening file [" + sourceLocation + "]: " + e.getMessage());
}
finally {
}
return sftpFileHandle;
}
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;
long lngNoOfBytesRead = 0;
try {
lngNoOfBytesRead = this.getFile(remoteFile, localFile, flgAppendLocalFile);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return lngNoOfBytesRead;
}
/**
* 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
*/
/**
* 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) {
this.put(localFile, remoteFile);
}
/**
* 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 {
long offset = 0;
try {
remoteFile = resolvePathname(remoteFile);
SFTPv3FileHandle fileHandle = objFTPClient.createFileTruncate(remoteFile);
File localF = new File(localFile);
FileInputStream fis = null;
try {
fis = new FileInputStream(localF);
byte[] buffer = new byte[32768];
while (true) {
int len = fis.read(buffer, 0, buffer.length);
if (len <= 0)
break;
objFTPClient.write(fileHandle, offset, buffer, 0, len);
offset += len;
}
fis.close();
fis = null;
}
catch (Exception e) {
RaiseException("error occurred writing file [" + localFile + "]: " + e.getMessage());
}
finally {
if (fis != null)
try {
fis.close();
fis = null;
}
catch (Exception ex) {
} // gracefully ignore this error
}
objFTPClient.closeFile(fileHandle);
logger.debug(String.format("file '%1$s' transfered to '%2$s'", localFile, remoteFile));
fileHandle = null;
reply = "put OK";
return offset;
}
catch (Exception e) {
reply = e.toString();
RaiseException(e, "Error during putFile: " + e);
}
return offset;
}
/**
* 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) {
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);
return lngTotalBytesWritten;
}
catch (Exception e) {
RaiseException(e, "putfile returns an exception");
}
finally {
closeInput(in);
closeObject(out);
}
return lngTotalBytesWritten;
} // putFile
private void RaiseException(final Exception e, final String pstrM) {
logger.error(pstrM);
e.printStackTrace(System.err);
throw new JobSchedulerException(pstrM, e);
}
private void RaiseException(final String pstrM) {
logger.error(pstrM);
throw new JobSchedulerException(pstrM);
}
public SFTPv3Client 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) {
notImplemented();
// long i;
// try {
// i = putFile(localFile, Client().appendFileStream(remoteFile));
// logger.info("bytes appended : " + i);
//
// }
// catch (IOException e) {
// throw new RuntimeException("appendFileStream returns an exception", e);
// }
return -1;
} // 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() {
// try {
// boolean flgResult = Client().setFileType(FTP.ASCII_FILE_TYPE);
// if (flgResult == false) {
// throw new JobSchedulerException("setFileType not possible, due to : " + getReplyString());
// }
// }
// catch (IOException e) {
// throw new JobSchedulerException("ascii returns an exception", e);
// }
}
/**
* 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() {
// try {
// boolean flgResult = Client().setFileType(FTP.BINARY_FILE_TYPE);
// if (flgResult == false) {
// throw new JobSchedulerException("setFileType not possible, due to : " + getReplyString());
// }
//
// }
// catch (IOException e) {
// throw new JobSchedulerException("setFileType to binary returns an exception", e);
// }
}
/**
*
* @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 {
changeWorkingDirectory(directory);
return 1;
}
private boolean fileExists(String filename) {
try {
SFTPv3FileAttributes attributes = Client().stat(filename);
if (attributes != null) {
return (attributes.isRegularFile() || attributes.isDirectory());
}
else {
return false;
}
}
catch (Exception e) {
return false;
}
}
public boolean changeWorkingDirectory(String pathname) throws IOException {
pathname = resolvePathname(pathname);
// cut trailing "/" if it's not the only character
if (pathname.length() > 1 && pathname.endsWith("/"))
pathname = pathname.substring(0, pathname.length() - 1);
if (!fileExists(pathname)) {
reply = "\"" + pathname + "\" doesn't exist.";
return false;
}
if (!isDirectory(pathname)) {
reply = "\"" + pathname + "\" is not a directory.";
return false;
}
if (pathname.startsWith("/") || currentDirectory.length() == 0) {
currentDirectory = pathname;
reply = "cd OK";
return true;
}
currentDirectory = pathname;
reply = "cd OK";
return true;
}
private String resolvePathname(String pathname) {
if ((!pathname.startsWith("./") && !pathname.startsWith("/")) && currentDirectory.length() > 0) {
// if (!pathname.startsWith("/") && currentDirectory.length()>0){
String slash = "";
if (!currentDirectory.endsWith("/"))
slash = "/";
pathname = currentDirectory + slash + pathname;
}
while (pathname.contains("\\")) {
pathname = pathname.replace('\\', '/');
}
return pathname;
}
/**
* 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 {
Client().rm(pathname);
reply = "rm OK";
logger.info(String.format("File deleted : %1$s, reply is %2$s", pathname, getReplyString()));
}
@Override
public void login(String strUserName, String strPassword) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::login";
boolean isAuthenticated = false;
try {
gstrUser = strUserName;
logger.debug(String.format("Try to login with user '%1$s'.", strUserName));
isAuthenticated = sshConnection.authenticateWithPassword(strUserName, strPassword);
if (!isAuthenticated)
RaiseException("authentication failed");
reply = "OK";
logger.debug(String.format("user '%1$s' logged in.", strUserName));
LogReply();
}
catch (IOException e) {
e.printStackTrace();
}
LogReply();
} // private boolean login
@Override
public void disconnect() {
reply = "disconnect OK";
if (objFTPClient != null)
try {
objFTPClient.close();
objFTPClient = null;
}
catch (Exception ex) {
reply = "disconnect: " + ex;
} // gracefully ignore this error
if (sshConnection != null)
try {
sshConnection.close();
sshConnection = null;
}
catch (Exception ex) {
reply = "disconnect: " + ex;
} // gracefully ignore this error
isConnected = false;
logger.info(reply);
}
@Override
public String getReplyString() {
String strT = strReply;
return strT;
}
@Override
public boolean isConnected() {
return isConnected;
}
// @Override
// public String[] listNames(String pathname) throws IOException {
// String strA[] = Client().listNames(pathname);
// logger.debug(String.format("reply from FTP-Server is %1$s, code = %2$d", Client().getReplyString(), Client().getReplyCode()));
// return strA;
// }
@Override
public void logout() {
try {
if (isConnected() == true) {
disconnect();
logger.debug(String.format("logout from host '%1$s', reply '%2$s'", objHost.Value(), getReplyString()));
}
else {
logger.info("not connected, logout useless.");
}
}
catch (Exception e) { // no error-handling needed, due to end-of session
logger.warn("problems during logout. " + e.getMessage());
}
}
public void rename(String from, String to) {
from = resolvePathname(from);
to = resolvePathname(to);
try {
Client().mv(from, to);
}
catch (Exception e) {
reply = e.toString();
RaiseException(e, "rename failed");
}
reply = "mv OK";
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 {
notImplemented();
}
@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 {
objAO = pobjAO;
// TODO allow alternate Authentications
doAuthenticate(pobjAO);
return this;
}
private ISOSConnection doAuthenticate(ISOSAuthenticationOptions pobjAO) throws Exception {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::doAuthenticate";
boolean isAuthenticated = false;
try {
gstrUser = pobjAO.getUser().Value();
String strPW = pobjAO.getPassword().Value();
String strUserName = gstrUser;
logger.debug(String.format("Try to login with user '%1$s'.", strUserName));
if (pobjAO.getAuth_method().isPublicKey()) {
SOSOptionInFileName objAF = pobjAO.getAuth_file();
objAF.CheckMandatory(true);
if (objAF.IsNotEmpty()) {
char[] chrAFContent = objAF.JSFile().File2String().toCharArray();
isAuthenticated = sshConnection.authenticateWithPublicKey(strUserName, chrAFContent, strPW);
}
}
else {
if (pobjAO.getAuth_method().isPassword()) {
isAuthenticated = sshConnection.authenticateWithPassword(this.gstrUser, strPW);
}
else {
throw new Exception("Unknown authentication method: " + pobjAO.getAuth_method().Value());
}
}
if (!isAuthenticated) {
RaiseException("authentication failed, auth_method=" + pobjAO.getAuth_method().Value() + ", auth_file=" + pobjAO.getAuth_file().Value());
}
reply = "OK";
logger.debug(String.format("user '%1$s' logged in.", strUserName));
LogReply();
}
catch (Exception e) {
RaiseException(e, "Authentication problem");
}
finally {
}
return this;
}
@Override
public void CloseConnection() throws Exception {
if (isConnected()) {
disconnect();
logger.debug(String.format("Disconnected from host '%1$s'", objConnectionOptions.getHost().Value()));
LogReply();
}
}
private SFTPv3Client Client() {
if (objFTPClient == null) {
try {
objFTPClient = new SFTPv3Client(sshConnection);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* This listener is to write all commands and response from commands to system.out
*
*/
// this.Connect();
}
return objFTPClient;
}
@Override
public ISOSConnection Connect() {
logger.debug("Try to connect ...");
try {
this.connect(objConnectionOptions.getHost().Value(), objConnectionOptions.getPort().value());
logger.info(String.format("successful connected to Host '%1$s' at port '%1$d'.", objConnectionOptions.getHost().Value(),
objConnectionOptions.getPort().value()));
}
catch (RuntimeException e) {
if (objConnectionOptions.getalternative_host().IsNotEmpty() && objConnectionOptions.getalternative_port().IsNotEmpty()) {
logger.info("Not possible to connect to Host. Try alternate host.");
this.connect(objConnectionOptions.getalternative_host().Value(), //
objConnectionOptions.getalternative_port().value());
logger.info(String.format("successful connected to Host '%1$s' at port '%1$d'.", objConnectionOptions.getalternative_host().Value(), //
objConnectionOptions.getalternative_port().value()));
}
else {
throw e;
}
}
isConnected = true;
reply = "OK";
return this;
}
@Override
public ISOSConnection Connect(SOSConnection2OptionsAlternate pobjConnectionOptions) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::Connect";
objConnection2Options = pobjConnectionOptions;
try {
objHost = objConnection2Options.getHost();
objHost.CheckMandatory();
objPort = objConnection2Options.getport();
objPort.CheckMandatory();
host = objHost.Value();
port = objPort.value();
this.connect(objHost.Value(), objPort.value());
if (isConnected == false) {
SOSConnection2OptionsSuperClass objAlternate = objConnection2Options.Alternatives();
objHost = objAlternate.host;
objPort = objAlternate.port;
host = objHost.Value();
port = objPort.value();
logger.info(String.format("try alternate host due to connection-error ", host));
this.connect(objHost.Value(), objPort.value());
if (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) {
e.printStackTrace();
logger.error("exception occured", e);
throw new JobSchedulerException("exception occured:", e);
}
return this;
}
@Override
public ISOSConnection Connect(ISOSConnectionOptions pobjConnectionOptions) throws Exception {
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);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
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) {
if (pobjFileTransferMode.isAscii()) {
this.ascii();
logger.debug("using ASCII mode for file transfer");
logger.debug("ftp server reply [ascii]: " + getReplyString());
}
else {
this.binary();
logger.debug("using binary mode for file transfer");
logger.debug("ftp server reply [binary]: " + 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) {
if (vecDirectoryListing == null) {
vecDirectoryListing = nList(folder, withSubFolder);
}
Vector<String> strB = new Vector<String>();
Pattern pattern = Pattern.compile(regexp, 0);
for (String strFile : vecDirectoryListing) {
Matcher matcher = pattern.matcher(strFile);
if (matcher.find() == true) {
strB.add(strFile);
}
}
return strB.toArray(new String[strB.size()]);
}
@Override
public OutputStream getAppendFileStream(String strFileName) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::getAppendFileStream";
OutputStream objO = null;
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) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::getInputStream";
InputStream objI = null;
// SFTPv3FileHandle objI = getClient().openFileRO(strFileName);
return objI;
}
@Override
public String getModificationTime(String strFileName) {
String strT = "";
// TODO transform mtime to real date
// try {
// strT = Client().stat(strFileName).mtime;
// }
// catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
return strT;
}
@Override
public OutputStream getOutputStream(String strFileName) {
OutputStream objO = null;
return objO;
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public void closeInput() {
// TODO Auto-generated method stub
}
@Override
public void closeOutput() {
// TODO Auto-generated method stub
}
@Override
public void flush() {
// TODO Auto-generated method stub
}
@Override
public int read(byte[] bteBuffer) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::read";
int intL = -1;
try {
// int intMaxBuffLen = bteBuffer.length;
int intMaxBuffLen = bteBuffer.length;
// if (intMaxBuffLen > 32000) {
// intMaxBuffLen = 32000;
// }
intL = objFTPClient.read(objInputFile, lngReadOffset, bteBuffer, 0, intMaxBuffLen);
lngReadOffset += intL;
}
catch (IOException e) {
e.printStackTrace();
}
return intL;
}
@Override
public int read(byte[] bteBuffer, int intOffset, int intLength) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::read";
int intL = -1;
try {
intL = objFTPClient.read(objInputFile, lngReadOffset, bteBuffer, 0, intLength);
lngReadOffset += intL;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return intL;
}
@Override
public void write(byte[] bteBuffer, int intOffset, int intLength) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::write";
try {
objFTPClient.write(objOutputFile, lngWriteOffset, bteBuffer, 0, intLength);
lngWriteOffset += intLength;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void write(byte[] bteBuffer) {
// TODO Auto-generated method stub
}
private SFTPv3FileHandle objInputFile = null;
private long lngReadOffset = 0;
private SFTPv3FileHandle objOutputFile = null;
private long lngWriteOffset = 0;
@Override
public void openInputFile(String pstrFileName) {
try {
if (objInputFile == null || objInputFile.isClosed() == true) {
objInputFile = openFileRO(pstrFileName);
lngReadOffset = 0;
}
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void openOutputFile(String pstrFileName) {
@SuppressWarnings("unused")
final String conMethodName = conClassName + "::openOutputFile";
try {
objOutputFile = openFileWR(pstrFileName);
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Vector<ISOSVirtualFile> getFiles(String string) {
// TODO Auto-generated method stub
return null;
}
@Override
public Vector<ISOSVirtualFile> getFiles() {
// TODO Auto-generated method stub
return null;
}
public void putFile(ISOSVirtualFile objVirtualFile) {
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();
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) {
throw new JobSchedulerException("putfile reports exception", e);
}
finally {
}
}
@Override
public void ControlEncoding(String pstrControlEncoding) {
}
}