extensions/net.sf.basedb.xfiles/trunk/src/net/sf/basedb/xfiles/ftp/FtpConnectionManager.java

Code
Comments
Other
Rev Date Author Line
2521 25 Jun 14 nicklas 1 /**
2521 25 Jun 14 nicklas 2   $Id$
2521 25 Jun 14 nicklas 3
2521 25 Jun 14 nicklas 4   Copyright (C) 2014 Nicklas Nordborg
2521 25 Jun 14 nicklas 5
2521 25 Jun 14 nicklas 6   This file is part of BASE - BioArray Software Environment.
2521 25 Jun 14 nicklas 7   Available at http://base.thep.lu.se/
2521 25 Jun 14 nicklas 8
2521 25 Jun 14 nicklas 9   BASE is free software; you can redistribute it and/or
2521 25 Jun 14 nicklas 10   modify it under the terms of the GNU General Public License
2521 25 Jun 14 nicklas 11   as published by the Free Software Foundation; either version 3
2521 25 Jun 14 nicklas 12   of the License, or (at your option) any later version.
2521 25 Jun 14 nicklas 13
2521 25 Jun 14 nicklas 14   BASE is distributed in the hope that it will be useful,
2521 25 Jun 14 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
2521 25 Jun 14 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2521 25 Jun 14 nicklas 17   GNU General Public License for more details.
2521 25 Jun 14 nicklas 18
2521 25 Jun 14 nicklas 19   You should have received a copy of the GNU General Public License
2521 25 Jun 14 nicklas 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
2521 25 Jun 14 nicklas 21 */
2521 25 Jun 14 nicklas 22 package net.sf.basedb.xfiles.ftp;
2521 25 Jun 14 nicklas 23
2521 25 Jun 14 nicklas 24 import it.sauronsoftware.ftp4j.FTPClient;
2521 25 Jun 14 nicklas 25 import it.sauronsoftware.ftp4j.FTPFile;
2521 25 Jun 14 nicklas 26
2521 25 Jun 14 nicklas 27 import java.io.IOException;
2521 25 Jun 14 nicklas 28 import java.io.InputStream;
2521 25 Jun 14 nicklas 29 import java.net.URI;
2521 25 Jun 14 nicklas 30
2521 25 Jun 14 nicklas 31 import javax.net.ssl.SSLContext;
2521 25 Jun 14 nicklas 32
3797 18 Mar 16 nicklas 33 import net.sf.basedb.util.ssl.SSLUtil2;
2521 25 Jun 14 nicklas 34 import net.sf.basedb.util.uri.CloseResourceInputStream;
2521 25 Jun 14 nicklas 35 import net.sf.basedb.util.uri.ConnectionParameters;
2523 25 Jun 14 nicklas 36 import net.sf.basedb.util.uri.ResumableConnectionManager;
2521 25 Jun 14 nicklas 37 import net.sf.basedb.util.uri.UriMetadata;
2572 13 Aug 14 nicklas 38 import net.sf.basedb.xfiles.ConnectionCache;
2572 13 Aug 14 nicklas 39 import net.sf.basedb.xfiles.ConnectionInfo;
2521 25 Jun 14 nicklas 40 import net.sf.basedb.xfiles.MultiCloseable;
2521 25 Jun 14 nicklas 41 import net.sf.basedb.xfiles.XFiles;
2521 25 Jun 14 nicklas 42
2521 25 Jun 14 nicklas 43 /**
2521 25 Jun 14 nicklas 44   Access remote files via FTP protocol. URI:s should use 'ftp://' or 'ftps://' as schema. 
2521 25 Jun 14 nicklas 45   The host and port of the URI should point to a FTP server.
2521 25 Jun 14 nicklas 46
2521 25 Jun 14 nicklas 47   @author Nicklas
2521 25 Jun 14 nicklas 48   @since 1.0
2521 25 Jun 14 nicklas 49 */
2521 25 Jun 14 nicklas 50 public class FtpConnectionManager
2523 25 Jun 14 nicklas 51   implements ResumableConnectionManager
2521 25 Jun 14 nicklas 52 {
2521 25 Jun 14 nicklas 53
2572 13 Aug 14 nicklas 54   static ConnectionCache<FTPClientWrapper> CONNECTION_CACHE = new ConnectionCache<FTPClientWrapper>(new FtpConnectionParametersComparator());
2572 13 Aug 14 nicklas 55
2521 25 Jun 14 nicklas 56   private final URI uri;
2521 25 Jun 14 nicklas 57   private final ConnectionParameters parameters;
2521 25 Jun 14 nicklas 58   private UriMetadata metadata;
2521 25 Jun 14 nicklas 59   
2521 25 Jun 14 nicklas 60   public FtpConnectionManager(URI uri, ConnectionParameters parameters)
2521 25 Jun 14 nicklas 61   {
2521 25 Jun 14 nicklas 62     this.uri = uri;
2521 25 Jun 14 nicklas 63     this.parameters = parameters;
2521 25 Jun 14 nicklas 64   }
2521 25 Jun 14 nicklas 65   
2521 25 Jun 14 nicklas 66   /*
2523 25 Jun 14 nicklas 67     From the ResumableConnectionManager interface
2523 25 Jun 14 nicklas 68     ---------------------------------------------
2521 25 Jun 14 nicklas 69   */
2521 25 Jun 14 nicklas 70   @Override
2521 25 Jun 14 nicklas 71   public URI getURI()
2521 25 Jun 14 nicklas 72   {
2521 25 Jun 14 nicklas 73     return uri;
2521 25 Jun 14 nicklas 74   }
2521 25 Jun 14 nicklas 75
2521 25 Jun 14 nicklas 76   @Override
2521 25 Jun 14 nicklas 77   public InputStream getInputStream() 
2521 25 Jun 14 nicklas 78     throws IOException
2521 25 Jun 14 nicklas 79   {
2523 25 Jun 14 nicklas 80     return getInputStream(0);
2523 25 Jun 14 nicklas 81   }
2523 25 Jun 14 nicklas 82   
2523 25 Jun 14 nicklas 83   @Override
2523 25 Jun 14 nicklas 84   public InputStream getInputStream(long offset) 
2523 25 Jun 14 nicklas 85     throws IOException
2523 25 Jun 14 nicklas 86   {
2521 25 Jun 14 nicklas 87     URI uri = getURI();
2521 25 Jun 14 nicklas 88     InputStream stream = null;
2572 13 Aug 14 nicklas 89     FTPClientWrapper wrapper = null;
2521 25 Jun 14 nicklas 90     try
2521 25 Jun 14 nicklas 91     {
2572 13 Aug 14 nicklas 92       wrapper = connect(uri, parameters);
2572 13 Aug 14 nicklas 93       stream = new CloseResourceInputStream(
2572 13 Aug 14 nicklas 94           wrapper.download(uri, offset), 
2572 13 Aug 14 nicklas 95           new MultiCloseable(wrapper));
2521 25 Jun 14 nicklas 96     }
2521 25 Jun 14 nicklas 97     finally
2521 25 Jun 14 nicklas 98     {
2521 25 Jun 14 nicklas 99       // If no stream has been created we close everything immediately
2521 25 Jun 14 nicklas 100       if (stream == null)
2521 25 Jun 14 nicklas 101       {
2572 13 Aug 14 nicklas 102         MultiCloseable.close(wrapper);
2521 25 Jun 14 nicklas 103       }
2521 25 Jun 14 nicklas 104     }
2521 25 Jun 14 nicklas 105     return stream;        
2521 25 Jun 14 nicklas 106   }
2521 25 Jun 14 nicklas 107
2521 25 Jun 14 nicklas 108   @Override
2521 25 Jun 14 nicklas 109   public UriMetadata getMetadata() 
2521 25 Jun 14 nicklas 110     throws IOException
2521 25 Jun 14 nicklas 111   {
2521 25 Jun 14 nicklas 112     if (metadata == null) 
2521 25 Jun 14 nicklas 113     {
2521 25 Jun 14 nicklas 114       // Create new metadata object
2521 25 Jun 14 nicklas 115       URI uri = getURI();
2521 25 Jun 14 nicklas 116       metadata = new UriMetadata(uri);
2572 13 Aug 14 nicklas 117
2572 13 Aug 14 nicklas 118       FTPClientWrapper wrapper = null;
2521 25 Jun 14 nicklas 119       try
2521 25 Jun 14 nicklas 120       {
2572 13 Aug 14 nicklas 121         wrapper = connect(uri, parameters);
2572 13 Aug 14 nicklas 122         FTPFile[] files = wrapper.list(uri);
2521 25 Jun 14 nicklas 123         if (files.length > 0)
2521 25 Jun 14 nicklas 124         {
2521 25 Jun 14 nicklas 125           loadMetadata(metadata, files[0]);
2521 25 Jun 14 nicklas 126         }
2521 25 Jun 14 nicklas 127       }
2521 25 Jun 14 nicklas 128       catch (Exception ex)
2521 25 Jun 14 nicklas 129       {
2521 25 Jun 14 nicklas 130         throw new IOException(ex);
2521 25 Jun 14 nicklas 131       }
2521 25 Jun 14 nicklas 132       finally
2521 25 Jun 14 nicklas 133       {
2521 25 Jun 14 nicklas 134         // Clean up
2572 13 Aug 14 nicklas 135         MultiCloseable.close(wrapper);
2521 25 Jun 14 nicklas 136       }
2521 25 Jun 14 nicklas 137     }
2521 25 Jun 14 nicklas 138     return metadata;
2521 25 Jun 14 nicklas 139   }
2521 25 Jun 14 nicklas 140   // --------------------------------------
2521 25 Jun 14 nicklas 141   
2521 25 Jun 14 nicklas 142   
2572 13 Aug 14 nicklas 143   public FTPClientWrapper connect(URI uri, ConnectionParameters parameters)
2521 25 Jun 14 nicklas 144     throws IOException
2521 25 Jun 14 nicklas 145   {
3804 22 Mar 16 nicklas 146     ConnectionInfo info = new ConnectionInfo(uri, parameters, null);
2572 13 Aug 14 nicklas 147
2572 13 Aug 14 nicklas 148     FTPClientWrapper wrapper = CONNECTION_CACHE.getClient(info);
2572 13 Aug 14 nicklas 149     boolean connected = wrapper != null && wrapper.ftp.isConnected();
2572 13 Aug 14 nicklas 150
2521 25 Jun 14 nicklas 151     try
2521 25 Jun 14 nicklas 152     {
2572 13 Aug 14 nicklas 153       FTPClient ftp = new FTPClient();
2521 25 Jun 14 nicklas 154       // Get username and password
2521 25 Jun 14 nicklas 155       String username = null;
2521 25 Jun 14 nicklas 156       String password = null;
2521 25 Jun 14 nicklas 157       if (parameters != null)
2521 25 Jun 14 nicklas 158       {
2521 25 Jun 14 nicklas 159         username = parameters.getUsername();
2521 25 Jun 14 nicklas 160         password = parameters.getPassword();
2521 25 Jun 14 nicklas 161       }
2521 25 Jun 14 nicklas 162       if (username == null) username = "anonymous";
2521 25 Jun 14 nicklas 163       if (password == null) password = "anonymous@anonymous.com";
2521 25 Jun 14 nicklas 164       
2521 25 Jun 14 nicklas 165       // Setup SSL if needed
2521 25 Jun 14 nicklas 166       int port = uri.getPort();
2521 25 Jun 14 nicklas 167       if (uri.getScheme().equals("ftps"))
2521 25 Jun 14 nicklas 168       {
2521 25 Jun 14 nicklas 169         // Implicit SSL (default port is 990)
2521 25 Jun 14 nicklas 170         ftp.setSecurity(FTPClient.SECURITY_FTPS);
3797 18 Mar 16 nicklas 171         SSLContext slc = parameters == null ? SSLContext.getDefault() : SSLUtil2.getSSLContext(parameters.getServerCertificate(), parameters.getClientCertificate(), parameters.getClientCertificatePassword());
2521 25 Jun 14 nicklas 172         ftp.setSSLSocketFactory(slc.getSocketFactory());
2521 25 Jun 14 nicklas 173         if (port == -1) port = XFiles.DEFAULT_FTPS_PORT;
2521 25 Jun 14 nicklas 174       }
2521 25 Jun 14 nicklas 175       else if (parameters != null && parameters.getServerCertificate() != null)
2521 25 Jun 14 nicklas 176       {
2521 25 Jun 14 nicklas 177         // Explicit SSL (default port is 21)
2521 25 Jun 14 nicklas 178         ftp.setSecurity(FTPClient.SECURITY_FTPES);
3797 18 Mar 16 nicklas 179         SSLContext slc = SSLUtil2.getSSLContext(parameters.getServerCertificate(), parameters.getClientCertificate(), parameters.getClientCertificatePassword());
2521 25 Jun 14 nicklas 180         ftp.setSSLSocketFactory(slc.getSocketFactory());
2521 25 Jun 14 nicklas 181       }
2521 25 Jun 14 nicklas 182       if (port == -1) port = XFiles.DEFAULT_FTP_PORT;
2521 25 Jun 14 nicklas 183       
2521 25 Jun 14 nicklas 184       ftp.connect(uri.getHost(), port);
2521 25 Jun 14 nicklas 185       ftp.login(username, password);
2521 25 Jun 14 nicklas 186       // Always use binary file format
2521 25 Jun 14 nicklas 187       ftp.setType(FTPClient.TYPE_BINARY);
2521 25 Jun 14 nicklas 188       // Always use passive mode
2521 25 Jun 14 nicklas 189       ftp.setPassive(true);
2572 13 Aug 14 nicklas 190       wrapper = new FTPClientWrapper(ftp, info);
2521 25 Jun 14 nicklas 191       connected = true;
2521 25 Jun 14 nicklas 192     }
2521 25 Jun 14 nicklas 193     catch (Exception ex)
2521 25 Jun 14 nicklas 194     {
2521 25 Jun 14 nicklas 195       throw new IOException(ex);
2521 25 Jun 14 nicklas 196     }
2521 25 Jun 14 nicklas 197     finally
2521 25 Jun 14 nicklas 198     {
2572 13 Aug 14 nicklas 199       if (!connected) 
2572 13 Aug 14 nicklas 200       {
2572 13 Aug 14 nicklas 201         MultiCloseable.close(wrapper);
2572 13 Aug 14 nicklas 202         wrapper = null;
2572 13 Aug 14 nicklas 203       }
2521 25 Jun 14 nicklas 204     }
2572 13 Aug 14 nicklas 205     return wrapper;
2521 25 Jun 14 nicklas 206   }
2521 25 Jun 14 nicklas 207   
2521 25 Jun 14 nicklas 208
2521 25 Jun 14 nicklas 209   /**
2521 25 Jun 14 nicklas 210     Read metadata from the given file information.
2521 25 Jun 14 nicklas 211     <ul>
2521 25 Jun 14 nicklas 212     <li>Length: {@link FTPFile#getSize()}
2521 25 Jun 14 nicklas 213     <li>Last modified: {@link FTPFile#getModifiedDate()}
2521 25 Jun 14 nicklas 214     </ul>
2521 25 Jun 14 nicklas 215   */
2521 25 Jun 14 nicklas 216   public void loadMetadata(UriMetadata metadata, FTPFile ftpFile)
2521 25 Jun 14 nicklas 217     throws IOException
2521 25 Jun 14 nicklas 218   {
2521 25 Jun 14 nicklas 219     metadata.setLength(ftpFile.getSize());
2521 25 Jun 14 nicklas 220     metadata.setLastModified(ftpFile.getModifiedDate());
2521 25 Jun 14 nicklas 221   }
2521 25 Jun 14 nicklas 222   
2521 25 Jun 14 nicklas 223 }