/*! ****************************************************************************** * * 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.ftpput; import org.pentaho.di.job.entry.validator.AndValidator; import org.pentaho.di.job.entry.validator.JobEntryValidatorUtils; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.pentaho.di.cluster.SlaveServer; import org.pentaho.di.core.CheckResultInterface; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.Result; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.encryption.Encr; import org.pentaho.di.core.exception.KettleDatabaseException; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettleXMLException; import org.pentaho.di.core.variables.VariableSpace; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.job.JobMeta; import org.pentaho.di.job.entries.ftp.MVSFileParser; import org.pentaho.di.job.entry.JobEntryBase; import org.pentaho.di.job.entry.JobEntryInterface; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.Repository; import org.pentaho.di.resource.ResourceEntry; import org.pentaho.di.resource.ResourceEntry.ResourceType; import org.pentaho.di.resource.ResourceReference; import org.pentaho.metastore.api.IMetaStore; import org.w3c.dom.Node; import com.enterprisedt.net.ftp.FTPClient; import com.enterprisedt.net.ftp.FTPConnectMode; import com.enterprisedt.net.ftp.FTPException; import com.enterprisedt.net.ftp.FTPFileFactory; import com.enterprisedt.net.ftp.FTPFileParser; import com.enterprisedt.net.ftp.FTPTransferType; /** * This defines an FTP put job entry. * * @author Samatar * @since 15-09-2007 */ public class JobEntryFTPPUT extends JobEntryBase implements Cloneable, JobEntryInterface { private static Class<?> PKG = JobEntryFTPPUT.class; // for i18n purposes, needed by Translator2!! public static final int FTP_DEFAULT_PORT = 21; private String serverName; private String serverPort; private String userName; private String password; private String remoteDirectory; private String localDirectory; private String wildcard; private boolean binaryMode; private int timeout; private boolean remove; private boolean onlyPuttingNewFiles; /* Don't overwrite files */ private boolean activeConnection; private String controlEncoding; /* how to convert list of filenames e.g. */ private String proxyHost; private String proxyPort; /* string to allow variable substitution */ private String proxyUsername; private String proxyPassword; private String socksProxyHost; private String socksProxyPort; private String socksProxyUsername; private String socksProxyPassword; /** * Implicit encoding used before PDI v2.4.1 */ private static final String LEGACY_CONTROL_ENCODING = "US-ASCII"; /** * Default encoding when making a new ftp job entry instance. */ private static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1"; public JobEntryFTPPUT( String n ) { super( n, "" ); serverName = null; serverPort = "21"; socksProxyPort = "1080"; remoteDirectory = null; localDirectory = null; setControlEncoding( DEFAULT_CONTROL_ENCODING ); } public JobEntryFTPPUT() { this( "" ); } public Object clone() { JobEntryFTPPUT je = (JobEntryFTPPUT) super.clone(); return je; } public String getXML() { StringBuilder retval = new StringBuilder( 450 ); // 365 characters in spaces and tag names alone retval.append( super.getXML() ); retval.append( " " ).append( XMLHandler.addTagValue( "servername", serverName ) ); retval.append( " " ).append( XMLHandler.addTagValue( "serverport", serverPort ) ); retval.append( " " ).append( XMLHandler.addTagValue( "username", userName ) ); retval.append( " " ).append( XMLHandler.addTagValue( "password", Encr.encryptPasswordIfNotUsingVariables( getPassword() ) ) ); retval.append( " " ).append( XMLHandler.addTagValue( "remoteDirectory", remoteDirectory ) ); retval.append( " " ).append( XMLHandler.addTagValue( "localDirectory", localDirectory ) ); retval.append( " " ).append( XMLHandler.addTagValue( "wildcard", wildcard ) ); retval.append( " " ).append( XMLHandler.addTagValue( "binary", binaryMode ) ); retval.append( " " ).append( XMLHandler.addTagValue( "timeout", timeout ) ); retval.append( " " ).append( XMLHandler.addTagValue( "remove", remove ) ); retval.append( " " ).append( XMLHandler.addTagValue( "only_new", onlyPuttingNewFiles ) ); retval.append( " " ).append( XMLHandler.addTagValue( "active", activeConnection ) ); retval.append( " " ).append( XMLHandler.addTagValue( "control_encoding", controlEncoding ) ); retval.append( " " ).append( XMLHandler.addTagValue( "proxy_host", proxyHost ) ); retval.append( " " ).append( XMLHandler.addTagValue( "proxy_port", proxyPort ) ); retval.append( " " ).append( XMLHandler.addTagValue( "proxy_username", proxyUsername ) ); retval.append( " " ).append( XMLHandler.addTagValue( "proxy_password", Encr.encryptPasswordIfNotUsingVariables( proxyPassword ) ) ); retval.append( " " ).append( XMLHandler.addTagValue( "socksproxy_host", socksProxyHost ) ); retval.append( " " ).append( XMLHandler.addTagValue( "socksproxy_port", socksProxyPort ) ); retval.append( " " ).append( XMLHandler.addTagValue( "socksproxy_username", socksProxyUsername ) ); retval.append( " " ).append( XMLHandler.addTagValue( "socksproxy_password", Encr .encryptPasswordIfNotUsingVariables( socksProxyPassword ) ) ); return retval.toString(); } public void loadXML( Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers, Repository rep, IMetaStore metaStore ) throws KettleXMLException { try { super.loadXML( entrynode, databases, slaveServers ); serverName = XMLHandler.getTagValue( entrynode, "servername" ); serverPort = XMLHandler.getTagValue( entrynode, "serverport" ); userName = XMLHandler.getTagValue( entrynode, "username" ); password = Encr.decryptPasswordOptionallyEncrypted( XMLHandler.getTagValue( entrynode, "password" ) ); remoteDirectory = XMLHandler.getTagValue( entrynode, "remoteDirectory" ); localDirectory = XMLHandler.getTagValue( entrynode, "localDirectory" ); wildcard = XMLHandler.getTagValue( entrynode, "wildcard" ); binaryMode = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "binary" ) ); timeout = Const.toInt( XMLHandler.getTagValue( entrynode, "timeout" ), 10000 ); remove = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "remove" ) ); onlyPuttingNewFiles = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "only_new" ) ); activeConnection = "Y".equalsIgnoreCase( XMLHandler.getTagValue( entrynode, "active" ) ); controlEncoding = XMLHandler.getTagValue( entrynode, "control_encoding" ); proxyHost = XMLHandler.getTagValue( entrynode, "proxy_host" ); proxyPort = XMLHandler.getTagValue( entrynode, "proxy_port" ); proxyUsername = XMLHandler.getTagValue( entrynode, "proxy_username" ); proxyPassword = Encr.decryptPasswordOptionallyEncrypted( XMLHandler.getTagValue( entrynode, "proxy_password" ) ); socksProxyHost = XMLHandler.getTagValue( entrynode, "socksproxy_host" ); socksProxyPort = XMLHandler.getTagValue( entrynode, "socksproxy_port" ); socksProxyUsername = XMLHandler.getTagValue( entrynode, "socksproxy_username" ); socksProxyPassword = Encr.decryptPasswordOptionallyEncrypted( XMLHandler.getTagValue( entrynode, "socksproxy_password" ) ); if ( controlEncoding == null ) { // if we couldn't retrieve an encoding, assume it's an old instance and // put in the the encoding used before v 2.4.0 controlEncoding = LEGACY_CONTROL_ENCODING; } } catch ( KettleXMLException xe ) { throw new KettleXMLException( BaseMessages.getString( PKG, "JobFTPPUT.Log.UnableToLoadFromXml" ), xe ); } } public void loadRep( Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases, List<SlaveServer> slaveServers ) throws KettleException { try { serverName = rep.getJobEntryAttributeString( id_jobentry, "servername" ); serverPort = rep.getJobEntryAttributeString( id_jobentry, "serverport" ); userName = rep.getJobEntryAttributeString( id_jobentry, "username" ); password = Encr.decryptPasswordOptionallyEncrypted( rep.getJobEntryAttributeString( id_jobentry, "password" ) ); remoteDirectory = rep.getJobEntryAttributeString( id_jobentry, "remoteDirectory" ); localDirectory = rep.getJobEntryAttributeString( id_jobentry, "localDirectory" ); wildcard = rep.getJobEntryAttributeString( id_jobentry, "wildcard" ); binaryMode = rep.getJobEntryAttributeBoolean( id_jobentry, "binary" ); timeout = (int) rep.getJobEntryAttributeInteger( id_jobentry, "timeout" ); remove = rep.getJobEntryAttributeBoolean( id_jobentry, "remove" ); onlyPuttingNewFiles = rep.getJobEntryAttributeBoolean( id_jobentry, "only_new" ); activeConnection = rep.getJobEntryAttributeBoolean( id_jobentry, "active" ); controlEncoding = rep.getJobEntryAttributeString( id_jobentry, "control_encoding" ); if ( controlEncoding == null ) { // if we couldn't retrieve an encoding, assume it's an old instance and // put in the the encoding used before v 2.4.0 controlEncoding = LEGACY_CONTROL_ENCODING; } proxyHost = rep.getJobEntryAttributeString( id_jobentry, "proxy_host" ); proxyPort = rep.getJobEntryAttributeString( id_jobentry, "proxy_port" ); proxyUsername = rep.getJobEntryAttributeString( id_jobentry, "proxy_username" ); proxyPassword = Encr .decryptPasswordOptionallyEncrypted( rep.getJobEntryAttributeString( id_jobentry, "proxy_password" ) ); socksProxyHost = rep.getJobEntryAttributeString( id_jobentry, "socksproxy_host" ); socksProxyPort = rep.getJobEntryAttributeString( id_jobentry, "socksproxy_port" ); socksProxyUsername = rep.getJobEntryAttributeString( id_jobentry, "socksproxy_username" ); socksProxyPassword = Encr.decryptPasswordOptionallyEncrypted( rep.getJobEntryAttributeString( id_jobentry, "socksproxy_password" ) ); } catch ( KettleException dbe ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPPUT.UnableToLoadFromRepo", String .valueOf( id_jobentry ) ), dbe ); } } public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_job ) throws KettleException { try { rep.saveJobEntryAttribute( id_job, getObjectId(), "servername", serverName ); rep.saveJobEntryAttribute( id_job, getObjectId(), "serverport", serverPort ); rep.saveJobEntryAttribute( id_job, getObjectId(), "username", userName ); rep.saveJobEntryAttribute( id_job, getObjectId(), "password", Encr .encryptPasswordIfNotUsingVariables( password ) ); rep.saveJobEntryAttribute( id_job, getObjectId(), "remoteDirectory", remoteDirectory ); rep.saveJobEntryAttribute( id_job, getObjectId(), "localDirectory", localDirectory ); rep.saveJobEntryAttribute( id_job, getObjectId(), "wildcard", wildcard ); rep.saveJobEntryAttribute( id_job, getObjectId(), "binary", binaryMode ); rep.saveJobEntryAttribute( id_job, getObjectId(), "timeout", timeout ); rep.saveJobEntryAttribute( id_job, getObjectId(), "remove", remove ); rep.saveJobEntryAttribute( id_job, getObjectId(), "only_new", onlyPuttingNewFiles ); rep.saveJobEntryAttribute( id_job, getObjectId(), "active", activeConnection ); rep.saveJobEntryAttribute( id_job, getObjectId(), "control_encoding", controlEncoding ); rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_host", proxyHost ); rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_port", proxyPort ); rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_username", proxyUsername ); rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_password", Encr .encryptPasswordIfNotUsingVariables( proxyPassword ) ); rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_host", socksProxyHost ); rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_port", socksProxyPort ); rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_username", socksProxyUsername ); rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_password", Encr .encryptPasswordIfNotUsingVariables( socksProxyPassword ) ); } catch ( KettleDatabaseException dbe ) { throw new KettleException( BaseMessages.getString( PKG, "JobFTPPUT.UnableToSaveToRepo", String .valueOf( id_job ) ), dbe ); } } /** * @return Returns the binaryMode. */ public boolean isBinaryMode() { return binaryMode; } /** * @param binaryMode The binaryMode to set. */ public void setBinaryMode( boolean binaryMode ) { this.binaryMode = binaryMode; } /** * @param timeout The timeout to set. */ public void setTimeout( int timeout ) { this.timeout = timeout; } /** * @return Returns the timeout. */ public int getTimeout() { return timeout; } /** * @return Returns the onlyGettingNewFiles. */ public boolean isOnlyPuttingNewFiles() { return onlyPuttingNewFiles; } /** * @param onlyPuttingNewFiles Only transfer new files to the remote host */ public void setOnlyPuttingNewFiles( boolean onlyPuttingNewFiles ) { this.onlyPuttingNewFiles = onlyPuttingNewFiles; } /** * Get the control encoding to be used for ftp'ing * * @return the used encoding */ public String getControlEncoding() { return controlEncoding; } /** * Set the encoding to be used for ftp'ing. This determines how names are translated in dir e.g. It does impact the * contents of the files being ftp'ed. * * @param encoding The encoding to be used. */ public void setControlEncoding( String encoding ) { this.controlEncoding = encoding; } /** * @return Returns the remoteDirectory. */ public String getRemoteDirectory() { return remoteDirectory; } /** * @param directory The remoteDirectory to set. */ public void setRemoteDirectory( String directory ) { this.remoteDirectory = directory; } /** * @return Returns the password. */ public String getPassword() { return password; } /** * @param password The password to set. */ public void setPassword( String password ) { this.password = password; } /** * @return Returns the serverName. */ public String getServerName() { return serverName; } /** * @param serverName The serverName to set. */ public void setServerName( String serverName ) { this.serverName = serverName; } /** * @return Returns the userName. */ public String getUserName() { return userName; } /** * @param userName The userName to set. */ public void setUserName( String userName ) { this.userName = userName; } /** * @return Returns the wildcard. */ public String getWildcard() { return wildcard; } /** * @param wildcard The wildcard to set. */ public void setWildcard( String wildcard ) { this.wildcard = wildcard; } /** * @return Returns the localDirectory. */ public String getLocalDirectory() { return localDirectory; } /** * @param directory The localDirectory to set. */ public void setLocalDirectory( String directory ) { this.localDirectory = directory; } /** * @param remove The remove to set. */ public void setRemove( boolean remove ) { this.remove = remove; } /** * @return Returns the remove. */ public boolean getRemove() { return remove; } public String getServerPort() { return serverPort; } public void setServerPort( String serverPort ) { this.serverPort = serverPort; } /** * @return the activeConnection */ public boolean isActiveConnection() { return activeConnection; } /** * @param activeConnection set to true to get an active FTP connection */ public void setActiveConnection( boolean activeConnection ) { this.activeConnection = activeConnection; } /** * @return Returns the hostname of the ftp-proxy. */ public String getProxyHost() { return proxyHost; } /** * @param proxyHost The hostname of the proxy. */ public void setProxyHost( String proxyHost ) { this.proxyHost = proxyHost; } /** * @return Returns the password which is used to authenticate at the proxy. */ public String getProxyPassword() { return proxyPassword; } /** * @param proxyPassword The password which is used to authenticate at the proxy. */ public void setProxyPassword( String proxyPassword ) { this.proxyPassword = proxyPassword; } /** * @return Returns the port of the ftp-proxy. */ public String getProxyPort() { return proxyPort; } /** * @param proxyPort The port of the ftp-proxy. */ public void setProxyPort( String proxyPort ) { this.proxyPort = proxyPort; } /** * @return Returns the username which is used to authenticate at the proxy. */ public String getProxyUsername() { return proxyUsername; } /** * @param socksProxyHost The socks proxy host to set */ public void setSocksProxyHost( String socksProxyHost ) { this.socksProxyHost = socksProxyHost; } /** * @param socksProxyPort The socks proxy port to set */ public void setSocksProxyPort( String socksProxyPort ) { this.socksProxyPort = socksProxyPort; } /** * @param socksProxyUsername The socks proxy username to set */ public void setSocksProxyUsername( String socksProxyUsername ) { this.socksProxyUsername = socksProxyUsername; } /** * @param socksProxyPassword The socks proxy password to set */ public void setSocksProxyPassword( String socksProxyPassword ) { this.socksProxyPassword = socksProxyPassword; } /** * @return The sox proxy host name */ public String getSocksProxyHost() { return this.socksProxyHost; } /** * @return The socks proxy port */ public String getSocksProxyPort() { return this.socksProxyPort; } /** * @return The socks proxy username */ public String getSocksProxyUsername() { return this.socksProxyUsername; } /** * @return The socks proxy password */ public String getSocksProxyPassword() { return this.socksProxyPassword; } /** * @param proxyUsername The username which is used to authenticate at the proxy. */ public void setProxyUsername( String proxyUsername ) { this.proxyUsername = proxyUsername; } public Result execute( Result previousResult, int nr ) { Result result = previousResult; result.setResult( false ); long filesput = 0; if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.Starting" ) ); } FTPClient ftpclient = null; try { // Create ftp client to host:port ... ftpclient = createAndSetUpFtpClient(); // login to ftp host ... String realUsername = environmentSubstitute( userName ); String realPassword = Encr.decryptPasswordOptionallyEncrypted( environmentSubstitute( password ) ); ftpclient.connect(); ftpclient.login( realUsername, realPassword ); // set BINARY if ( binaryMode ) { ftpclient.setType( FTPTransferType.BINARY ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.BinaryMode" ) ); } } // Remove password from logging, you don't know where it ends up. if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.Logged", realUsername ) ); } // Fix for PDI-2534 - add auxilliary FTP File List parsers to the ftpclient object. this.hookInOtherParsers( ftpclient ); // move to spool dir ... String realRemoteDirectory = environmentSubstitute( remoteDirectory ); if ( !Utils.isEmpty( realRemoteDirectory ) ) { ftpclient.chdir( realRemoteDirectory ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.ChangedDirectory", realRemoteDirectory ) ); } } String realLocalDirectory = environmentSubstitute( localDirectory ); if ( realLocalDirectory == null ) { throw new FTPException( BaseMessages.getString( PKG, "JobFTPPUT.LocalDir.NotSpecified" ) ); } else { // handle file:/// prefix if ( realLocalDirectory.startsWith( "file:" ) ) { realLocalDirectory = new URI( realLocalDirectory ).getPath(); } } final List<String> files; File localFiles = new File( realLocalDirectory ); File[] children = localFiles.listFiles(); if ( children == null ) { files = Collections.emptyList(); } else { files = new ArrayList<String>( children.length ); for ( File child : children ) { // Get filename of file or directory if ( !child.isDirectory() ) { files.add( child.getName() ); } } } if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.FoundFileLocalDirectory", "" + files.size(), realLocalDirectory ) ); } String realWildcard = environmentSubstitute( wildcard ); Pattern pattern; if ( !Utils.isEmpty( realWildcard ) ) { pattern = Pattern.compile( realWildcard ); } else { pattern = null; } for ( String file : files ) { if ( parentJob.isStopped() ) { break; } boolean toBeProcessed = true; // First see if the file matches the regular expression! if ( pattern != null ) { Matcher matcher = pattern.matcher( file ); toBeProcessed = matcher.matches(); } if ( toBeProcessed ) { // File exists? boolean fileExist = false; try { fileExist = ftpclient.exists( file ); } catch ( Exception e ) { // Assume file does not exist !! } if ( log.isDebug() ) { if ( fileExist ) { logDebug( BaseMessages.getString( PKG, "JobFTPPUT.Log.FileExists", file ) ); } else { logDebug( BaseMessages.getString( PKG, "JobFTPPUT.Log.FileDoesNotExists", file ) ); } } if ( !fileExist || !onlyPuttingNewFiles ) { if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobFTPPUT.Log.PuttingFileToRemoteDirectory", file, realRemoteDirectory ) ); } String localFilename = realLocalDirectory + Const.FILE_SEPARATOR + file; ftpclient.put( localFilename, file ); filesput++; // Delete the file if this is needed! if ( remove ) { new File( localFilename ).delete(); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.DeletedFile", localFilename ) ); } } } } } result.setResult( true ); if ( log.isDetailed() ) { logDebug( BaseMessages.getString( PKG, "JobFTPPUT.Log.WeHavePut", "" + filesput ) ); } } catch ( Exception e ) { result.setNrErrors( 1 ); logError( BaseMessages.getString( PKG, "JobFTPPUT.Log.ErrorPuttingFiles", e.getMessage() ) ); logError( Const.getStackTracker( e ) ); } finally { if ( ftpclient != null && ftpclient.connected() ) { try { ftpclient.quit(); } catch ( Exception e ) { logError( BaseMessages.getString( PKG, "JobFTPPUT.Log.ErrorQuitingFTP", e.getMessage() ) ); } } FTPClient.clearSOCKS(); } return result; } // package-local visibility for testing purposes FTPClient createAndSetUpFtpClient() throws IOException, FTPException { String realServerName = environmentSubstitute( serverName ); String realServerPort = environmentSubstitute( serverPort ); FTPClient ftpClient = createFtpClient(); ftpClient.setRemoteAddr( InetAddress.getByName( realServerName ) ); if ( !Utils.isEmpty( realServerPort ) ) { ftpClient.setRemotePort( Const.toInt( realServerPort, FTP_DEFAULT_PORT ) ); } if ( !Utils.isEmpty( proxyHost ) ) { String realProxyHost = environmentSubstitute( proxyHost ); ftpClient.setRemoteAddr( InetAddress.getByName( realProxyHost ) ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobEntryFTPPUT.OpenedProxyConnectionOn", realProxyHost ) ); } // FIXME: Proper default port for proxy int port = Const.toInt( environmentSubstitute( proxyPort ), FTP_DEFAULT_PORT ); if ( port != 0 ) { ftpClient.setRemotePort( port ); } } else { if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobEntryFTPPUT.OpenConnection", realServerName ) ); } } // set activeConnection connectmode ... if ( activeConnection ) { ftpClient.setConnectMode( FTPConnectMode.ACTIVE ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.SetActiveConnection" ) ); } } else { ftpClient.setConnectMode( FTPConnectMode.PASV ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.SetPassiveConnection" ) ); } } // Set the timeout if ( timeout > 0 ) { ftpClient.setTimeout( timeout ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.SetTimeout", "" + timeout ) ); } } ftpClient.setControlEncoding( controlEncoding ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.SetEncoding", controlEncoding ) ); } // If socks proxy server was provided if ( !Utils.isEmpty( socksProxyHost ) ) { // if a port was provided if ( !Utils.isEmpty( socksProxyPort ) ) { FTPClient.initSOCKS( environmentSubstitute( socksProxyPort ), environmentSubstitute( socksProxyHost ) ); } else { // looks like we have a host and no port throw new FTPException( BaseMessages.getString( PKG, "JobFTPPUT.SocksProxy.PortMissingException", environmentSubstitute( socksProxyHost ) ) ); } // now if we have authentication information if ( !Utils.isEmpty( socksProxyUsername ) && Utils.isEmpty( socksProxyPassword ) || Utils.isEmpty( socksProxyUsername ) && !Utils.isEmpty( socksProxyPassword ) ) { // we have a username without a password or vica versa throw new FTPException( BaseMessages.getString( PKG, "JobFTPPUT.SocksProxy.IncompleteCredentials", environmentSubstitute( socksProxyHost ), getName() ) ); } } return ftpClient; } // package-local visibility for testing purposes FTPClient createFtpClient() { return new PDIFTPClient( log ); } public boolean evaluates() { return true; } public List<ResourceReference> getResourceDependencies( JobMeta jobMeta ) { List<ResourceReference> references = super.getResourceDependencies( jobMeta ); if ( !Utils.isEmpty( serverName ) ) { String realServerName = jobMeta.environmentSubstitute( serverName ); ResourceReference reference = new ResourceReference( this ); reference.getEntries().add( new ResourceEntry( realServerName, ResourceType.SERVER ) ); references.add( reference ); } return references; } @Override public void check( List<CheckResultInterface> remarks, JobMeta jobMeta, VariableSpace space, Repository repository, IMetaStore metaStore ) { JobEntryValidatorUtils.andValidator().validate( this, "serverName", remarks, AndValidator.putValidators( JobEntryValidatorUtils.notBlankValidator() ) ); JobEntryValidatorUtils.andValidator().validate( this, "localDirectory", remarks, AndValidator.putValidators( JobEntryValidatorUtils.notBlankValidator(), JobEntryValidatorUtils.fileExistsValidator() ) ); JobEntryValidatorUtils.andValidator().validate( this, "userName", remarks, AndValidator.putValidators( JobEntryValidatorUtils.notBlankValidator() ) ); JobEntryValidatorUtils.andValidator().validate( this, "password", remarks, AndValidator.putValidators( JobEntryValidatorUtils.notNullValidator() ) ); JobEntryValidatorUtils.andValidator().validate( this, "serverPort", remarks, AndValidator.putValidators( JobEntryValidatorUtils.integerValidator() ) ); } /** * Hook in known parsers, and then those that have been specified in the variable ftp.file.parser.class.names * * @param ftpClient * @throws FTPException * @throws IOException */ protected void hookInOtherParsers( FTPClient ftpClient ) throws FTPException, IOException { if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Hooking.Parsers" ) ); } String system = ftpClient.system(); MVSFileParser parser = new MVSFileParser( log ); if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Created.MVS.Parser" ) ); } FTPFileFactory factory = new FTPFileFactory( system ); if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Created.Factory" ) ); } factory.addParser( parser ); ftpClient.setFTPFileFactory( factory ); if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Get.Variable.Space" ) ); } VariableSpace vs = this.getVariables(); if ( vs != null ) { if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Getting.Other.Parsers" ) ); } String otherParserNames = vs.getVariable( "ftp.file.parser.class.names" ); if ( otherParserNames != null ) { if ( log.isDebug() ) { logDebug( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Creating.Parsers" ) ); } String[] parserClasses = otherParserNames.split( "|" ); String cName = null; Class<?> clazz = null; Object parserInstance = null; for ( int i = 0; i < parserClasses.length; i++ ) { cName = parserClasses[ i ].trim(); if ( cName.length() > 0 ) { try { clazz = Class.forName( cName ); parserInstance = clazz.newInstance(); if ( parserInstance instanceof FTPFileParser ) { if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "JobEntryFTP.DEBUG.Created.Other.Parser", cName ) ); } factory.addParser( (FTPFileParser) parserInstance ); } } catch ( Exception ignored ) { if ( log.isDebug() ) { ignored.printStackTrace(); logError( BaseMessages.getString( PKG, "JobEntryFTP.ERROR.Creating.Parser", cName ) ); } } } } } } } }