/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.job.entries.ftpsget; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.apache.commons.io.IOUtils; import org.apache.commons.vfs2.FileObject; import org.ftp4che.FTPConnection; import org.ftp4che.FTPConnectionFactory; import org.ftp4che.event.FTPEvent; import org.ftp4che.event.FTPListener; import org.ftp4che.util.ftpfile.FTPFile; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.i18n.BaseMessages; public class FTPSConnection implements FTPListener { private static Class<?> PKG = JobEntryFTPSGet.class; // for i18n purposes, needed by Translator2!! public static final String HOME_FOLDER = "/"; public static final String COMMAND_SUCCESSUL = "COMMAND SUCCESSFUL"; public static final int CONNECTION_TYPE_FTP = 0; public static final int CONNECTION_TYPE_FTP_IMPLICIT_SSL = 1; public static final int CONNECTION_TYPE_FTP_AUTH_SSL = 2; public static final int CONNECTION_TYPE_FTP_IMPLICIT_SSL_WITH_CRYPTED = 3; public static final int CONNECTION_TYPE_FTP_AUTH_TLS = 4; public static final int CONNECTION_TYPE_FTP_IMPLICIT_TLS = 5; public static final int CONNECTION_TYPE_FTP_IMPLICIT_TLS_WITH_CRYPTED = 6; public static final String[] connection_type_Desc = new String[] { BaseMessages.getString( PKG, "JobFTPS.ConnectionType.FTP" ), BaseMessages.getString( PKG, "JobFTPS.ConnectionType.ImplicitSSL" ), BaseMessages.getString( PKG, "JobFTPS.ConnectionType.AuthSSL" ), BaseMessages.getString( PKG, "JobFTPS.ConnectionType.ImplicitSSLCrypted" ), BaseMessages.getString( PKG, "JobFTPS.ConnectionType.AuthTLS" ), BaseMessages.getString( PKG, "JobFTPS.ConnectionType.ImplicitTLS" ), BaseMessages.getString( PKG, "JobFTPS.ConnectionType.ImplicitTLSCrypted" ) }; public static final String[] connection_type_Code = new String[] { "FTP_CONNECTION", "IMPLICIT_SSL_FTP_CONNECTION", "AUTH_SSL_FTP_CONNECTION", "IMPLICIT_SSL_WITH_CRYPTED_DATA_FTP_CONNECTION", "AUTH_TLS_FTP_CONNECTION", "IMPLICIT_TLS_FTP_CONNECTION", "IMPLICIT_TLS_WITH_CRYPTED_DATA_FTP_CONNECTION" }; private FTPConnection connection = null; private ArrayList<String> replies = new ArrayList<String>(); private String hostName; private int portNumber; private String userName; private String passWord; private int connectionType; private int timeOut; private boolean passiveMode; private String proxyHost; private String proxyUser; private String proxyPassword; private int proxyPort; public FTPSConnection( int connectionType, String hostname, int port, String username, String password ) { this.hostName = hostname; this.portNumber = port; this.userName = username; this.passWord = password; this.connectionType = connectionType; this.passiveMode = false; } /** * * this method is used to set the proxy host * * @param type * true: proxy host */ public void setProxyHost( String proxyhost ) { this.proxyHost = proxyhost; } /** * * this method is used to set the proxy port * * @param type * true: proxy port */ public void setProxyPort( int proxyport ) { this.proxyPort = proxyport; } /** * * this method is used to set the proxy username * * @param type * true: proxy username */ public void setProxyUser( String username ) { this.proxyUser = username; } /** * * this method is used to set the proxy password * * @param type * true: proxy password */ public void setProxyPassword( String password ) { this.proxyPassword = password; } /** * * this method is used to connect to a remote host * * @throws KettleException */ public void connect() throws KettleException { try { connection = FTPConnectionFactory.getInstance( getProperties( hostName, portNumber, userName, passWord, connectionType, timeOut, passiveMode ) ); connection.addFTPStatusListener( this ); connection.connect(); } catch ( Exception e ) { connection = null; throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.Connecting", hostName ), e ); } } private Properties getProperties( String hostname, int port, String username, String password, int connectionType, int timeout, boolean passiveMode ) { Properties pt = new Properties(); pt.setProperty( "connection.host", hostname ); pt.setProperty( "connection.port", String.valueOf( port ) ); pt.setProperty( "user.login", username ); pt.setProperty( "user.password", password ); pt.setProperty( "connection.type", getConnectionType( connectionType ) ); pt.setProperty( "connection.timeout", String.valueOf( timeout ) ); pt.setProperty( "connection.passive", String.valueOf( passiveMode ) ); // Set proxy if ( this.proxyHost != null ) { pt.setProperty( "proxy.host", this.proxyHost ); } if ( this.proxyPort != 0 ) { pt.setProperty( "proxy.port", String.valueOf( this.proxyPort ) ); } if ( this.proxyUser != null ) { pt.setProperty( "proxy.user", this.proxyUser ); } if ( this.proxyPassword != null ) { pt.setProperty( "proxy.pass", this.proxyPassword ); } return pt; } public static String getConnectionTypeDesc( String tt ) { if ( Utils.isEmpty( tt ) ) { return connection_type_Desc[0]; } if ( tt.equalsIgnoreCase( connection_type_Code[ 1 ] ) ) { return connection_type_Desc[1]; } else { return connection_type_Desc[0]; } } public static String getConnectionTypeCode( String tt ) { if ( tt == null ) { return connection_type_Code[0]; } if ( tt.equals( connection_type_Desc[1] ) ) { return connection_type_Code[1]; } else { return connection_type_Code[0]; } } public static String getConnectionTypeDesc( int i ) { if ( i < 0 || i >= connection_type_Desc.length ) { return connection_type_Desc[0]; } return connection_type_Desc[i]; } public static String getConnectionType( int i ) { return connection_type_Code[i]; } public static int getConnectionTypeByDesc( String tt ) { if ( tt == null ) { return 0; } for ( int i = 0; i < connection_type_Desc.length; i++ ) { if ( connection_type_Desc[i].equalsIgnoreCase( tt ) ) { return i; } } // If this fails,return the first value return 0; } public static int getConnectionTypeByCode( String tt ) { if ( tt == null ) { return 0; } for ( int i = 0; i < connection_type_Code.length; i++ ) { if ( connection_type_Code[i].equalsIgnoreCase( tt ) ) { return i; } } return 0; } public static String getConnectionTypeCode( int i ) { if ( i < 0 || i >= connection_type_Code.length ) { return connection_type_Code[0]; } return connection_type_Code[i]; } /** * public void setBinaryMode(boolean type) * * this method is used to set the transfer type to binary * * @param type * true: Binary * @throws KettleException */ public void setBinaryMode( boolean type ) throws KettleException { try { connection.setTransferType( true ); } catch ( Exception e ) { throw new KettleException( e ); } } /** * * this method is used to set the mode to passive * * @param type * true: passive mode */ public void setPassiveMode( boolean passivemode ) { this.passiveMode = passivemode; } /** * * this method is used to return the passive mode * * @return TRUE if we use passive mode * */ public boolean isPassiveMode() { return this.passiveMode; } /** * * this method is used to set the timeout * * @param timeout * */ public void setTimeOut( int timeout ) { this.timeOut = timeout; } /** * * this method is used to return the timeout * * @return timeout * */ public int getTimeOut() { return this.timeOut; } public String getUserName() { return userName; } public String getHostName() { return hostName; } public ArrayList<String> getReplies() { return replies; } /** * * this method is used to set the connection type * * @param type * true: connection type */ public void setConnectionType( int connectiontype ) { this.connectionType = connectiontype; } public int getConnectionType() { return this.connectionType; } public void connectionStatusChanged( FTPEvent arg0 ) { } public void replyMessageArrived( FTPEvent event ) { this.replies = new ArrayList<String>(); for ( String e : event.getReply().getLines() ) { if ( !e.trim().equals( "" ) ) { e = e.substring( 3 ).trim().replace( "\n", "" ); if ( !e.toUpperCase().contains( COMMAND_SUCCESSUL ) ) { e = e.substring( 1 ).trim(); replies.add( e ); } } } } /** * * this method change FTP working directory * * @param directory * change the working directory * @throws KettleException */ public void changeDirectory( String directory ) throws KettleException { try { this.connection.changeDirectory( directory ); } catch ( Exception f ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.ChangingFolder", directory ), f ); } } /** * * this method is used to create a directory in remote host * * @param directory * directory name on remote host * @throws KettleException */ public void createDirectory( String directory ) throws KettleException { try { this.connection.makeDirectory( directory ); } catch ( Exception f ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.CreationFolder", directory ), f ); } } public List<FTPFile> getFileList( String folder ) throws KettleException { try { if ( connection != null ) { List<FTPFile> response = connection.getDirectoryListing( folder ); return response; } else { return null; } } catch ( Exception e ) { throw new KettleException( e ); } } /** * this method is used to download a file from a remote host * * @param file remote file to download * @param localFilename target filename * @throws KettleException */ public void downloadFile( FTPFile file, String localFilename ) throws KettleException { try { FileObject localFile = KettleVFS.getFileObject( localFilename ); writeToFile( connection.downloadStream( file ), localFile.getContent().getOutputStream(), localFilename ); } catch ( Exception e ) { throw new KettleException( e ); } } private void writeToFile( InputStream is, OutputStream os, String filename ) throws KettleException { try { IOUtils.copy( is, os ); } catch ( IOException e ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.WritingToFile", filename ), e ); } finally { IOUtils.closeQuietly( is ); IOUtils.closeQuietly( os ); } } /** * * this method is used to upload a file to a remote host * * @param localFileName * Local full filename * @param shortFileName * Filename in remote host * @throws KettleException */ public void uploadFile( String localFileName, String shortFileName ) throws KettleException { FileObject file = null; try { file = KettleVFS.getFileObject( localFileName ); this.connection.uploadStream( file.getContent().getInputStream(), new FTPFile( new File( shortFileName ) ) ); } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.UuploadingFile", localFileName ), e ); } finally { if ( file != null ) { try { file.close(); } catch ( Exception e ) { // Ignore close errors } } } } /** * * this method is used to return filenames in working directory * * @return filenames * @throws KettleException */ public String[] getFileNames() throws KettleException { ArrayList<String> list = null; try { List<FTPFile> fileList = getFileList( getWorkingDirectory() ); list = new ArrayList<String>(); Iterator<FTPFile> it = fileList.iterator(); while ( it.hasNext() ) { FTPFile file = it.next(); if ( !file.isDirectory() ) { list.add( file.getName() ); } } } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.RetrievingFilenames" ), e ); } return list == null ? null : list.toArray( new String[list.size()] ); } /** * * this method is used to delete a file in remote host * * @param file * File on remote host to delete * @throws KettleException */ public void deleteFile( FTPFile file ) throws KettleException { try { this.connection.deleteFile( file ); } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.DeletingFile", file.getName() ), e ); } } /** * * this method is used to delete a file in remote host * * @param filename * Name of file on remote host to delete * @throws KettleException */ public void deleteFile( String filename ) throws KettleException { try { this.connection.deleteFile( new FTPFile( getWorkingDirectory(), filename ) ); } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.DeletingFile", filename ), e ); } } /** * * this method is used to move a file to remote directory * * @param fromFile * File on remote host to move * @param targetFoldername * Target remote folder * @throws KettleException */ public void moveToFolder( FTPFile fromFile, String targetFoldername ) throws KettleException { try { this.connection.renameFile( fromFile, new FTPFile( targetFoldername, fromFile.getName() ) ); } catch ( Exception e ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPS.Error.MovingFileToFolder", fromFile .getName(), targetFoldername ), e ); } } /** * * Checks if a directory exists * * @return true if the directory exists * */ public boolean isDirectoryExists( String directory ) { String currectDirectory = null; boolean retval = false; try { // Before save current directory currectDirectory = this.connection.getWorkDirectory(); // Change directory this.connection.changeDirectory( directory ); retval = true; } catch ( Exception e ) { // Ignore directory change errors } finally { // switch back to the current directory if ( currectDirectory != null ) { try { this.connection.changeDirectory( currectDirectory ); } catch ( Exception e ) { // Ignore directory change errors } } } return retval; } /** * * Checks if a file exists on remote host * * @param filename * the name of the file to check * @return true if the file exists * */ public boolean isFileExists( String filename ) { boolean retval = false; try { FTPFile file = new FTPFile( new File( filename ) ); // Get modification time just to check if file exists connection.getModificationTime( file ); retval = true; } catch ( Exception e ) { // Ignore errors } return retval; } /** * * Returns the working directory * * @return working directory * @throws Exception */ public String getWorkingDirectory() throws Exception { return this.connection.getWorkDirectory(); } /** * * this method is used to disconnect the connection * */ public void disconnect() { if ( this.connection != null ) { this.connection.disconnect(); } if ( this.replies != null ) { this.replies.clear(); } } }