com.hfg.util.io.FTPFileObj Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.util.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import com.hfg.security.LoginCredentials;
import com.hfg.units.TimeUnit;
//------------------------------------------------------------------------------
/**
* Implementation of FileObj for FTP files
*
* This class depends on Jakarta's commons-net library.
*
* @author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
public class FTPFileObj extends FileObjImpl
{
//###########################################################################
// PRIVATE FIELDS
//###########################################################################
private URL mURL;
private FTPClient mFTP;
private String mFTPServer;
private FTPFile mFTPFile;
private String mParentDirPath;
private String mName;
private String mRequestedFilePath;
private LoginCredentials mCredentials = sDefaultCredentials;
private int mFileTransferMode = sDefaultFileTransferMode;
private static final int sDefaultFileTransferMode = FTP.BINARY_FILE_TYPE;
private static LoginCredentials sDefaultCredentials = new LoginCredentials("anonymous", getUserAtHostPassword().toCharArray());
private static final String SCHEME = "ftp";
//###########################################################################
// CONSTRUCTORS
//###########################################################################
//---------------------------------------------------------------------------
public FTPFileObj(String inURL)
throws MalformedURLException
{
this(new URL(inURL));
}
//---------------------------------------------------------------------------
public FTPFileObj(URI inURI)
throws MalformedURLException
{
this(inURI.toURL());
}
//---------------------------------------------------------------------------
public FTPFileObj(URL inURL)
{
mURL = inURL;
String path = inURL.getPath();
if (path.endsWith("/"))
{
path = path.substring(0, path.length() - 1);
}
mName = path.substring(path.lastIndexOf("/") + 1);
if (path.length() > 0)
{
int index = path.lastIndexOf("/");
mParentDirPath = (index >= 0 ? path.substring(0, index) : "");
}
mFTPServer = inURL.getHost();
}
//###########################################################################
// PUBLIC METHODS
//###########################################################################
//---------------------------------------------------------------------------
@Override
public String getScheme()
{
return SCHEME;
}
//---------------------------------------------------------------------------
@Override
public String getName()
{
return mName;
}
//---------------------------------------------------------------------------
public FTPFileObj setRequestedPath(String inValue)
{
mRequestedFilePath = inValue;
return this;
}
//---------------------------------------------------------------------------
@Override
public String getRequestedPath()
{
return mRequestedFilePath != null ? mRequestedFilePath : getPath();
}
//---------------------------------------------------------------------------
@Override
public String getPath()
{
return mURL.getPath();
}
//---------------------------------------------------------------------------
@Override
public URI getURI()
{
URI uri;
try
{
uri = new URI(getScheme(), mFTPServer, getPath(), null);
}
catch (URISyntaxException e)
{
throw new RuntimeIOException(e);
}
return uri;
}
//---------------------------------------------------------------------------
public String getURL()
{
return mURL.toString();
}
//---------------------------------------------------------------------------
@Override
public long length()
{
return getFTPFile().getSize();
}
//---------------------------------------------------------------------------
@Override
public Long lastModified()
{
Long lastModifiedOverride = super.lastModified();
return lastModifiedOverride != null ? lastModifiedOverride : getFTPFile().getTimestamp().getTimeInMillis();
}
//---------------------------------------------------------------------------
@Override
public Calendar getTimestamp()
{
// Round to seconds since I was seeing some odd behavior with millis precision.
Calendar cal = getFTPFile().getTimestamp();
cal.setTimeInMillis((cal.getTimeInMillis() / 1000) * 1000);
return cal;
}
//---------------------------------------------------------------------------
public FTPFileObj setCredentials(LoginCredentials inValue)
{
mCredentials = inValue;
return this;
}
//---------------------------------------------------------------------------
public LoginCredentials getCredentials()
{
return mCredentials;
}
//---------------------------------------------------------------------------
@Override
public List listFiles()
{
List fileObjs = null;
if (isDirectory())
{
try
{
FTPFile[] files = getFTPClient(mURL).listFiles(getPath());
if (files.length > 0)
{
fileObjs = new ArrayList<>(files.length);
for (FTPFile file : files)
{
URL url = new URL(mURL.getProtocol(), mURL.getHost(), getPath() + (getPath().endsWith("/") ? "" : "/") + file.getName());
fileObjs.add(new FTPFileObj(url));
}
}
}
catch (Exception e)
{
throw new RuntimeIOException(e);
}
}
return fileObjs;
}
//---------------------------------------------------------------------------
/**
* Use FTP.ASCII_FILE_TYPE or FTP.BINARY_FILE_TYPE (default).
*/
public void setFileTransferMode(int inValue)
{
mFileTransferMode = FTP.ASCII_FILE_TYPE;
}
//---------------------------------------------------------------------------
@Override
public boolean exists()
{
boolean result;
try
{
result = getFTPClient(mURL).list(getPath()) > 0;
}
catch (IOException e)
{
throw new RuntimeIOException(e);
}
return result;
}
//---------------------------------------------------------------------------
@Override
public boolean canRead()
{
FTPFile ftpFile = getFTPFile();
return ftpFile.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION)
|| (ftpFile.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION)
&& ftpFile.getUser().equals(getCredentials().getUser()))
|| (ftpFile.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION)
&& ftpFile.getGroup().equals("???")); //TODO: How to determine the group(s) for the logged in FTP user?
}
//---------------------------------------------------------------------------
@Override
public boolean canWrite()
{
FTPFile ftpFile = getFTPFile();
return ftpFile.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.WRITE_PERMISSION)
|| (ftpFile.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION)
&& ftpFile.getUser().equals(getCredentials().getUser()))
|| (ftpFile.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.WRITE_PERMISSION)
&& ftpFile.getGroup().equals("???")); //TODO: How to determine the group(s) for the logged in FTP user?
}
//---------------------------------------------------------------------------
@Override
public boolean isFile()
{
return getFTPFile().isFile();
}
//---------------------------------------------------------------------------
@Override
public boolean isDirectory()
{
FTPFile ftpFile = getFTPFile();
return (ftpFile != null ? ftpFile.isDirectory() : true); // The root won't return an ftpFile
}
//---------------------------------------------------------------------------
@Override
public FTPFileObj getParentDir()
throws IOException
{
FTPFileObj parentDir = null;
if (getPath().length() > 1)
{
URL url = new URL(getScheme(), mURL.getHost(), getParentDirPath());
parentDir = new FTPFileObj(url);
}
return parentDir;
}
//---------------------------------------------------------------------------
@Override
public boolean mkdirs()
throws IOException
{
return getFTPClient(mURL).makeDirectory(getPath());
}
//---------------------------------------------------------------------------
@Override
public boolean delete()
throws IOException
{
return getFTPClient(mURL).deleteFile(getPath());
}
//---------------------------------------------------------------------------
/**
* Note that the FTP connection is closed when the returned InputStream is closed.
*/
@Override
public InputStream getInputStream()
throws IOException
{
FTPClient ftpClient = getFTPClient(mURL);
ftpClient.setFileType(mFileTransferMode);
InputStream stream = ftpClient.retrieveFileStream(mURL.getPath());
return new BufferedInputStream(stream);
}
//---------------------------------------------------------------------------
@Override
public OutputStream getOutputStream()
throws IOException
{
FTPClient ftpClient = getFTPClient(mURL);
ftpClient.setFileType(mFileTransferMode);
OutputStream stream = ftpClient.appendFileStream(mURL.getPath());
return new BufferedOutputStream(stream);
}
//---------------------------------------------------------------------------
@Override
public long writeToStream(OutputStream stream)
throws IOException
{
FTPClient ftpClient = getFTPClient(mURL);
ftpClient.setFileType(mFileTransferMode);
ftpClient.changeWorkingDirectory(getParentDirPath());
ftpClient.retrieveFile(getName(), stream);
return length();
}
//---------------------------------------------------------------------------
private FTPClient getFTPClient(URL inURL)
{
if (null == mFTP)
{
FTPClient client = new FTPClient();
client.setRemoteVerificationEnabled(false); // Bad with caching firewalls
client.setDataTimeout((int) TimeUnit.hour.getMilliseconds());
try
{
int reply;
if (inURL.getPort() > 0)
{
client.connect(inURL.getHost(), inURL.getPort());
}
else
{
client.connect(inURL.getHost());
}
// After connection attempt, check the reply code to verify success.
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply))
{
throw new RuntimeException("FTP server '" + inURL.getHost() + "' refused connection.");
}
client.login(mCredentials.getUser(), new String(mCredentials.getPassword()));
// Hmmm. Data connections on my mac never seem to go anywhere unless I do this to force passive mode.
client.enterLocalPassiveMode();
}
catch (IOException e)
{
if (client.isConnected())
{
try
{
client.disconnect();
}
catch (IOException f)
{
// do nothing
}
}
throw new RuntimeException(e);
}
mFTP = client;
}
return mFTP;
}
//---------------------------------------------------------------------------
private static String getUserAtHostPassword()
{
String passwd;
try
{
passwd = System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
throw new RuntimeException(e);
}
return passwd;
}
//---------------------------------------------------------------------------
private FTPFile getFTPFile()
{
if (null == mFTPFile)
{
try
{
FTPFile[] files = getFTPClient(mURL).listFiles(getParentDirPath());
if (files.length > 0)
{
for (FTPFile file : files)
{
if (file.getName().equals(getName()))
{
mFTPFile = file;
break;
}
}
}
}
catch (IOException e)
{
throw new RuntimeIOException(e);
}
}
return mFTPFile;
}
//---------------------------------------------------------------------------
private String getParentDirPath()
{
String parentDirPath = "";
String path = mURL.getPath();
if (path.length() > 0)
{
int index = path.substring(0,path.length() - 1).lastIndexOf("/");
if (index >= 0)
{
parentDirPath = path.substring(0, index + 1);
}
}
return parentDirPath;
}
}