FTP to SFTP.
843790Aug 6 2008 — edited Aug 6 2008Hi,
My application is using ftp to connect to the server. but now it is going to change to sftp. For that I am not able to get what are the things in need to change in my ftp program to make it support for sftp. The following is the ftpbean class and the methods of the class are used by other classes. sftp is already installed and the environment is ready now. but I am not able to proceed where to modify the java..Please help.
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.StringTokenizer;
import java.util.Vector;
public class FtpBean
{
private String server = ""; // server name
private String user = ""; // user name
private String replyMessage = ""; // reply message from server
private String reply = ""; // reply to the command
private Socket socket; // Socket for FTP connection
private BufferedReader in; // Input for FTP connection
private PrintWriter out; // Output for FTP connection
private int port = 21; // FTP port number, default 21
private boolean passive = true; // Passive mode transfer, default true
// Needed for thread safety
private int[] lock = new int[0]; // For synchronized locking
private boolean acquired = false; // Count the number of acquire
private Vector threadSpool = new Vector(); // Spool for the waiting threads
// Needed for some Visual tools
private PropertyChangeSupport pcs; // PropertyChangeSupport for visual tools
final private boolean DEBUG = false; // True to turn on debug mode
/**
* Constructor
*/
public FtpBean()
{
pcs = new PropertyChangeSupport(this);
}
/*
* Add PropertyChangeListener
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
pcs.addPropertyChangeListener(listener);
}
/*
* removePropertyChangeListener
*/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
pcs.removePropertyChangeListener(listener);
}
/**
* Connect to FTP server and login.
* @param server Name of server
* @param user User name for login
* @param password Password for login
* @exception FtpException if a ftp error occur (eg. Login fail in this case).
* @exception IOException if an I/O error occur
*/
public void ftpConnect(String server, String user, String password)
throws IOException, FtpException
{
if (DEBUG) // Debug message
System.out.println("FtpBean: Connecting to server " + server);
acquire(); // Acquire the object
// Set server name & user name
setServerName(server);
setUserName(user);
try {
// Create socket, get input & output stream
socket = new Socket(server, port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Read reply code when get connected
getRespond();
if (DEBUG) // Debug message
System.out.println("FtpBean: Connected");
// Login
ftpLogin(user, password); // check if login success
}
finally {
release(); // Release the object
}
}
/**
* Close FTP connection.
* @exception IOException if an I/O error occur
* @exception FtpException if a ftp error occur
*/
public void close()
throws IOException, FtpException
{
if (out == null)
return;
acquire(); // Acquire the object
try {
ftpCommand("QUIT");
if (!reply.startsWith("221"))
throw new FtpException(reply);
closeSocket();
// Set server name & user name to ""
setServerName("");
setUserName("");
}
finally {
release(); // Release the object
}
}
/**
* Delete a file at the FTP server.
* @param filename Name of the file to be deleted.
* @exception FtpException if a ftp error occur. (eg. no such file in this case)
* @exception IOException if an I/O error occur.
*/
public void fileDelete(String fileName)
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("DELE " + fileName);
if (!reply.startsWith("250"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
/**
* Rename a file at the FTP server.
* @param oldFileName The name of the file to be renamed
* @param newFileName The new name of the file
* @exception FtpException if a ftp error occur. (eg. A file named the new file name already in this case.)
* @exception IOException if an I/O error occur.
*/
public void fileRename(String oldFileName, String newFileName)
throws IOException, FtpException
{
acquire(); // Acquire this object
try {
ftpCommand("RNFR " + oldFileName);
if (!reply.startsWith("350"))
throw new FtpException(reply);
ftpCommand("RNTO " + newFileName);
if (!reply.startsWith("250"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
private boolean isSameSystem()
throws IOException, FtpException
{
String sysType = getSystemType();
return (sysType.toUpperCase().indexOf("WINDOWS") < 0);
}
/**
* @param ftpFile Name of file to be get from the ftp server, can be in full path.
* @param localFile File name of local file
* @exception FtpException if a ftp error occur. (eg. No such file in this case)
* @exception IOException if an I/O error occur.
* @see FtpObserver
*/
public void getAsciiFile(String ftpFile, String localFile)
throws IOException, FtpException
{
getAsciiFile(ftpFile, localFile, null);
}
/**
* @param ftpFile Name of file to be get from the ftp server, can be in full path.
* @param localFile File name of local file
* @param observer The FtpObserver which monitor this downloading progress
* @exception FtpException if a ftp error occur. (eg. No such file in this case)
* @exception IOException if an I/O error occur.
* @see FtpObserver
*/
public void getAsciiFile(String ftpFile, String localFile, FtpObserver observer)
throws IOException, FtpException
{
if (isSameSystem()) {
getBinaryFile(ftpFile, localFile, observer);
return;
}
acquire(); // Acquire the object
setTransferType(true); // Set transfer type to ascii
Socket sock = null;
try {
sock = getDataSocket("RETR " + ftpFile, 0);
// Read bytes from server and write to file.
BufferedReader din = new BufferedReader(new InputStreamReader(sock.getInputStream()));
PrintWriter dout = new PrintWriter(new BufferedWriter(new FileWriter(localFile)));
/*
char[] cbuf = new char[2048];
int n;
while ((n = din.read(cbuf, 0, cbuf.length)) != -1) {
if (skipLineSepFilter())
dout.write(cbuf, 0, n);
else {
// filter DOS line-sep to UNIX line-sep
String data = filterLineSep(cbuf, n);
dout.write(data, 0, data.length());
}
if (observer != null)
observer.byteRead(n);
}
*/
String data = null;
while ((data = din.readLine()) != null) {
dout.println(data);
if (observer != null)
observer.byteRead(data.length() + 1);
}
din.close();
dout.close();
sock.close();
getRespond();
if (!reply.startsWith("226"))
throw new FtpException(reply); // transfer incomplete
}
finally {
release(); // Release the object
}
}
public void putAsciiFile(String localFile, String remoteFile, FtpObserver observer)
throws IOException, FtpException
{
acquire(); // Acquire the object
setTransferType(true);
// if file is to be transferred to MF, without slash, exec quote site cmd
if (!remoteFile.startsWith("/"))
setQuoteSite();
Socket sock = null;
try {
// Read bytes from local file and write to a server.
BufferedReader din = new BufferedReader(new FileReader(localFile));
sock = getDataSocket("STOR " + remoteFile, 0);
PrintWriter dout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())));
String data = null;
while ((data = din.readLine()) != null) {
//dout.println(data);
dout.write(data);
dout.write("\r\n");
if (observer != null)
observer.byteWrite(data.length() + 1);
}
din.close();
dout.close();
sock.close();
getRespond();
if (DEBUG) // Debug message
System.out.println("FtpBean: Reply is " + reply);
/*
putAsciiFile()
Changed manner of checking if transfer is complete by checking the
string Transfer Complete in the reply.
For UNIX: Reply is 226 Transfer complete.
For MF: Reply is 250 Transfer completed successfully.
*/
//if (!reply.startsWith("226"))
int m = 0;
if ((m = reply.indexOf("Transfer complete")) < 0)
throw new FtpException(reply); // transfer incomplete
}
finally {
release(); // Release the object
}
}
/**
* Read file from ftp server and write to a file in local hard disk.
* This method is much faster than those method which return a byte array<br>
* if the network is fast enough.<br>
* <br>Remark:<br>
* Cannot be used in unsigned applet.
* @param ftpFile Name of file to be get from the ftp server, can be in full path.
* @param localFile Name of local file to be write, can be in full path.
* @exception FtpException if a ftp error occur. (eg. No such file in this case)
* @exception IOException if an I/O error occur.
*/
public void getBinaryFile(String ftpFile, String localFile)
throws IOException, FtpException
{
getBinaryFile(ftpFile, localFile, 0, null);
}
/**
* Read file from ftp server and write to a file in local hard disk.
* This method is much faster than those method which return a byte array<br>
* if the network is fast enough.<br>
* <br>Remark:<br>
* Cannot be used in unsigned applet.
* @param ftpFile Name of file to be get from the ftp server, can be in full path.
* @param localFile Name of local file to be write, can be in full path.
* @param restart Restarting point
* @exception FtpException if a ftp error occur. (eg. No such file in this case)
* @exception IOException if an I/O error occur.
*/
public void getBinaryFile(String ftpFile, String localFile, long restart)
throws IOException, FtpException
{
getBinaryFile(ftpFile, localFile, restart, null);
}
/**
* Read file from ftp server and write to a file in local hard disk.
* This method is much faster than those method which return a byte array<br>
* if the network is fast enough.<br>
* <br>Remark:<br>
* Cannot be used in unsigned applet.
* @param ftpFile Name of file to be get from the ftp server, can be in full path.
* @param localFile Name of local file to be write, can be in full path.
* @param observer The FtpObserver which monitor this downloading progress
* @exception FtpException if a ftp error occur. (eg. No such file in this case)
* @exception IOException if an I/O error occur.
* @see FtpObserver
*/
public void getBinaryFile(String ftpFile, String localFile, FtpObserver observer)
throws IOException, FtpException
{
getBinaryFile(ftpFile, localFile, 0, observer);
}
/**
* Read from a ftp file and restart at a specific point.
* This method is much faster than those method which return a byte array<br>
* if the network is fast enough.<br>
* Remark:<br>
* Cannot be used in unsigned applet.
* @param ftpFile Name of file to be get from the ftp server, can be in full path.
* @param localFile File name of local file
* @param restart Restarting point, ignored if equal or less than zero.
* @param observer The FtpObserver which monitor this downloading progress
* @exception FtpException if a ftp error occur. (eg. No such file in this case)
* @exception IOException if an I/O error occur.
* @see FtpObserver
*/
public void getBinaryFile(String ftpFile, String localFile, long restart, FtpObserver observer)
throws IOException, FtpException
{
acquire(); // Acquire the object
setTransferType(false); // Set transfer type to binary
Socket sock = null;
try {
sock = getDataSocket("RETR " + ftpFile, restart);
// Read bytes from server and write to file.
BufferedInputStream din = new BufferedInputStream(sock.getInputStream());
RandomAccessFile dout = new RandomAccessFile(localFile, "rw");
dout.seek(restart);
byte[] data = new byte[1024];
int n;
while ((n = din.read(data)) != -1) {
dout.write(data, 0, n);
if (observer != null)
observer.byteRead(n);
}
din.close();
dout.close();
sock.close();
getRespond();
if (!reply.startsWith("226"))
throw new FtpException(reply); // transfer incomplete
}
finally {
release(); // Release the object
}
}
/**
* Read a file from local hard disk and write to the server.
* <br>Remark:<br>
* <br>Cannot be used in unsigned applet.
* @param local_file Name of local file, can be in full path.
* @param remoteFile Name of file in the ftp server, can be in full path.
* @exception FtpException if a ftp error occur. (eg. permission denied)
* @exception IOException if an I/O error occur.
*/
public void putBinaryFile(String localFile, String remoteFile)
throws IOException, FtpException
{
putBinaryFile(localFile, remoteFile, 0, null);
}
/**
* Read a file from local hard disk and write to the server.
* <br>Remark:<br>
* <br>Cannot be used in unsigned applet.
* @param localFile Name of local file, can be in full path.
* @param remoteFile Name of file in the ftp server, can be in full path.
* @param observer The FtpObserver which monitor this uploading progress.
* @exception FtpException if a ftp error occur. (eg. permission denied)
* @exception IOException if an I/O error occur.
*/
public void putBinaryFile(String localFile, String remoteFile, FtpObserver observer)
throws IOException, FtpException
{
putBinaryFile(localFile, remoteFile, 0, observer);
}
/**
* Read a file from local hard disk and write to the server with restarting point.
* Remark:<br>
* Cannot be used in unsigned applet.
* @param localFile Name of local file, can be in full path.
* @param remoteFile Name of file in the ftp server, can be in full path.
* @param restart The restarting point, ignored if less than or greater than zero.
* @exception FtpException if a ftp error occur. (eg. permission denied)
* @exception IOException if an I/O error occur.
*/
public void putBinaryFile(String localFile, String remoteFile, long restart)
throws IOException, FtpException
{
putBinaryFile(localFile, remoteFile, restart, null);
}
/**
* Read a file from local hard disk and write to the server with restarting point.
* Remark:<br>
* Cannot be used in unsigned applet.
* @param localFile Name of local file, can be in full path.
* @param remoteFile Name of file in the ftp server, can be in full path.
* @param observer The FtpObserver which monitor this uploading progress
* @exception FtpException if a ftp error occur. (eg. permission denied)
* @exception IOException if an I/O error occur.
*/
public void putBinaryFile(String localFile, String remoteFile, long restart, FtpObserver observer)
throws IOException, FtpException
{
acquire(); // Acquire the object
setTransferType(false);
Socket sock = null;
try {
RandomAccessFile din = new RandomAccessFile(localFile, "r");
sock = getDataSocket("STOR " + remoteFile, restart);
if (restart > 0)
din.seek(restart);
DataOutputStream dout = new DataOutputStream(sock.getOutputStream());
byte[] data = new byte[1024];
int n;
while ((n = din.read(data)) != -1) {
dout.write(data, 0, n);
if (observer != null)
observer.byteWrite(n);
}
din.close();
dout.close();
sock.close();
getRespond();
/*
putBinaryFile()
Changed manner of checking if transfer is complete by checking the
string Transfer Complete in the reply.
For UNIX: Reply is 226 Transfer complete.
For MF: Reply is 250 Transfer completed successfully.
*/
//if (!reply.startsWith("226"))
int m = 0;
if ((m = reply.indexOf("Transfer complete")) < 0)
throw new FtpException(reply); // transfer incomplete
}
finally {
release(); // Release the object
}
}
/**
* Get current directory name.
* @return The name of the current directory.
* @exception FtpException if a ftp error occur.
* @exception IOException if an I/O error occur.
*/
public String getDirectory()
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("PWD");
if (!reply.startsWith("257"))
throw new FtpException(reply);
int first = reply.indexOf("\"");
int last = reply.lastIndexOf("\"");
return reply.substring(first + 1, last);
}
finally {
release(); // Release the object
}
}
/**
* Change directory.
* @param directory Name of directory
* @exception FtpException if a ftp error occur. (eg. permission denied in this case)
* @exception IOException if an I/O error occur.
*/
public void setDirectory(String directory)
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("CWD " + directory);
if (!reply.startsWith("250"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
/**
* Change to parent directory.
* @exception FtpException if a ftp error occur. (eg. permission denied in this case)
* @exception IOException if an I/O error occur.
*/
public void toParentDirectory()
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("CDUP");
if (!reply.startsWith("250"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
/**
* Get the content of current directory
* @return A FtpListResult object, return null if it is not connected.
* @exception FtpException if a ftp error occur. (eg. permission denied in this case)
* @exception IOException if an I/O error occur.
* @see FtpListResult
*/
public FtpListResult getDirectoryContent()
throws IOException, FtpException
{
String strList = getDirectoryContentAsString();
FtpListResult ftpList = new FtpListResult();
ftpList.parseList(strList, getSystemType());
return ftpList;
}
/**
* Get the content of current directory.
* @return A list of directories, files and links in the current directory.
* @exception FtpException if a ftp error occur. (eg. permission denied in this case)
* @exception IOException if an I/O error occur.
*/
public String getDirectoryContentAsString()
throws IOException, FtpException
{
StringBuffer list = new StringBuffer(""); // Directory list
Socket sock = null; // Socket to establish data connection
acquire(); // Acquire the object
try {
// get DataSocket for the LIST command.
// As no restarting point, send 0.
sock = getDataSocket("LIST", 0);
BufferedReader din = new BufferedReader(new InputStreamReader(sock.getInputStream()));
// Read bytes from server.
String line;
while ((line = din.readLine()) != null)
list.append(line).append("\n");
din.close();
sock.close();
getRespond();
if (!reply.startsWith("226"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
return list.toString();
}
/**
* Make a directory in the server.
* @param directory The name of directory to be made.
* @exception FtpException if a ftp error occur. (eg. permission denied in this case)
* @exception IOException if an I/O error occur.
*/
public void makeDirectory(String directory)
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("MKD " + directory);
if (!reply.startsWith("257"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
/**
* Remove a directory in the server
* @param directory The name of directory to be removed
* @exception FtpException if a ftp error occur. (eg. permission denied in this case)
* @exception IOException if an I/O error occur.
*/
public void removeDirectory(String directory)
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("RMD " + directory);
if (!reply.startsWith("250"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
/**
* Execute a command using ftp.
* e.g. chmod 700 file
* @param exec The command to execute.
* @exception FtpException if a ftp error occur. (eg. command not understood)
* @exception IOException if an I/O error occur.
*/
public void execute(String exec)
throws IOException, FtpException
{
acquire(); // Acquire the object
try {
ftpCommand("SITE " + exec);
if (!reply.startsWith("200"))
throw new FtpException(reply);
}
finally {
release(); // Release the object
}
}
private String _ftpSystemType = null;
/**
* Get the type of operating system of the server.
* Return null if it is not currently connected to any ftp server.
* @return Name of the operating system.
*/
public String getSystemType()
throws IOException, FtpException
{
if (_ftpSystemType != null)
return _ftpSystemType;
acquire(); // Acquire the object
try {
ftpCommand("SYST");
if (!reply.startsWith("215"))
throw new FtpException(reply);
_ftpSystemType = reply.substring(4);
return _ftpSystemType;
}
finally {
release(); // Release the object
}
}
/**
* Return the port number
*/
public int getPort()
{
return port;
}
/**
* Set port number if the port number of ftp is not 21
*/
public void setPort(int port)
{
acquire(); // Acquire the object
pcs.firePropertyChange("port", new Integer(this.port), new Integer(port));
this.port = port;
release(); // Release the object
}
/**
* Return the server name. Return "" if it is not connected to any server.
*/
public String getServerName()
{
return server;
}
/**
* Return the user name. Return "" if it is not connected to any server.
*/
public String getUserName()
{
return user;
}
/**
* Get reply of the last command.
* @return Reply of the last comomand<br>for example: 250 CWD command successful
*/
public String getReply()
{
return reply;
}
/**
* Get reply message of the last command.
* @return Reply message of the last command<br>for example:<br>
* 250-Please read the file README<br>
* 250-it was last modified on Wed Feb 10 21:51:00 1999 - 268 days ago
*/
public String getReplyMessage()
{
return replyMessage;
}
/**
* Return true if it is using passive transfer mode.
*/
public boolean isPassiveModeTransfer()
{
return passive;
}
/**
* Set passive transfer mode. Default is true.
* @param passive Using passive transfer if true.
*/
public void setPassiveModeTransfer(boolean passive)
{
acquire(); // Acquire the object
pcs.firePropertyChange("passiveModeTransfer", new Boolean(this.passive), new Boolean(passive));
this.passive = passive;
if (DEBUG) // debug message
System.out.println("FtpBean: Set passive transfer - " + passive);
release(); // Release the object
}
/*
* Close the Socket, input and output stream
*/
private void closeSocket()
throws IOException
{
_ftpSystemType = null;
in.close();
out.close();
socket.close();
in = null;
out = null;
socket = null;
}
/*
* Read the respond message from the server's inputstream and assign to replyMessage
*/
private void getRespond()
throws IOException
{
String line = "";
String replyMessage = "";
while (true) {
// Problem.....
line = in.readLine();
if (!checkReply(line))
break;
replyMessage = replyMessage.concat(line).concat("\n");
}
setReplyMessage(replyMessage);
setReply(line);
}
/*
* Login to server, using FTP commands "USER" and "PASS"
* @param user FTP username
* @param password FTP Password
*/
private void ftpLogin(String user, String password)
throws IOException, FtpException
{
ftpCommand("USER " + user); // send user name
ftpCommand("PASS " + password); // send password
if (!reply.startsWith("230")) {
closeSocket();
throw new FtpException(reply);
}
}
/*
* Send FTP command to the server.
* @param command The command to be sent
*/
private void ftpCommand(String command)
throws IOException
{
if (DEBUG) { // Debug message
if (command.startsWith("PASS"))
System.out.println("FtpBean: Send password");
else
System.out.println("FtpBean: Send command \"" + command + "\"");
}
out.print(command + "\r\n"); // Send command
out.flush();
getRespond();
}
/*
* Establish data connection for transfer
*/
private Socket getDataSocket(String command, long restart)
throws IOException, FtpException
{
Socket sock = null;
ServerSocket ssock = null;
// Establish data conncetion using passive or active mode.
if (passive)
sock = getPassiveDataSocket();
else
ssock = getActiveDataSocket();
// Send the restart command if it is greater than zero
if (restart > 0) {
ftpCommand("REST " + restart);
if (!reply.startsWith("350"))
throw new FtpException(reply);
}
// Send commands like LIST, RETR and STOR
// These commands will return 125 or 150 when success.
ftpCommand(command);
if (!(reply.startsWith("125") || reply.startsWith("150")))
throw new FtpException(reply); // command file
// Get Socket object for active mode.
if (!passive)
sock = ssock.accept();
return sock;
}
/*
* Establish data connection in passive mode using "PASV" command
* Change the server to passive mode.
* by the command "PASV", it will return its address
* and port number that it will listen to.
* Create a Socket object to that address and port number.
* Then return the Socket object.
*/
private Socket getPassiveDataSocket()
throws IOException, FtpException
{
ftpCommand("PASV");
if (!reply.startsWith("227"))
throw new FtpException(reply);
// array that holds the outputed address and port number.
String[] address = new String[6];
// put the 'reply' to the array 'address'
StringTokenizer t = new StringTokenizer(reply, ",");
for (int i = 0; i < 6; i++)
address[i] = t.nextToken();
// Get port number.
// Erase all other characters except the port number
// which is at the beginning of the string
String lastPort = "";
int num = 3;
if (address[5].length() < 3)
num = address[5].length();
for (int i = 0; i < num; i++) {
if (Character.isDigit(address[5].charAt(i)))
lastPort = lastPort + address[5].charAt(i);
}
// assign last port number to address[5]
address[5] = lastPort;
// Get the port number
// Left shift the first number by 8
int newPort = (Integer.parseInt(address[4]) << 8) + Integer.parseInt(address[5]);
// Create a new socket object
Socket sock = new Socket(getServerName(), newPort);
return sock;
}
/*
* Establish data connection in active mode using "PORT" command.
* It create a ServerSocket object to listen for a port number in local machine.
* Use port command to tell the server which port the local machine is listenning.
* Return the ServerSocket object.
*/
private ServerSocket getActiveDataSocket()
throws IOException, FtpException
{
int[] portNumbers = new int[6]; // Array that contains
// Get ip address of local machine. ip address and port numbers
String localAddr = socket.getLocalAddress().getHostAddress();
// Assign the ip address of local machine to the array.
StringTokenizer st = new StringTokenizer(localAddr, ".");
for (int i = 0; i < 4; i++)
portNumbers[i] = Integer.parseInt(st.nextToken());
ServerSocket ssocket = new ServerSocket(0); // ServerSocket to listen to a random free port number
int localPort = ssocket.getLocalPort(); // The port number it is listenning to
// Assign port numbers the array
portNumbers[4] = ((localPort & 0xff00) >> 8);
portNumbers[5] = (localPort & 0x00ff);
// Send "PORT" command to s