title: Apache Commons Net FTPClient abort file store
body: <p>I'm developing an applet to allow FTP upload from a webapp...</p>
  
  <p>The send operation is working fine, but I'd like to able to cancel a file storing in progress.</p>
  
  <p>I'm not very fluent with threads. My first attempt was to call ftp.abort() in the cancel thread, but the abort method was only called when the storeFile method finished, like if the send thread was locking the ftp object.</p>
  
  <p>So I changed the code to interrupt the send thread and check it in the copy stream listener. The file storing stops as expected, but ftp.abort() call hangs the application, it never complete.</p>
  
  <p>Any ideas?</p>
  
  <p>Thanks,
  Philip</p>
  
  <p><strong>Send operation:</strong></p>
  
  <pre><code>  botaoEnviar.setEnabled(false);
    botaoCancelar.setEnabled(true);
    textField.requestFocus();
  
    threadEnvio = new Thread(new Runnable()
    {
       @Override
       public void run()
       {            
          FileInputStream fis = null;
          try
          {
             if(arquivoSelecionado == null)
             {
                throw new IllegalArgumentException("Arquivo deve ser informado");
             }
  
             try
             {
                ftp = new FTPClient();
                ftp.connect("192.168.1.243");
             }
             catch(Exception e)
             {
                throw new FtpConnectionException("Não foi possível conectar no servidor FTP", e);
             }
  
             if(!ftp.login("c001", "0AJF2J36"))
             {
                throw new IllegalArgumentException("Não foi possível autenticar no servidor FTP");
             }
  
             ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
  
             ftp.setCopyStreamListener(new CopyStreamAdapter()
             {                  
                @Override
                public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize)
                {
                   if(threadEnvio.isInterrupted())
                   {
                      try
                      {
                         ftp.abort();                           
                      }
                      catch(IOException ex)
                      {
                         handleException(ex);
                      }
                   }
                   else
                   {
                      int percent = (int) (totalBytesTransferred * 100 / arquivoSelecionado.length());
                      progressBar.setValue(percent);
                   }
                }
             });
  
             fis = new FileInputStream(arquivoSelecionado);               
             if(ftp.storeFile(arquivoSelecionado.getName(), fis))
             {
                JOptionPane.showMessageDialog(null, "Arquivo enviado com suceso");
             }
             else
             {
                JOptionPane.showMessageDialog(null, "Não foi possível enviar o arquivo", "Erro", JOptionPane.ERROR_MESSAGE);
             }
  
             ftp.logout();
          }            
          catch(Exception e)
          {
             handleException(e);
          }
          finally
          {
             if(fis != null)
             {
                try
                {
                   fis.close();
                }
                catch(IOException ex)
                {
                   handleException(ex);
                }
             }
  
             if(ftp != null)
             {
                try
                {
                   ftp.disconnect();
                }
                catch(IOException ex)
                {
                   handleException(ex);
                }
             }
  
             progressBar.setValue(0);
             botaoEnviar.setEnabled(true);               
             botaoCancelar.setEnabled(false);               
          }
       }
    });
    threadEnvio.start();
  </code></pre>
  
  <p><strong>Cancel operation:</strong></p>
  
  <pre><code>botaoCancelar.setEnabled(false);
  
    new Thread(new Runnable()
    {
       @Override
       public void run()
       {
          try
          {               
             threadEnvio.interrupt();
          }
          catch(Exception ex)
          {
             handleException(ex);
          }
          finally
          {
             botaoCancelar.setEnabled(true);               
          }
       }
  
    }).start();
  </code></pre>