re-adding src from branch to include FTPS support.

This commit is contained in:
Josh Long
2010-08-28 18:19:17 +00:00
parent 5f0ba7f578
commit 02faab51dc
36 changed files with 2514 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
package org.springframework.integration.ftp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.integration.MessagingException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.net.SocketException;
abstract public class AbstractFtpClientFactory<T extends FTPClient> implements FtpClientFactory<T> {
private static final Log logger = LogFactory.getLog(FtpClientFactory.class);
private static final String DEFAULT_REMOTE_WORKING_DIRECTORY = "/";
protected FTPClientConfig config;
protected String username;
protected String host;
protected String password;
protected int port = FTP.DEFAULT_PORT;
protected String remoteWorkingDirectory = DEFAULT_REMOTE_WORKING_DIRECTORY;
protected int clientMode = FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE;
protected int fileType = FTP.BINARY_FILE_TYPE;
public void setFileType(int fileType) {
this.fileType = fileType;
}
public void setConfig(FTPClientConfig config) {
Assert.notNull(config);
this.config = config;
}
public void setHost(String host) {
Assert.hasText(host);
this.host = host;
}
public void setPort(int port) {
Assert.isTrue(port > 0, "Port number should be > 0");
this.port = port;
}
public void setUsername(String user) {
Assert.hasText(user, "'user' should be a nonempty string");
this.username = user;
}
public void setPassword(String pass) {
Assert.notNull(pass, "password should not be null");
this.password = pass;
}
public void setRemoteWorkingDirectory(String remoteWorkingDirectory) {
Assert.notNull(remoteWorkingDirectory, "remote directory should not be null");
this.remoteWorkingDirectory = remoteWorkingDirectory.replaceAll("^$", "/");
}
/**
* Set client mode for example
* <code>FTPClient.ACTIVE_LOCAL_CONNECTION_MODE</code> (default) Only local
* modes are supported.
*/
public void setClientMode(int clientMode) {
this.clientMode = clientMode;
}
protected abstract T createSingleInstanceOfClient();
/**
* this is a hook to setup the state of the {@link org.apache.commons.net.ftp.FTPClient} impl *after* the
* implementation's {@link org.apache.commons.net.ftp.FTPClient#connect(String)} method's been called but before any
* action's been taken.
*
* @param t the ftp client instance on which to act
* @throws IOException if anything should go wrong
*/
protected void onAfterConnect(T t) throws IOException {
// NOOP
}
public T getClient() throws SocketException, IOException {
T client = createSingleInstanceOfClient();
client.configure(config);
if (!StringUtils.hasText(username)) {
throw new MessagingException("username is required");
}
client.connect(host);
onAfterConnect(client);
if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
throw new MessagingException("Connecting to server [" + host + ":" + port + "] failed, please check the connection");
}
if (logger.isDebugEnabled()) {
logger.debug("Connected to server [" + host + ":" + port + "]");
}
if (!client.login(username, password)) {
throw new MessagingException("Login failed. Please check the username and password.");
}
setClientMode(client);
client.setFileType(this.fileType);
if (logger.isDebugEnabled()) {
logger.debug("login successful");
}
if (!remoteWorkingDirectory.equals(client.printWorkingDirectory()) && !client.changeWorkingDirectory(remoteWorkingDirectory)) {
throw new MessagingException("Could not change directory to '" + remoteWorkingDirectory + "'. Please check the path.");
}
if (logger.isDebugEnabled()) {
logger.debug("working directory is: " + client.printWorkingDirectory());
}
return client;
}
/**
* Sets the mode of the connection. Only local modes are supported.
*/
protected void setClientMode(FTPClient client) {
switch (clientMode) {
case FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE:
client.enterLocalActiveMode();
break;
case FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE:
client.enterLocalPassiveMode();
break;
default:
break;
}
}
}

View File

@@ -0,0 +1,85 @@
package org.springframework.integration.ftp;
import org.springframework.util.StringUtils;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
/**
* Factors out the client factory creaton
*
* @author Josh Long
*/
public class ClientFactorySupport {
public static DefaultFtpsClientFactory ftpsClientFactory(String host, int port, String remoteDir, String user, String pw, int fileType, int clientMode, String prot, String protocol,
String authValue, Boolean implicit, TrustManager trustManager, KeyManager keyManager, Boolean sessionCreation, Boolean useClientMode, Boolean wantsClientAuth, Boolean needClientAuth , String [] cipherSuites) {
DefaultFtpsClientFactory defaultFtpClientFactory = new DefaultFtpsClientFactory();
defaultFtpClientFactory.setHost(host);
defaultFtpClientFactory.setPassword(pw);
defaultFtpClientFactory.setPort((port));
defaultFtpClientFactory.setRemoteWorkingDirectory(remoteDir);
defaultFtpClientFactory.setUsername(user);
defaultFtpClientFactory.setFileType(fileType);
defaultFtpClientFactory.setClientMode(clientMode);
if(cipherSuites !=null)
defaultFtpClientFactory.setCipherSuites( cipherSuites );
if (StringUtils.hasText(prot)) {
defaultFtpClientFactory.setProt(prot);
}
if (StringUtils.hasText(protocol)) {
defaultFtpClientFactory.setProtocol(protocol);
}
if (StringUtils.hasText(authValue)) {
defaultFtpClientFactory.setAuthValue(authValue);
}
if (null != implicit) {
defaultFtpClientFactory.setImplicit(implicit);
}
if (trustManager != null) {
defaultFtpClientFactory.setTrustManager(trustManager);
}
if (keyManager != null) {
defaultFtpClientFactory.setKeyManager(keyManager);
}
if (needClientAuth != null) {
defaultFtpClientFactory.setNeedClientAuth(needClientAuth);
}
if (wantsClientAuth != null) {
defaultFtpClientFactory.setWantsClientAuth(wantsClientAuth);
}
if (sessionCreation != null) {
defaultFtpClientFactory.setSessionCreation(sessionCreation);
}
if (useClientMode != null) {
defaultFtpClientFactory.setUseClientMode(useClientMode);
}
return defaultFtpClientFactory;
}
public static DefaultFtpClientFactory ftpClientFactory(String host, int port, String remoteDir, String user, String pw, int clientMode) {
DefaultFtpClientFactory defaultFtpClientFactory = new DefaultFtpClientFactory();
defaultFtpClientFactory.setHost(host);
defaultFtpClientFactory.setPassword(pw);
defaultFtpClientFactory.setPort(port);
defaultFtpClientFactory.setRemoteWorkingDirectory(remoteDir);
defaultFtpClientFactory.setUsername(user);
defaultFtpClientFactory.setClientMode(clientMode);
return defaultFtpClientFactory;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.springframework.integration.ftp;
import org.apache.commons.net.ftp.FTPClient;
/**
* Default implementation of FtpClientFactory.
*
* @author iwein
* @author Josh Long
*/
public class DefaultFtpClientFactory extends AbstractFtpClientFactory<FTPClient> {
@Override
protected FTPClient createSingleInstanceOfClient() {
return new FTPClient();
}
}

View File

@@ -0,0 +1,193 @@
package org.springframework.integration.ftp;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPSClient;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
/**
* provides a working FTPS implementation
*
* @author Josh Long
*/
public class DefaultFtpsClientFactory extends AbstractFtpClientFactory<FTPSClient> {
private Boolean useClientMode;
private Boolean sessionCreation;
private String authValue;
private TrustManager trustManager;
private String[] cipherSuites;
private String[] protocols;
private KeyManager keyManager;
private Boolean needClientAuth;
private Boolean wantsClientAuth;
private boolean implicit = false;
private String prot = "P";
private String protocol;
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public static void main(String[] args) throws Throwable {
File file = new File(SystemUtils.getUserHome(), "Desktop/ftp.properties");
Resource r = new FileSystemResource(file);
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(r);
propertiesFactoryBean.afterPropertiesSet();
Properties props = propertiesFactoryBean.getObject();
String user = props.getProperty("ftp.username");
String pw = props.getProperty("ftp.password");
String host = props.getProperty("ftp.host");
if (!file.exists()) {
throw new RuntimeException("doesn't exist");
}
DefaultFtpsClientFactory defaultFtpsClientFactory = new DefaultFtpsClientFactory();
defaultFtpsClientFactory.setUsername(user);
defaultFtpsClientFactory.setImplicit(false);
defaultFtpsClientFactory.setPassword(pw);
defaultFtpsClientFactory.setClientMode(FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE);
defaultFtpsClientFactory.setHost(host);
FTPSClient ftpClient = defaultFtpsClientFactory.getClient();
InputStream fileStream = r.getInputStream();
ftpClient.storeFile("pushed.java", fileStream);
fileStream.close();
ftpClient.disconnect();
}
public void setUseClientMode(Boolean useClientMode) {
this.useClientMode = useClientMode;
}
public void setSessionCreation(Boolean sessionCreation) {
this.sessionCreation = sessionCreation;
}
public void setAuthValue(String authValue) {
this.authValue = authValue;
}
public void setTrustManager(TrustManager trustManager) {
this.trustManager = trustManager;
}
public void setCipherSuites(String[] cipherSuites) {
this.cipherSuites = cipherSuites;
}
public void setProtocols(String[] protocols) {
this.protocols = protocols;
}
public void setKeyManager(KeyManager keyManager) {
this.keyManager = keyManager;
}
public void setNeedClientAuth(Boolean needClientAuth) {
this.needClientAuth = needClientAuth;
}
public void setWantsClientAuth(Boolean wantsClientAuth) {
this.wantsClientAuth = wantsClientAuth;
}
public void setProt(String prot) {
this.prot = prot;
}
@Override
protected void onAfterConnect(FTPSClient ftpsClient)
throws IOException {
ftpsClient.execPBSZ(0);
ftpsClient.execPROT(this.prot);
}
@Override
public FTPSClient getClient() throws SocketException, IOException {
FTPSClient ftpsClient = super.getClient();
if (StringUtils.hasText(this.authValue)) {
ftpsClient.setAuthValue(authValue);
}
if (this.trustManager != null) {
ftpsClient.setTrustManager(this.trustManager);
}
if (this.cipherSuites != null) {
ftpsClient.setEnabledCipherSuites(this.cipherSuites);
}
if (this.protocols != null) {
ftpsClient.setEnabledProtocols(this.protocols);
}
if (this.sessionCreation != null) {
ftpsClient.setEnabledSessionCreation(this.sessionCreation);
}
if (this.useClientMode != null) {
ftpsClient.setUseClientMode(this.useClientMode);
}
if (this.sessionCreation != null) {
ftpsClient.setEnabledSessionCreation(this.sessionCreation);
}
if (this.keyManager != null) {
ftpsClient.setKeyManager(keyManager);
}
if (this.needClientAuth != null) {
ftpsClient.setNeedClientAuth(this.needClientAuth);
}
if (this.wantsClientAuth != null) {
ftpsClient.setWantClientAuth(this.wantsClientAuth);
}
return ftpsClient;
}
public void setImplicit(boolean implicit) {
this.implicit = implicit;
}
@Override
protected FTPSClient createSingleInstanceOfClient() {
try {
if (StringUtils.hasText(this.protocol)) {
return new FTPSClient(this.protocol, this.implicit);
}
return new FTPSClient(this.implicit);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.springframework.integration.ftp;
import org.apache.commons.net.ftp.FTPClient;
import java.io.IOException;
/**
* Factory for {@link FTPClient}.
*
* @author Iwein Fuld
*/
public interface FtpClientFactory <T extends FTPClient>{
/**
* @return Fully configured and connected FTPClient. Never <code>null</code>.
* @throws IOException thrown when a networking IO subsystem error occurs
*/
T getClient() throws IOException;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.springframework.integration.ftp;
import org.apache.commons.net.ftp.FTPClient;
/**
* A pool of {@link FTPClient} instances. The pool can be used to control the
* number of open FTP connections and reuse these connections efficiently.
*
* @author Iwein Fuld
*/
public interface FtpClientPool extends FtpClientFactory {
/**
* Releases the client back to the pool. When calling this method the caller
* is no longer responsible for the connection. The pool is free to do with
* it as it sees fit, which means either recycling or disconnecting it most
* probably.
* <p/>
* The caller should NOT disconnect the client before calling this method.
* <p/>
* The caller is NOT expected to use the client after calling this method.
* Doing so can lead to unexpected behavior.
*
* @param client the {@link FTPClient} to release. Implementations of this
* method are recommended to deal gracefully with a <code>null</code>
* argument, although the endpoint implementations in
* <code>org.springframework.integration.ftp</code> will never pass in
* <code>null</code>.
*/
void releaseClient(FTPClient client);
}

View File

@@ -0,0 +1,16 @@
package org.springframework.integration.ftp;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.integration.file.entries.EntryNamer;
/**
* A {@link org.springframework.integration.file.entries.EntryNamer} for {@link org.apache.commons.net.ftp.FTPFile} objects
*
* @author Josh Long
*/
public class FtpFileEntryNamer implements EntryNamer<FTPFile> {
public String nameOf(FTPFile entry) {
return entry.getName();
}
}

View File

@@ -0,0 +1,199 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.springframework.integration.ftp;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.integration.Message;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import java.io.*;
import java.net.SocketException;
/**
* A {@link org.springframework.integration.core.MessageHandler} implementation that sends files to an FTP server.
*
* @author Iwein Fuld
* @author Mark Fisher
* @author Josh Long
*/
public class FtpSendingMessageHandler implements MessageHandler, InitializingBean {
private FtpClientPool ftpClientPool;
public FtpSendingMessageHandler() {
}
public FtpSendingMessageHandler(FtpClientPool ftpClientPool) {
this.ftpClientPool = ftpClientPool;
}
public void setFtpClientPool(FtpClientPool ftpClientPool) {
this.ftpClientPool = ftpClientPool;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(ftpClientPool, "'ftpClientPool' must not be null");
Assert.notNull(temporaryBufferFolder, "'temporaryBufferFolder' must not be null");
temporaryBufferFolderFile = this.temporaryBufferFolder.getFile();
}
/* Ugh this needs to be put in a convenient place accessible for all the file:, sftp:, and ftp:* adapters */
private File handleFileMessage(File sourceFile, File tempFile, File resultFile)
throws IOException {
if (sourceFile.renameTo(resultFile)) {
return resultFile;
}
FileCopyUtils.copy(sourceFile, tempFile);
tempFile.renameTo(resultFile);
return resultFile;
}
private File handleByteArrayMessage(byte[] bytes, File tempFile, File resultFile)
throws IOException {
FileCopyUtils.copy(bytes, tempFile);
tempFile.renameTo(resultFile);
return resultFile;
}
private File handleStringMessage(String content, File tempFile, File resultFile, String charset)
throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tempFile), charset);
FileCopyUtils.copy(content, writer);
tempFile.renameTo(resultFile);
return resultFile;
}
private static final String TEMPORARY_FILE_SUFFIX = ".writing";
private FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
private File temporaryBufferFolderFile;
private Resource temporaryBufferFolder = new FileSystemResource(SystemUtils.getJavaIoTmpDir());
public void setTemporaryBufferFolder(Resource temporaryBufferFolder) {
this.temporaryBufferFolder = temporaryBufferFolder;
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
this.fileNameGenerator = fileNameGenerator;
}
private File redeemForStorableFile(Message<?> msg) throws MessageDeliveryException {
try {
Object payload = msg.getPayload();
String generateFileName = this.fileNameGenerator.generateFileName(msg);
File tempFile = new File(temporaryBufferFolderFile, generateFileName + TEMPORARY_FILE_SUFFIX);
File resultFile = new File(temporaryBufferFolderFile, generateFileName);
File sendableFile;
if (payload instanceof String)
sendableFile = this.handleStringMessage((String) payload, tempFile, resultFile, this.charset);
else if (payload instanceof File)
sendableFile = this.handleFileMessage((File) payload, tempFile, resultFile);
else if (payload instanceof byte[])
sendableFile = this.handleByteArrayMessage((byte[]) payload, tempFile, resultFile);
else sendableFile = null;
return sendableFile;
} catch (Throwable th) {
throw new MessageDeliveryException(msg);
}
}
private String charset;
public void setCharset(String charset) {
this.charset = charset;
}
/* Ugh this needs to be put in a convenient place accessible for all the file:, sftp:, and ftp:* adapters */
public void handleMessage(Message<?> message) throws MessageRejectedException,
MessageHandlingException, MessageDeliveryException {
Assert.notNull(message, "'message' must not be null");
Object payload = message.getPayload();
Assert.notNull(payload, "Message payload must not be null");
File file = this.redeemForStorableFile(message);
if ((file != null) && file.exists()) {
FTPClient client = null;
boolean sentSuccesfully;
try {
client = getFtpClient();
sentSuccesfully = sendFile(file, client);
} catch (FileNotFoundException e) {
throw new MessageDeliveryException(message, "File [" + file + "] not found in local working directory; it was moved or deleted unexpectedly", e);
} catch (IOException e) {
throw new MessageDeliveryException(message, "Error transferring file [" + file + "] from local working directory to remote FTP directory", e);
} catch (Exception e) {
throw new MessageDeliveryException(message, "Error handling message for file [" + file + "]", e);
} finally {
if (file.exists())
try {
file.delete();
} catch (Throwable th) {
/// noop
}
if (client != null) {
ftpClientPool.releaseClient(client);
}
}
if (!sentSuccesfully) {
throw new MessageDeliveryException(message, "Failed to store file '" + file + "'");
}
}
}
private boolean sendFile(File file, FTPClient client)
throws FileNotFoundException, IOException {
FileInputStream fileInputStream = new FileInputStream(file);
boolean sent = client.storeFile(file.getName(), fileInputStream);
fileInputStream.close();
return sent;
}
private FTPClient getFtpClient() throws SocketException, IOException {
FTPClient client;
client = this.ftpClientPool.getClient();
Assert.state(client != null, FtpClientPool.class.getSimpleName() + " returned 'null' client this most likely a bug in the pool implementation.");
return client;
}
}

View File

@@ -0,0 +1,86 @@
package org.springframework.integration.ftp;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
/**
* A factory bean implementation that handles constructing an outbound FTP adapter.
*
* @author Josh Long
*/
public class FtpSendingMessageHandlerFactoryBean extends AbstractFactoryBean<FtpSendingMessageHandler> implements ResourceLoaderAware, ApplicationContextAware {
protected int port;
protected String username;
protected String password;
protected String host;
protected String remoteDirectory;
protected int clientMode;
// private vars
private ResourceLoader resourceLoader;
private ApplicationContext applicationContext;
public void setClientMode(int clientMode) {
this.clientMode = clientMode;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Class<?extends FtpSendingMessageHandler> getObjectType() {
return FtpSendingMessageHandler.class;
}
protected AbstractFtpClientFactory clientFactory() {
return ClientFactorySupport.ftpClientFactory( this.host, this.port , this.remoteDirectory , this.username , this.password , this.clientMode );
}
@Override
protected FtpSendingMessageHandler createInstance()
throws Exception {
// the dependencies for the outbound-adapter are much simpler
// they only require an instance of the pool
AbstractFtpClientFactory defaultFtpClientFactory = clientFactory();
QueuedFtpClientPool queuedFtpClientPool = new QueuedFtpClientPool(15, defaultFtpClientFactory);
FtpSendingMessageHandler ftpSendingMessageHandler = new FtpSendingMessageHandler(queuedFtpClientPool);
ftpSendingMessageHandler.afterPropertiesSet();
return ftpSendingMessageHandler;
}
public void setPort(int port) {
this.port = port;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setHost(String host) {
this.host = host;
}
public void setRemoteDirectory(String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
}

View File

@@ -0,0 +1,89 @@
package org.springframework.integration.ftp;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
public class FtpsSendingMessageHandlerFactoryBean extends FtpSendingMessageHandlerFactoryBean {
/**
* Sets whether the connection is implicit. Local testing reveals this to be a good choice.
*/
protected volatile Boolean implicit = Boolean.FALSE;
/**
* "TLS" or "SSL"
*/
protected volatile String protocol;
/**
* "P"
*/
protected volatile String prot;
private KeyManager keyManager;
private TrustManager trustManager;
protected volatile String authValue;
private Boolean sessionCreation;
private Boolean useClientMode;
private Boolean needClientAuth;
private Boolean wantsClientAuth;
private String[] cipherSuites;
public void setImplicit(Boolean implicit) {
this.implicit = implicit;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void setProt(String prot) {
this.prot = prot;
}
public void setKeyManager(KeyManager keyManager) {
this.keyManager = keyManager;
}
public void setTrustManager(TrustManager trustManager) {
this.trustManager = trustManager;
}
public void setAuthValue(String authValue) {
this.authValue = authValue;
}
public void setSessionCreation(Boolean sessionCreation) {
this.sessionCreation = sessionCreation;
}
public void setUseClientMode(Boolean useClientMode) {
this.useClientMode = useClientMode;
}
public void setNeedClientAuth(Boolean needClientAuth) {
this.needClientAuth = needClientAuth;
}
public void setWantsClientAuth(Boolean wantsClientAuth) {
this.wantsClientAuth = wantsClientAuth;
}
public void setCipherSuites(String[] cipherSuites) {
this.cipherSuites = cipherSuites;
}
private int fileType ;
public void setFileType(int fileType) {
this.fileType = fileType;
}
@Override
protected AbstractFtpClientFactory clientFactory() {
DefaultFtpsClientFactory factory = ClientFactorySupport.ftpsClientFactory(
this.host, (this.port), this.remoteDirectory, this.username, this.password, this.fileType,
this.clientMode, this.prot, this.protocol, this.authValue, this.implicit, this.trustManager, this.keyManager, this.sessionCreation, this.useClientMode, this.wantsClientAuth,
this.needClientAuth, this.cipherSuites);
return factory;
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* 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.springframework.integration.ftp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.util.Assert;
import java.io.IOException;
import java.net.SocketException;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
/**
* FtpClientPool implementation based on a Queue. This implementation has a
* default pool size of 5, but this is configurable with a constructor argument.
* <p/>
* This implementation pools released clients, but gives no guarantee to the
* number of clients open at the same time.
*
* @author Iwein Fuld
*/
public class QueuedFtpClientPool implements FtpClientPool {
private static final Log log = LogFactory.getLog(QueuedFtpClientPool.class);
private static final int DEFAULT_POOL_SIZE = 5;
private final Queue<FTPClient> pool;
private final FtpClientFactory factory;
public QueuedFtpClientPool(FtpClientFactory factory) {
this(DEFAULT_POOL_SIZE, factory);
}
/**
* @param maxPoolSize the maximum size of the pool
*/
public QueuedFtpClientPool(int maxPoolSize, FtpClientFactory factory) {
Assert.notNull(factory);
this.factory = factory;
pool = new ArrayBlockingQueue<FTPClient>(maxPoolSize);
}
/**
* Returns an active FTPClient connected to the configured server. When no
* clients are available in the queue a new client is created with the
* factory.
* <p/>
* It is possible that released clients are disconnected by the remote
* server (@see {@link FTPClient#sendNoOp()}. In this case getClient is
* called recursively to obtain a client that is still alive. For this
* reason large pools are not recommended in poor networking conditions.
*/
public FTPClient getClient() throws SocketException, IOException {
FTPClient client = pool.poll();
if (client == null) {
client = factory.getClient();
}
return prepareClient(client);
}
/**
* Prepares the client before it is returned through
* <code>getClient()</code>. The default implementation will check the
* connection using a noOp and replace the client with a new one if it
* encounters a problem.
* <p/>
* In more exotic environments subclasses can override this method to
* implement their own preparation strategy.
*
* @param client the unprepared client
* @return
* @throws SocketException
* @throws IOException
*/
protected FTPClient prepareClient(FTPClient client)
throws SocketException, IOException {
return isClientAlive(client) ? client : getClient();
}
private boolean isClientAlive(FTPClient client) {
try {
if (client.sendNoOp()) {
return true;
}
} catch (IOException e) {
log.warn("Client [" + client + "] discarded: ", e);
}
return false;
}
public void releaseClient(FTPClient client) {
if ((client != null) && !pool.offer(client)) {
try {
client.disconnect();
} catch (IOException e) {
log.warn("Error disconnecting ftpclient", e);
}
}
}
}

View File

@@ -0,0 +1,25 @@
package org.springframework.integration.ftp.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.ftp.FtpSendingMessageHandlerFactoryBean;
import org.w3c.dom.Element;
/**
* Logic for parsing the ftp:outbound-channel-adapter
*
* @author Josh Long
*/
public class FtpMessageSendingConsumerBeanDefinitionParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FtpSendingMessageHandlerFactoryBean.class.getName());
FtpNamespaceParserSupport.configureCoreFtpClient(builder, element, parserContext);
return builder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,40 @@
package org.springframework.integration.ftp.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.ftp.impl.FtpRemoteFileSystemSynchronizingMessageSourceFactoryBean;
import org.w3c.dom.Element;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Logic that configures an ftp:inbound-channel-adapter
*
* @author Josh Long
*/
public class FtpMessageSourceBeanDefinitionParser extends AbstractPollingInboundChannelAdapterParser {
private Set<String> receiveAttrs = new HashSet<String>(Arrays.asList("auto-delete-remote-files-on-sync,filename-pattern,local-working-directory".split(",")));
@Override
@SuppressWarnings("unused")
protected String parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FtpRemoteFileSystemSynchronizingMessageSourceFactoryBean.class.getName());
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "filter");
for (String a : receiveAttrs)
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, a);
FtpNamespaceParserSupport.configureCoreFtpClient(builder, element, parserContext);
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2010 the original author or authors
*
* 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.springframework.integration.ftp.config;
import org.apache.commons.net.ftp.FTP;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import java.util.HashMap;
import java.util.Map;
/**
* Provides namespace support for using FTP
* <p/>
* This is *heavily* influenced by the good work done by Iwein before.
*
* @author Josh Long
*/
@SuppressWarnings("unused")
public class FtpNamespaceHandler extends NamespaceHandlerSupport {
static public Map<String, Integer> FILE_TYPES = new HashMap<String, Integer>();
static public Map<String, Integer> CLIENT_MODES = new HashMap<String, Integer>();
static {
// file types
FILE_TYPES.put("ebcdic-file-type" , FTP.EBCDIC_FILE_TYPE);
FILE_TYPES.put("ascii-file-type" , FTP.ASCII_FILE_TYPE);
FILE_TYPES.put("binary-file-type" , FTP.BINARY_FILE_TYPE);
// client modes
CLIENT_MODES.put("active-local-data-connection-mode", 0);
CLIENT_MODES.put("active-remote-data-connection-mode", 1);
CLIENT_MODES.put("passive-local-data-connection-mode", 2);
CLIENT_MODES.put("passive-remote-data-connection-mode", 3);
}
public void init() {
registerBeanDefinitionParser("inbound-channel-adapter", new FtpMessageSourceBeanDefinitionParser());
registerBeanDefinitionParser("outbound-channel-adapter", new FtpMessageSendingConsumerBeanDefinitionParser());
}
}

View File

@@ -0,0 +1,38 @@
package org.springframework.integration.ftp.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.w3c.dom.Element;
/**
* A lot of parsers need to support the same set of core attributes, so I'm hiding that logic here
*
* @author Josh Long
*
*/
public class FtpNamespaceParserSupport {
/**
* lots of values are supported across all adapters, let this code handle it initially
*
* @param builder a builder
* @param element an element
* @param parserContext a parser context
*/
public static void configureCoreFtpClient(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
for (String p : "auto-create-directories,username,port,password,host,remote-directory".split(",")) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, p);
}
if (element.hasAttribute("file-type")) {
int fileType = FtpNamespaceHandler.FILE_TYPES.get(element.getAttribute("file-type"));
builder.addPropertyValue("fileType", fileType);
}
if (element.hasAttribute("client-mode")) {
int clientMode = FtpNamespaceHandler.CLIENT_MODES.get(element.getAttribute("client-mode"));
builder.addPropertyValue("clientMode", clientMode);
}
}
}

View File

@@ -0,0 +1,26 @@
package org.springframework.integration.ftp.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.ftp.FtpSendingMessageHandlerFactoryBean;
import org.springframework.integration.ftp.FtpsSendingMessageHandlerFactoryBean;
import org.w3c.dom.Element;
/**
* Logic for parsing the ftp:outbound-channel-adapter
*
* @author Josh Long
*/
public class FtpsMessageSendingConsumerBeanDefinitionParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FtpsSendingMessageHandlerFactoryBean.class.getName());
FtpNamespaceParserSupport.configureCoreFtpClient(builder, element, parserContext);
return builder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,39 @@
package org.springframework.integration.ftp.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.ftp.impl.FtpRemoteFileSystemSynchronizingMessageSourceFactoryBean;
import org.springframework.integration.ftp.impl.FtpsRemoteFileSystemSynchronizingMessageSourceFactoryBean;
import org.w3c.dom.Element;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Logic that configures an ftp:inbound-channel-adapter
*
* @author Josh Long
*/
public class FtpsMessageSourceBeanDefinitionParser extends AbstractPollingInboundChannelAdapterParser {
private Set<String> receiveAttrs = new HashSet<String>(Arrays.asList("auto-delete-remote-files-on-sync,filename-pattern,local-working-directory".split(",")));
@Override
@SuppressWarnings("unused")
protected String parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FtpsRemoteFileSystemSynchronizingMessageSourceFactoryBean.class.getName());
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "filter");
for (String a : receiveAttrs)
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, a);
FtpNamespaceParserSupport.configureCoreFtpClient(builder, element, parserContext);
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2010 the original author or authors
*
* 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.springframework.integration.ftp.config;
/**
* Provides namespace support for using FTP
* <p/>
* This is *heavily* influenced by the good work done by Iwein before.
*
*
* @author Josh Long
*/
@SuppressWarnings("unused")
public class FtpsNamespaceHandler extends FtpNamespaceHandler {
@Override
public void init() {
this.registerBeanDefinitionParser( "inbound-channel-adapter", new FtpsMessageSourceBeanDefinitionParser());
// todo test this
this.registerBeanDefinitionParser( "outbound-channel-adapter", new FtpsMessageSendingConsumerBeanDefinitionParser());
}
}

View File

@@ -0,0 +1,118 @@
package org.springframework.integration.ftp.impl;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.core.io.Resource;
import org.springframework.integration.MessagingException;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.ftp.FtpClientPool;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.util.Assert;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
/**
* An FTP-adapter implementation of {@link org.springframework.integration.file.AbstractInboundRemoteFileSystemSychronizer}
*
* @author Josh Long
*/
public class FtpInboundRemoteFileSystemSynchronizer extends AbstractInboundRemoteFileSystemSychronizer<FTPFile> {
protected FtpClientPool clientPool;
@Override
protected void onInit() throws Exception {
Assert.notNull(this.clientPool, "clientPool can't be null");
if (this.shouldDeleteSourceFile) {
this.entryAcknowledgmentStrategy = new DeletionEntryAcknowledgmentStrategy();
}
}
/**
* The {@link org.springframework.integration.ftp.FtpClientPool} that holds references to {@link org.apache.commons.net.ftp.FTPClient} instances
*
* @param clientPool the {@link org.springframework.integration.ftp.FtpClientPool}
*/
public void setClientPool(FtpClientPool clientPool) {
this.clientPool = clientPool;
}
protected boolean copyFileToLocalDirectory(FTPClient client, FTPFile ftpFile, Resource localDirectory)
throws IOException, FileNotFoundException {
String remoteFileName = ftpFile.getName();
String localFileName = localDirectory.getFile().getPath() + "/" + remoteFileName;
File localFile = new File(localFileName);
if (!localFile.exists()) {
String tempFileName = localFileName + AbstractInboundRemoteFileSystemSynchronizingMessageSource.INCOMPLETE_EXTENSION;
File file = new File(tempFileName);
FileOutputStream fos = new FileOutputStream(file);
try {
client.retrieveFile(remoteFileName, fos);
// Perhaps we have some dispatch of hte source file to do?
acknowledge(client, ftpFile);
} catch (Throwable th) {
throw new RuntimeException(th);
} finally {
fos.close();
}
file.renameTo(localFile);
return true;
} else {
return false;
}
}
@Override
protected void syncRemoteToLocalFileSystem() {
try {
FTPClient client = this.clientPool.getClient();
Assert.state(client != null, FtpClientPool.class.getSimpleName() + " returned a 'null' client. " + "This most likely a bug in the pool implementation.");
Collection<FTPFile> fileList = this.filter.filterEntries(client.listFiles());
try {
for (FTPFile ftpFile : fileList) {
if ((ftpFile != null) && ftpFile.isFile()) {
copyFileToLocalDirectory(client, ftpFile, this.localDirectory);
}
}
} finally {
this.clientPool.releaseClient(client);
}
} catch (IOException e) {
throw new MessagingException("Problem occurred while synchronizing remote to local directory", e);
}
}
@Override
protected Trigger getTrigger() {
return new PeriodicTrigger(10 * 1000);
}
/**
* An ackowledgment strategy that deletes
*/
class DeletionEntryAcknowledgmentStrategy implements AbstractInboundRemoteFileSystemSychronizer.EntryAcknowledgmentStrategy<FTPFile> {
public void acknowledge(Object useful, FTPFile msg)
throws Exception {
FTPClient ftpClient = (FTPClient) useful;
if ((msg != null) && ftpClient.deleteFile(msg.getName())) {
if (logger.isDebugEnabled()) {
logger.debug("deleted " + msg.getName());
}
}
}
}
}

View File

@@ -0,0 +1,35 @@
package org.springframework.integration.ftp.impl;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.integration.file.AbstractInboundRemoteFileSystemSynchronizingMessageSource;
import org.springframework.integration.ftp.FtpClientPool;
/**
* a {@link org.springframework.integration.core.MessageSource} implementation for FTP
*
* @author Josh Long
*/
public class FtpInboundRemoteFileSystemSynchronizingMessageSource extends AbstractInboundRemoteFileSystemSynchronizingMessageSource<FTPFile, FtpInboundRemoteFileSystemSynchronizer> {
private volatile FtpClientPool clientPool;
public void setClientPool(FtpClientPool clientPool) {
this.clientPool = clientPool;
}
@Override
protected void doStart() {
this.synchronizer.start();
}
@Override
protected void doStop() {
this.synchronizer.stop();
}
@Override
protected void onInit() throws Exception {
super.onInit();
this.synchronizer.setClientPool(this.clientPool);
}
}

View File

@@ -0,0 +1,173 @@
package org.springframework.integration.ftp.impl;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.integration.file.entries.CompositeEntryListFilter;
import org.springframework.integration.file.entries.EntryListFilter;
import org.springframework.integration.file.entries.PatternMatchingEntryListFilter;
import org.springframework.integration.ftp.*;
import org.springframework.util.StringUtils;
import java.io.File;
/**
* Factory to make building the namespace easier
*
* @author Josh Long
*/
public class FtpRemoteFileSystemSynchronizingMessageSourceFactoryBean extends AbstractFactoryBean<FtpInboundRemoteFileSystemSynchronizingMessageSource> implements ResourceLoaderAware {
protected volatile String port;
protected volatile String autoCreateDirectories;
protected volatile String filenamePattern;
protected volatile String username;
protected volatile String password;
protected volatile String host;
protected volatile String remoteDirectory;
protected volatile String localWorkingDirectory;
protected volatile ResourceLoader resourceLoader;
protected volatile Resource localDirectoryResource;
protected volatile EntryListFilter<FTPFile> filter;
protected volatile int clientMode = FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE;
protected volatile int fileType = FTP.BINARY_FILE_TYPE;
public void setFileType(int fileType) {
this.fileType = fileType;
}
private volatile String autoDeleteRemoteFilesOnSync;
@SuppressWarnings("unused")
public void setAutoDeleteRemoteFilesOnSync(String autoDeleteRemoteFilesOnSync) {
this.autoDeleteRemoteFilesOnSync = autoDeleteRemoteFilesOnSync;
}
@Override
public Class<?> getObjectType() {
return FtpInboundRemoteFileSystemSynchronizingMessageSource.class;
}
private Resource fromText(String path) {
ResourceEditor resourceEditor = new ResourceEditor(this.resourceLoader);
resourceEditor.setAsText(path);
return (Resource) resourceEditor.getValue();
}
protected AbstractFtpClientFactory defaultClientFactory() throws Exception {
return ClientFactorySupport.ftpClientFactory( this.host , Integer.parseInt(this.port) , this.remoteDirectory , this.username ,this.password, this.clientMode );
}
protected String defaultFtpInboundFolderName = "ftpInbound";
@Override
protected FtpInboundRemoteFileSystemSynchronizingMessageSource createInstance()
throws Exception {
boolean autoCreatDirs = Boolean.parseBoolean(this.autoCreateDirectories);
boolean ackRemoteDir = Boolean.parseBoolean(this.autoDeleteRemoteFilesOnSync);
FtpInboundRemoteFileSystemSynchronizingMessageSource ftpRemoteFileSystemSynchronizingMessageSource = new FtpInboundRemoteFileSystemSynchronizingMessageSource();
ftpRemoteFileSystemSynchronizingMessageSource.setAutoCreateDirectories(autoCreatDirs);
if (!StringUtils.hasText(this.localWorkingDirectory)) {
File tmp = new File(SystemUtils.getJavaIoTmpDir(), defaultFtpInboundFolderName);
this.localWorkingDirectory = "file://" + tmp.getAbsolutePath();
}
this.localDirectoryResource = this.fromText(this.localWorkingDirectory);
FtpFileEntryNamer ftpFileEntryNamer = new FtpFileEntryNamer();
CompositeEntryListFilter<FTPFile> compositeFtpFileListFilter = new CompositeEntryListFilter<FTPFile>();
if (StringUtils.hasText(this.filenamePattern)) {
PatternMatchingEntryListFilter<FTPFile> ftpFilePatternMatchingEntryListFilter = new PatternMatchingEntryListFilter<FTPFile>(ftpFileEntryNamer, filenamePattern);
compositeFtpFileListFilter.addFilter(ftpFilePatternMatchingEntryListFilter);
}
if (this.filter != null) {
compositeFtpFileListFilter.addFilter(this.filter);
}
QueuedFtpClientPool queuedFtpClientPool = new QueuedFtpClientPool(15, defaultClientFactory());
FtpInboundRemoteFileSystemSynchronizer ftpRemoteFileSystemSynchronizer = new FtpInboundRemoteFileSystemSynchronizer();
ftpRemoteFileSystemSynchronizer.setClientPool(queuedFtpClientPool);
ftpRemoteFileSystemSynchronizer.setLocalDirectory(this.localDirectoryResource);
ftpRemoteFileSystemSynchronizer.setShouldDeleteSourceFile(ackRemoteDir);
ftpRemoteFileSystemSynchronizer.setFilter(compositeFtpFileListFilter);
ftpRemoteFileSystemSynchronizingMessageSource.setRemotePredicate(compositeFtpFileListFilter);
ftpRemoteFileSystemSynchronizingMessageSource.setSynchronizer(ftpRemoteFileSystemSynchronizer);
ftpRemoteFileSystemSynchronizingMessageSource.setClientPool(queuedFtpClientPool);
ftpRemoteFileSystemSynchronizingMessageSource.setLocalDirectory(this.localDirectoryResource);
ftpRemoteFileSystemSynchronizingMessageSource.setBeanFactory(this.getBeanFactory());
ftpRemoteFileSystemSynchronizingMessageSource.setAutoStartup(true);
ftpRemoteFileSystemSynchronizingMessageSource.afterPropertiesSet();
ftpRemoteFileSystemSynchronizingMessageSource.start();
return ftpRemoteFileSystemSynchronizingMessageSource;
}
@SuppressWarnings("unused")
public void setPort(String port) {
this.port = port;
}
@SuppressWarnings("unused")
public void setAutoCreateDirectories(String autoCreateDirectories) {
this.autoCreateDirectories = autoCreateDirectories;
}
@SuppressWarnings("unused")
public void setFilenamePattern(String filenamePattern) {
this.filenamePattern = filenamePattern;
}
@SuppressWarnings("unused")
public void setUsername(String username) {
this.username = username;
}
@SuppressWarnings("unused")
public void setPassword(String password) {
this.password = password;
}
@SuppressWarnings("unused")
public void setHost(String host) {
this.host = host;
}
@SuppressWarnings("unused")
public void setRemoteDirectory(String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
@SuppressWarnings("unused")
public void setLocalWorkingDirectory(String localWorkingDirectory) {
this.localWorkingDirectory = localWorkingDirectory;
}
@SuppressWarnings("unused")
public void setFilter(EntryListFilter<FTPFile> filter) {
this.filter = filter;
}
@SuppressWarnings("unused")
public void setClientMode(int clientMode) {
this.clientMode = clientMode;
}
@SuppressWarnings("unused")
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}

View File

@@ -0,0 +1,116 @@
package org.springframework.integration.ftp.impl;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.integration.file.entries.CompositeEntryListFilter;
import org.springframework.integration.file.entries.EntryListFilter;
import org.springframework.integration.file.entries.PatternMatchingEntryListFilter;
import org.springframework.integration.ftp.*;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
/**
* Factory to make building the namespace easier
*
* @author Josh Long
*/
public class FtpsRemoteFileSystemSynchronizingMessageSourceFactoryBean extends FtpRemoteFileSystemSynchronizingMessageSourceFactoryBean {
/**
* Sets whether the connection is implicit. Local testing reveals this to be a good choice.
*/
protected volatile Boolean implicit = Boolean.FALSE;
/**
* "TLS" or "SSL"
*/
protected volatile String protocol;
/**
* "P"
*/
protected volatile String prot;
private KeyManager keyManager;
private TrustManager trustManager;
protected volatile String authValue;
private Boolean sessionCreation;
private Boolean useClientMode;
private Boolean needClientAuth;
private Boolean wantsClientAuth;
private String[] cipherSuites;
public FtpsRemoteFileSystemSynchronizingMessageSourceFactoryBean() {
this.defaultFtpInboundFolderName = "ftpsInbound";
this.clientMode = FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE;
}
public void setKeyManager(KeyManager keyManager) {
this.keyManager = keyManager;
}
public void setTrustManager(TrustManager trustManager) {
this.trustManager = trustManager;
}
public void setImplicit(Boolean implicit) {
this.implicit = implicit;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void setProt(String prot) {
this.prot = prot;
}
public void setAuthValue(String authValue) {
this.authValue = authValue;
}
public void setSessionCreation(Boolean sessionCreation) {
this.sessionCreation = sessionCreation;
}
public void setUseClientMode(Boolean useClientMode) {
this.useClientMode = useClientMode;
}
public void setNeedClientAuth(Boolean needClientAuth) {
this.needClientAuth = needClientAuth;
}
public void setWantsClientAuth(Boolean wantsClientAuth) {
this.wantsClientAuth = wantsClientAuth;
}
protected AbstractFtpClientFactory defaultClientFactory()
throws Exception {
DefaultFtpsClientFactory factory = ClientFactorySupport.ftpsClientFactory(this.host, Integer.parseInt(this.port), this.remoteDirectory, this.username, this.password, this.fileType,
this.clientMode, this.prot, this.protocol, this.authValue, this.implicit, this.trustManager, this.keyManager, this.sessionCreation, this.useClientMode, this.wantsClientAuth,
this.needClientAuth, this.cipherSuites);
return factory;
}
public void setCipherSuites(String[] cipherSuites) {
this.cipherSuites = cipherSuites;
}
}

View File

@@ -0,0 +1,3 @@
http\://www.springframework.org/schema/integration/ftp=org.springframework.integration.ftp.config.FtpNamespaceHandler
http\://www.springframework.org/schema/integration/ftps=org.springframework.integration.ftp.config.FtpsNamespaceHandler

View File

@@ -0,0 +1,4 @@
http\://www.springframework.org/schema/integration/ftp/spring-integration-ftp-2.0.xsd=org/springframework/integration/ftp/config/spring-integration-ftp-2.0.xsd
http\://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd=org/springframework/integration/ftp/config/spring-integration-ftp-2.0.xsd
http\://www.springframework.org/schema/integration/ftp/spring-integration-ftps-2.0.xsd=org/springframework/integration/ftp/config/spring-integration-ftps-2.0.xsd
http\://www.springframework.org/schema/integration/ftp/spring-integration-ftps.xsd=org/springframework/integration/ftp/config/spring-integration-ftps-2.0.xsd

View File

@@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors
~
~ 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.
-->
<xsd:schema xmlns="http://www.springframework.org/schema/integration/ftp"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/integration/ftp"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an outbound-channel-adapter that writes files to a remote FTP endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute use="optional" name="client-mode" default="active-local-data-connection-mode">
<xsd:annotation>
<xsd:documentation><![CDATA[
the FTP Client-Mode.
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* should connect to the client's data port to initiate a data transfer.
* This is the default data connection mode when and FTPClient instance
* is created.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to should connect to the other server's
* data port to initiate a data transfer.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 1
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* is in passive mode, requiring the client to connect to the
* server's data port to initiate a transfer.
***/
PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to is in passive mode, requiring the other
* server to connect to the first server's data port to initiate a data
* transfer.
***/
PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="active-local-data-connection-mode"/>
<xsd:enumeration value="active-remote-data-connection-mode"/>
<xsd:enumeration value="passive-local-data-connection-mode"/>
<xsd:enumeration value="passive-remote-data-connection-mode"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute use="optional" name="file-type" default="binary-file-type">
<xsd:annotation>
<xsd:documentation><![CDATA[
Binary, ASCII, or EBDIC. Binary's a good default
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="ebcdic-file-type"/>
<xsd:enumeration value="ascii-file-type"/>
<xsd:enumeration value="binary-file-type"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an inbound-channel-adapter that synchronizes a local directory with the contents of a remote FTP endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute use="optional" name="file-type" default="binary-file-type">
<xsd:annotation>
<xsd:documentation><![CDATA[
Binary, ASCII, or EBDIC. Binary's a good default
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="ebcdic-file-type"/>
<xsd:enumeration value="ascii-file-type"/>
<xsd:enumeration value="binary-file-type"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.entries.EntryListFilter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filename-pattern" type="xsd:string"/>
<xsd:attribute name="local-working-directory" type="xsd:string"/>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
<xsd:attribute name="auto-delete-remote-files-on-sync" type="xsd:boolean"/>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute use="optional" name="client-mode" default="active-local-data-connection-mode">
<xsd:annotation>
<xsd:documentation><![CDATA[
the FTP Client-Mode.
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* should connect to the client's data port to initiate a data transfer.
* This is the default data connection mode when and FTPClient instance
* is created.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to should connect to the other server's
* data port to initiate a data transfer.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 1
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* is in passive mode, requiring the client to connect to the
* server's data port to initiate a transfer.
***/
PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to is in passive mode, requiring the other
* server to connect to the first server's data port to initiate a data
* transfer.
***/
PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="active-local-data-connection-mode"/>
<xsd:enumeration value="active-remote-data-connection-mode"/>
<xsd:enumeration value="passive-local-data-connection-mode"/>
<xsd:enumeration value="passive-remote-data-connection-mode"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,252 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2010 the original author or authors
~
~ 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.
-->
<xsd:schema xmlns="http://www.springframework.org/schema/integration/ftps"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/integration/ftps"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an outbound-channel-adapter that writes files to a remote FTPS endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute use="optional" name="client-mode" default="active-local-data-connection-mode">
<xsd:annotation>
<xsd:documentation><![CDATA[
the FTP Client-Mode.
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* should connect to the client's data port to initiate a data transfer.
* This is the default data connection mode when and FTPClient instance
* is created.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to should connect to the other server's
* data port to initiate a data transfer.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 1
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* is in passive mode, requiring the client to connect to the
* server's data port to initiate a transfer.
***/
PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to is in passive mode, requiring the other
* server to connect to the first server's data port to initiate a data
* transfer.
***/
PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="active-local-data-connection-mode"/>
<xsd:enumeration value="active-remote-data-connection-mode"/>
<xsd:enumeration value="passive-local-data-connection-mode"/>
<xsd:enumeration value="passive-remote-data-connection-mode"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute use="optional" name="file-type" default="binary-file-type">
<xsd:annotation>
<xsd:documentation><![CDATA[
Binary, ASCII, or EBDIC. Binary's a good default
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="ebcdic-file-type"/>
<xsd:enumeration value="ascii-file-type"/>
<xsd:enumeration value="binary-file-type"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an inbound-channel-adapter that synchronizes a local directory with the contents of a remote FTP endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute use="optional" name="file-type" default="binary-file-type">
<xsd:annotation>
<xsd:documentation><![CDATA[
Binary, ASCII, or EBDIC. Binary's a good default
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="ebcdic-file-type"/>
<xsd:enumeration value="ascii-file-type"/>
<xsd:enumeration value="binary-file-type"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.entries.EntryListFilter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filename-pattern" type="xsd:string"/>
<xsd:attribute name="local-working-directory" type="xsd:string"/>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
<xsd:attribute name="auto-delete-remote-files-on-sync" type="xsd:boolean"/>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="host" type="xsd:string" use="required"/>
<xsd:attribute name="password" type="xsd:string"/>
<xsd:attribute name="port" type="xsd:int" default="22"/>
<xsd:attribute use="optional" name="client-mode" default="passive-local-data-connection-mode">
<xsd:annotation>
<xsd:documentation><![CDATA[
the FTP Client-Mode.
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* should connect to the client's data port to initiate a data transfer.
* This is the default data connection mode when and FTPClient instance
* is created.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to should connect to the other server's
* data port to initiate a data transfer.
***/
ACTIVE_LOCAL_DATA_CONNECTION_MODE = 1
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between the client (local) and server and that the server
* is in passive mode, requiring the client to connect to the
* server's data port to initiate a transfer.
***/
PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2
/***
* A constant indicating the FTP session is expecting all transfers
* to occur between two remote servers and that the server
* the client is connected to is in passive mode, requiring the other
* server to connect to the first server's data port to initiate a data
* transfer.
***/
PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="active-local-data-connection-mode"/>
<xsd:enumeration value="active-remote-data-connection-mode"/>
<xsd:enumeration value="passive-local-data-connection-mode"/>
<xsd:enumeration value="passive-remote-data-connection-mode"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,9 @@
package org.springframework.integration.ftp;
/**
* the goal here is to sketch out what a simple FTPS client looks like
*/
public class FtpsExample {
}

View File

@@ -0,0 +1,34 @@
package org.springframework.integration.ftp;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.ServiceActivator;
import java.io.File;
/**
* Simple component to test the inbound integration
*
* @author Josh Long
*/
public class InboundFtpFileServiceActivator {
@ServiceActivator
public void onNewRemoteFTPFile(Message<File> file)
throws Throwable {
System.out.println(StringUtils.repeat("=", 100));
System.out.println("A new file has appeared: " + file.getPayload().getAbsolutePath());
for (String h : file.getHeaders().keySet())
System.out.println(String.format("%s = %s", h, file.getHeaders().get(h)));
}
public static void main(String[] args) throws Throwable {
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("inbound-ftp-context.xml");
classPathXmlApplicationContext.start();
}
}

View File

@@ -0,0 +1,34 @@
package org.springframework.integration.ftp;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.ServiceActivator;
import java.io.File;
/**
* Simple component to test the inbound integration
*
* @author Josh Long
*/
public class InboundFtpsFileServiceActivator {
@ServiceActivator
public void onNewRemoteFTPFile(Message<File> file)
throws Throwable {
System.out.println(StringUtils.repeat("=", 100));
System.out.println("A new file has appeared: " + file.getPayload().getAbsolutePath());
for (String h : file.getHeaders().keySet())
System.out.println(String.format("%s = %s", h, file.getHeaders().get(h)));
}
public static void main(String[] args) throws Throwable {
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("inbound-ftps-context.xml");
classPathXmlApplicationContext.start();
}
}

View File

@@ -0,0 +1,16 @@
package org.springframework.integration.ftp;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* This simple example demonstrates sending a file to a remote FTP server using the ftp:outbound-channel-adapter
* <p/>
* It reads files from a directory on your computer and systematically puts them on the remote FTP server,
*
* @author Josh Long
*/
public class OutboundFtpExample {
public static void main(String[] args) throws Throwable {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("outbound-ftp-context.xml");
}
}

View File

@@ -0,0 +1,16 @@
package org.springframework.integration.ftp;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* This simple example demonstrates sending a file to a remote FTP server using the ftp:outbound-channel-adapter
* <p/>
* It reads files from a directory on your computer and systematically puts them on the remote FTP server,
*
* @author Josh Long
*/
public class OutboundFtpsExample {
public static void main(String[] args) throws Throwable {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("outbound-ftps-context.xml");
}
}

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ftp="http://www.springframework.org/schema/integration/ftp"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ftp http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder
location="file://${user.home}/Desktop/ftp.properties"
ignore-unresolvable="true"/>
<ftp:inbound-channel-adapter remote-directory="${ftp.remotedir}" channel="ftpIn" auto-create-directories="true"
host="${ftp.host}" auto-delete-remote-files-on-sync="false"
username="${ftp.username}" password="${ftp.password}" port="21"
file-type="binary-file-type"
filename-pattern=".*?jpg"
>
<int:poller>
<int:interval-trigger interval="1000" time-unit="MILLISECONDS"/>
</int:poller>
</ftp:inbound-channel-adapter>
<int:channel id="ftpIn"/>
<bean id="inboundFTPFileServiceActivator"
class="org.springframework.integration.ftp.InboundFtpFileServiceActivator"/>
<int:service-activator input-channel="ftpIn" ref="inboundFTPFileServiceActivator"/>
</beans>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ftps="http://www.springframework.org/schema/integration/ftps"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ftps http://www.springframework.org/schema/integration/ftp/spring-integration-ftps.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder
location="file://${user.home}/Desktop/ftp.properties"
ignore-unresolvable="true"/>
<ftps:inbound-channel-adapter remote-directory="${ftp.remotedir}"
channel="ftpIn"
auto-create-directories="true"
host="${ftp.host}"
auto-delete-remote-files-on-sync="false"
username="${ftp.username}"
password="${ftp.password}"
port="21"
file-type="binary-file-type"
filename-pattern=".*?java"
client-mode="passive-local-data-connection-mode"
>
<int:poller>
<int:interval-trigger interval="1000" time-unit="MILLISECONDS"/>
</int:poller>
</ftps:inbound-channel-adapter>
<int:channel id="ftpIn"/>
<bean id="inboundFtpsFileServiceActivator"
class="org.springframework.integration.ftp.InboundFtpsFileServiceActivator"/>
<int:service-activator input-channel="ftpIn" ref="inboundFtpsFileServiceActivator"/>
</beans>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ftp="http://www.springframework.org/schema/integration/ftp"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:file="http://www.springframework.org/schema/integration/file"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ftp http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file-1.0.xsd">
<context:property-placeholder
location="file://${user.home}/Desktop/ftp.properties"
ignore-unresolvable="true"/>
<file:inbound-channel-adapter channel="ftpOutbound"
filename-pattern=".*?jpg"
directory="#{systemProperties['user.home']}/Desktop/imagesToSendViaFTP"
auto-create-directory="true">
<int:poller>
<int:interval-trigger interval="1000" time-unit="MILLISECONDS"/>
</int:poller>
</file:inbound-channel-adapter>
<int:channel id="ftpOutbound"/>
<ftp:outbound-channel-adapter
remote-directory="${ftp.remotedir}"
channel="ftpOutbound"
host="${ftp.host}"
username="${ftp.username}"
password="${ftp.password}" port="2222"
client-mode="passive-local-data-connection-mode"
/>
</beans>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ftp="http://www.springframework.org/schema/integration/ftp"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:file="http://www.springframework.org/schema/integration/file" xmlns:ftps="http://www.springframework.org/schema/integration/ftps"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ftps http://www.springframework.org/schema/integration/ftp/spring-integration-ftps.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file-1.0.xsd">
<context:property-placeholder
location="file://${user.home}/Desktop/ftp.properties"
ignore-unresolvable="true"/>
<file:inbound-channel-adapter channel="ftpOutbound"
filename-pattern=".*?jpg"
directory="#{systemProperties['user.home']}/Desktop/imagesToSendViaFTP"
auto-create-directory="true">
<int:poller>
<int:interval-trigger interval="1000" time-unit="MILLISECONDS"/>
</int:poller>
</file:inbound-channel-adapter>
<int:channel id="ftpOutbound"/>
<ftps:outbound-channel-adapter
remote-directory="${ftp.remotedir}"
channel="ftpOutbound"
host="${ftp.host}"
username="${ftp.username}"
password="${ftp.password}" port="21"
client-mode="passive-local-data-connection-mode"
/>
</beans>