Hello List,
i'm using VFS to regulary check some files on an FTP server. This works fine 
for a long time, but after a while the check crashes with the following 
stacktrace:

org.apache.commons.vfs.FileSystemException: Could not determine the type of 
file ftp://user:[EMAIL PROTECTED]/myfile.txt.
        at 
org.apache.commons.vfs.provider.AbstractFileObject.attach()V(Optimized Method)
        at 
org.apache.commons.vfs.provider.AbstractFileObject.exists()Z(AbstractFileObject.java:391)
        at my.class.Something.toDo(Unknown Source)
        at java.lang.Thread.run()V(Unknown Source)
        at java.lang.Thread.startThreadFromVM(Ljava.lang.Thread;)V(Unknown 
Source)
Caused by: java.net.SocketException: Broken pipe
        at jrockit.net.SocketNativeIO.write(IIIZ)I(Unknown Source)
        at jrockit.net.SocketNativeIO.write(III)I(Unknown Source)
        at jrockit.io.NativeIO.write(Ljava.io.FileDescriptor;II)I(Optimized 
Method)
        at java.net.AbstractSocketImpl$2.write(II)V(Optimized Method)
        at jrockit.io.NativeIOOutputStream.write([BII)V(Optimized Method)
        at java.io.BufferedOutputStream.flushBuffer()V(Optimized Method)
        at java.io.BufferedOutputStream.write(I)V(Optimized Method)
        at org.apache.commons.net.telnet.Telnet._sendByte(I)V(Optimized Method)
        at org.apache.commons.net.telnet.TelnetOutputStream.write(I)V(Optimized 
Method)
        at 
org.apache.commons.net.io.ToNetASCIIOutputStream.write([BII)V(Optimized Method)
        at 
sun.nio.cs.StreamEncoder$CharsetSE.writeBytes()V(StreamEncoder.java:325)
        at sun.nio.cs.StreamEncoder$CharsetSE.implWrite([CII)V(Optimized Method)
        at sun.nio.cs.StreamEncoder.write([CII)V(StreamEncoder.java:136)
        at java.io.OutputStreamWriter.write([CII)V(OutputStreamWriter.java:191)
        at java.io.BufferedWriter.flushBuffer()V(BufferedWriter.java:107)
        at java.io.BufferedWriter.flush()V(BufferedWriter.java:228)
        at 
org.apache.commons.net.ftp.FTP.sendCommand(Ljava.lang.String;Ljava.lang.String;)I(Optimized
 Method)
        at 
org.apache.commons.net.ftp.FTP.sendCommand(ILjava.lang.String;)I(Optimized 
Method)
        at 
org.apache.commons.net.ftp.FTP.port(Ljava.net.InetAddress;I)I(Optimized Method)
        at 
org.apache.commons.vfs.provider.ftp.FTPClientWrapper.listFiles(Ljava.lang.String;Ljava.lang.String;)[Lorg.apache.commons.net.ftp.FTPFile;(Optimized
 Method)
        at 
org.apache.commons.vfs.provider.ftp.FtpFileObject.doGetChildren()V(Optimized 
Method)
        at 
org.apache.commons.vfs.provider.ftp.FtpFileObject.getChildFile(Ljava.lang.String;Z)Lorg.apache.commons.net.ftp.FTPFile;(Optimized
 Method)
        at 
org.apache.commons.vfs.provider.ftp.FtpFileObject.getInfo(Z)V(Optimized Method)
        at 
org.apache.commons.vfs.provider.ftp.FtpFileObject.doAttach()V(Optimized Method)
        ... 6 more

When it comes to that error, the filesystem provider never recovers from that 
crash and all actions on files on the same ftp server fail. The ftp server 
works fine, i can connect fine from the commandline. it seems that the VFS ftp 
provider tries to reuse that old damaged connection, i don't see a new attempt 
to login in my ftp server log. There is no connection from VFS to the ftp 
server.

I looked in the source code of FTPClientWrapper, and tracked the error down to 
the listFiles function:

...
    public FTPFile[] listFiles(String key, String relPath) throws IOException
    {
        try
        {
            return getFtpClient().listFiles(key, relPath);
        }
        catch (FTPConnectionClosedException e)
        {
            disconnect();
            return getFtpClient().listFiles(key, relPath);
        }
    }
...

the FTPClient of commons.net throws FTPConnectionClosedException and 
IOException. if a FTPConnectionClosedException is thrown everything is fine, 
the old connection is closed and a new one is created. If a more general 
IOException is thrown the connection is not closed and not set to null, so the 
FTPClientWrapper tries to use it again. Normally isConnected() should fail 
then, but it seems that it still returns true und is a weak test. I suggest 
that the connection should also be disconnected and set to null on more general 
errors, if there is an IOException there is a big chance that the connection is 
not usable anymore.

Maybe like this:

    public FTPFile[] listFiles(String key, String relPath) throws IOException
    {
        try
        {
            return getFtpClient().listFiles(key, relPath);
        }
        catch (FTPConnectionClosedException e)
        {
            disconnect();
            return getFtpClient().listFiles(key, relPath);
        }
        catch (IOException ie)
        {
            disconnect();
            throw ie;
        }
    }

This fix should be applied to all functions in FTPClientWrapper

Maybe you have a better approach on fixing this issue ?

Reply via email to