INT-1562 removed the sftp remote directory header, but added support for an expression on the outbound adapter

This commit is contained in:
Mark Fisher
2010-11-10 17:07:35 -05:00
parent e14bbbe21d
commit fbaeead0a7
5 changed files with 57 additions and 86 deletions

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2002-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.sftp;
/**
* @author Josh Long
* @since 2.0
*/
public abstract class SftpHeaders {
public static final String REMOTE_DIRECTORY = "sftp_remoteDirectory";
}

View File

@@ -17,6 +17,8 @@
package org.springframework.integration.sftp.config;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.expression.Expression;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.sftp.outbound.SftpSendingMessageHandler;
import org.springframework.integration.sftp.session.QueuedSftpSessionPool;
import org.springframework.integration.sftp.session.SftpSessionFactory;
@@ -37,7 +39,7 @@ public class SftpMessageSendingConsumerFactoryBean implements FactoryBean<SftpSe
private String password;
private String remoteDirectory;
private Expression remoteDirectoryExpression;
private String username;
@@ -45,6 +47,7 @@ public class SftpMessageSendingConsumerFactoryBean implements FactoryBean<SftpSe
private String charset;
public void setCharset(String charset) {
this.charset = charset;
}
@@ -61,6 +64,10 @@ public class SftpMessageSendingConsumerFactoryBean implements FactoryBean<SftpSe
this.keyFilePassword = keyFilePassword;
}
public void setUsername(final String username) {
this.username = username;
}
public void setPassword(final String password) {
this.password = password;
}
@@ -69,24 +76,25 @@ public class SftpMessageSendingConsumerFactoryBean implements FactoryBean<SftpSe
this.port = port;
}
public void setRemoteDirectory(final String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
public void setRemoteDirectory(String remoteDirectory) {
remoteDirectory = (remoteDirectory != null) ? remoteDirectory : "";
this.remoteDirectoryExpression = new LiteralExpression(remoteDirectory);
}
public void setUsername(final String username) {
this.username = username;
public void setRemoteDirectoryExpression(Expression remoteDirectoryExpression) {
this.remoteDirectoryExpression = remoteDirectoryExpression;
}
public SftpSendingMessageHandler getObject() throws Exception {
SftpSessionFactory sessionFactory = SftpSessionUtils.buildSftpSessionFactory(
this.host, this.password, this.username, this.keyFile, this.keyFilePassword, this.port);
QueuedSftpSessionPool queuedSFTPSessionPool = new QueuedSftpSessionPool(15, sessionFactory);
queuedSFTPSessionPool.afterPropertiesSet();
SftpSendingMessageHandler sftpSendingMessageHandler = new SftpSendingMessageHandler(queuedSFTPSessionPool);
sftpSendingMessageHandler.setRemoteDirectory(this.remoteDirectory);
sftpSendingMessageHandler.setCharset(this.charset);
sftpSendingMessageHandler.afterPropertiesSet();
return sftpSendingMessageHandler;
QueuedSftpSessionPool sessionPool = new QueuedSftpSessionPool(15, sessionFactory);
sessionPool.afterPropertiesSet();
SftpSendingMessageHandler messageHandler = new SftpSendingMessageHandler(sessionPool);
messageHandler.setRemoteDirectoryExpression(this.remoteDirectoryExpression);
messageHandler.setCharset(this.charset);
messageHandler.afterPropertiesSet();
return messageHandler;
}
public Class<? extends SftpSendingMessageHandler> getObjectType() {

View File

@@ -26,12 +26,15 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.util.StringUtils;
/**
* Provides namespace support for using SFTP.
* This is largely based on the FTP support by Iwein Fuld.
*
* @author Josh Long
* @author Mark Fisher
* @since 2.0
*/
public class SftpNamespaceHandler extends AbstractIntegrationNamespaceHandler {
@@ -49,9 +52,27 @@ public class SftpNamespaceHandler extends AbstractIntegrationNamespaceHandler {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SftpMessageSendingConsumerFactoryBean.class.getName());
for (String p : "auto-create-directories,username,password,host,port,key-file,key-file-password,remote-directory,charset".split(",")) {
for (String p : "auto-create-directories,username,password,host,port,key-file,key-file-password,charset".split(",")) {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, p);
}
String remoteDirectory = element.getAttribute("remote-directory");
String remoteDirectoryExpression = element.getAttribute("remote-directory-expression");
boolean hasLiteralRemoteDirectory = StringUtils.hasText(remoteDirectory);
boolean hasRemoteDirectoryExpression = StringUtils.hasText(remoteDirectoryExpression);
if (hasLiteralRemoteDirectory ^ hasRemoteDirectoryExpression) {
if (hasLiteralRemoteDirectory) {
builder.addPropertyValue("remoteDirectory", remoteDirectory);
}
else {
BeanDefinitionBuilder expressionDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.config.ExpressionFactoryBean");
expressionDefBuilder.addConstructorArgValue(remoteDirectoryExpression);
builder.addPropertyValue("remoteDirectoryExpression", expressionDefBuilder.getBeanDefinition());
}
}
else {
parserContext.getReaderContext().error("exactly one of 'remote-directory' or 'remote-directory-expression' is required", element);
}
return builder.getBeanDefinition();
}
}

View File

@@ -31,16 +31,16 @@ import org.apache.commons.lang.SystemUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.expression.Expression;
import org.springframework.integration.Message;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.sftp.SftpHeaders;
import org.springframework.integration.sftp.session.SftpSession;
import org.springframework.integration.sftp.session.SftpSessionPool;
import org.springframework.integration.util.AbstractExpressionEvaluator;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
@@ -53,14 +53,14 @@ import com.jcraft.jsch.ChannelSftp;
* @author Josh Long
* @since 2.0
*/
public class SftpSendingMessageHandler implements MessageHandler, InitializingBean {
public class SftpSendingMessageHandler extends AbstractExpressionEvaluator implements MessageHandler, InitializingBean {
private static final String TEMPORARY_FILE_SUFFIX = ".writing";
private volatile SftpSessionPool pool;
private volatile String remoteDirectory;
private volatile Expression remoteDirectoryExpression;
private volatile FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator();
@@ -68,8 +68,6 @@ public class SftpSendingMessageHandler implements MessageHandler, InitializingBe
private volatile Resource temporaryBufferFolder = new FileSystemResource(SystemUtils.getJavaIoTmpDir());
private volatile boolean initialized;
private volatile String charset = Charset.defaultCharset().name();
@@ -86,12 +84,8 @@ public class SftpSendingMessageHandler implements MessageHandler, InitializingBe
this.fileNameGenerator = fileNameGenerator;
}
public void setRemoteDirectory(final String remoteDirectory) {
this.remoteDirectory = remoteDirectory;
}
public String getRemoteDirectory() {
return this.remoteDirectory;
public void setRemoteDirectoryExpression(Expression remoteDirectoryExpression) {
this.remoteDirectoryExpression = remoteDirectoryExpression;
}
public void setCharset(String charset) {
@@ -101,12 +95,6 @@ public class SftpSendingMessageHandler implements MessageHandler, InitializingBe
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.pool, "the pool must not be null");
this.temporaryBufferFolderFile = this.temporaryBufferFolder.getFile();
if (!this.initialized) {
if (StringUtils.isEmpty(this.remoteDirectory)) {
this.remoteDirectory = null;
}
this.initialized = true;
}
}
private File handleFileMessage(File sourceFile, File tempFile, File resultFile) throws IOException {
@@ -182,16 +170,11 @@ public class SftpSendingMessageHandler implements MessageHandler, InitializingBe
InputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
String baseOfRemotePath = StringUtils.isEmpty(this.remoteDirectory) ? StringUtils.EMPTY : remoteDirectory; // the safe default
String dynRd = null;
MessageHeaders messageHeaders = null;
if (message != null) {
messageHeaders = message.getHeaders();
if ((messageHeaders != null) && messageHeaders.containsKey(SftpHeaders.REMOTE_DIRECTORY)) {
dynRd = (String) messageHeaders.get(SftpHeaders.REMOTE_DIRECTORY);
if (!StringUtils.isEmpty(dynRd)) {
baseOfRemotePath = dynRd;
}
String baseOfRemotePath = "";
if (this.remoteDirectoryExpression != null) {
String result = this.evaluateExpression(this.remoteDirectoryExpression, message, String.class);
if (result != null) {
baseOfRemotePath = result;
}
}
if (!StringUtils.defaultString(baseOfRemotePath).endsWith("/")) {

View File

@@ -33,9 +33,7 @@
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an outbound-channel-adapter that writes files to a remote SFTP endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
@@ -49,16 +47,14 @@
</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="remote-directory" type="xsd:string"/>
<xsd:attribute name="remote-directory-expression" type="xsd:string"/>
<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 name="key-file" type="xsd:string"/>
<xsd:attribute name="key-file-password" type="xsd:string"/>
<xsd:attribute name="charset" type="xsd:string"/>
<xsd:attribute name="auto-create-directories" type="xsd:boolean"/>
</xsd:complexType>
@@ -67,14 +63,13 @@
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an inbound-channel-adapter that synchronizes with a remote SFTP endpoint.
You may configure a <code>poller</code> element to determine at what frequency to scan the remote directory.
There is support for automatically deleting remote files upon synchornization. This adapter supports two connectivity options:
<ol>
<li> Password authentication: using this opton, authentication is done using a username and a password.</li>
<li> Key-based authentication: using this option, you may specify a key that will be used to authenticate. If they key itself is encrypted and requires a password, you may specify that, as well.</li>
<li> Key-based authentication: using this option, you may specify a key that will be used to authenticate.
If they key itself is encrypted and requires a password, you may specify that, as well.</li>
</ol>
]]></xsd:documentation>
</xsd:annotation>
@@ -92,7 +87,6 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
@@ -102,26 +96,18 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filename-pattern" type="xsd:string"/>
<xsd:attribute name="username" type="xsd:string" use="required"/>
<xsd:attribute name="remote-directory" type="xsd:string" use="required"/>
<xsd:attribute name="local-directory-path" type="xsd:string"/>
<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 name="key-file" type="xsd:string"/>
<xsd:attribute name="key-file-password" 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:complexType>
</xsd:element>
</xsd:schema>