package com.rectang.xsm.io;
import java.io.*;
import java.util.Hashtable;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import com.rectang.xsm.XSM;
import com.rectang.xsm.site.Site;
public class FtpPublishedFile
extends PublishedFile
{
private static int TIMEOUT = 60000;
public FtpPublishedFile( Site site, String fileName )
{
super( site, fileName );
}
public OutputStream getOutputStream()
throws IOException
{
File tmp = XSM.getTempFile();
return new OutputStreamWrapper( tmp );
}
public String toString()
{
return "Ftp file: " + getSite().getRemoteHost() + ":" + file;
}
public boolean exists()
{
return exists( file );
}
private boolean exists( String f )
{
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
Object[] ret = ftpChannel.listNames( f );
return ret != null && ret.length > 0;
}
catch ( Exception e )
{
e.printStackTrace();
}
return false;
}
public boolean mkparentdirs()
{
String parent = (new File( file )).getParentFile().getPath();
return mkdir( parent ); /* this checks for existance */
}
public boolean mkdir()
{
return mkdir( file );
}
private boolean mkdir( String f )
{
if ( exists( f ) )
{
return true;
}
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
File parentFile = (new File( f )).getParentFile();
if ( parentFile != null )
{
String parent = parentFile.getPath();
mkdir( parent ); /* this checks for existance */
}
return ftpChannel.makeDirectory( f );
}
catch ( IOException e )
{
e.printStackTrace();
}
return false;
}
public boolean delete()
{
return deleteDir( file );
}
private boolean delete( String rmFile )
{
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
ftpChannel.deleteFile( rmFile );
return true;
}
catch ( IOException e )
{
e.printStackTrace();
}
return false;
}
private boolean deleteDir( String path )
{
FTPClient ftpChannel = getFTPChannel( getSite() );
if ( !exists( path ) )
{
return true;
}
String[] files = null;
try
{
files = ftpChannel.listNames( path );
}
catch ( Exception e )
{
/* fall through to deleting the path */
}
if ( files != null && files.length != 0 )
{
for ( int i = 0; i < files.length; i++ )
{
String next = files[i].trim();
int pos = next.lastIndexOf( ' ' );
String name = next.substring( pos + 1 );
if ( name.equals( "." ) || name.equals( ".." ) )
{
continue;
}
String subPath = path + "/" + name;
if ( isDirectory( subPath ) )
{
deleteDir( subPath );
}
else
{
delete( subPath );
}
}
}
return delete( path );
}
public boolean isDirectory()
{
return isDirectory( file );
}
private boolean isDirectory( String path )
{
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
String[] list = ftpChannel.listNames( path );
if ( list == null || (list.length == 1 /* 1 entry for non-directory */
&& list[0].trim().endsWith( /* if 1 entry make sure it is a file */
((new File( path )).getParentFile().getName()) )) )
{
return false;
}
return true;
}
catch ( Exception e )
{
return false;
}
}
public long length()
{
return length( file );
}
private long length( String path )
{
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
FTPFile[] list = ftpChannel.listFiles( path );
if ( list == null || (list.length < 1) )
{
return 0;
}
return list[0].getSize();
}
catch ( Exception e )
{
return 0;
}
}
public boolean rename( String newName )
{
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
String oldPath = file;
setFile( newName );
mkparentdirs();
ftpChannel.rename( oldPath, file );
return true;
}
catch ( IOException e )
{
e.printStackTrace();
}
return false;
}
public void uploadFile( File f )
{
uploadFile( f, true );
}
public void uploadFile( File f, boolean delete )
{
try
{
if ( !f.exists() )
{
return;
}
mkparentdirs();
FTPClient ftpChannel = getFTPChannel( getSite() );
try
{
FileInputStream fis = new FileInputStream( f );
ftpChannel.storeFile( file, fis );
fis.close();
if ( delete )
{
f.delete();
}
}
catch ( IOException e )
{
e.printStackTrace();
}
}
catch ( Exception io )
{
io.printStackTrace();
}
}
class OutputStreamWrapper
extends FileOutputStream
{
private File f;
public OutputStreamWrapper( File f )
throws IOException
{
super( f );
this.f = f;
}
public void close()
throws IOException
{
super.close();
uploadFile( f, true );
}
}
private static Hashtable channelHash = new Hashtable();
public static FTPClient getFTPChannel( Site site )
{
TimeoutChannel chan = (TimeoutChannel) channelHash.get( site );
if ( chan != null )
{
if ( chan.timeout < System.currentTimeMillis() )
{
try
{
chan.channel.disconnect();
chan.channel.quit();
}
catch ( Exception e )
{
/* we ignore these */
}
chan = null;
}
}
if ( chan == null )
{
try
{
FTPClient cli = new FTPClient();
cli.connect( site.getRemoteHost() );
cli.login( site.getRemoteUser(), site.getRemotePassword() );
cli.enterLocalPassiveMode();
cli.setFileType( org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE );
chan = new TimeoutChannel( cli, System.currentTimeMillis() + TIMEOUT );
channelHash.put( site, chan );
}
catch ( Exception e )
{
e.printStackTrace();
return null;
}
}
return chan.channel;
}
private static class TimeoutChannel
{
protected long timeout;
protected FTPClient channel;
public TimeoutChannel( FTPClient chan, long time )
{
this.channel = chan;
this.timeout = time;
}
}
}