INT-1782 added support for configuring temporary suffix

This commit is contained in:
Oleg Zhurakousky
2011-03-07 15:33:58 -05:00
parent 7c83bb17c6
commit 2d6e490969
27 changed files with 108 additions and 24 deletions

View File

@@ -53,11 +53,11 @@ import java.nio.charset.Charset;
* @author Mark Fisher
* @author Iwein Fuld
* @author Alex Peters
* @author Oleg Zhurakousky
*/
public class FileWritingMessageHandler extends AbstractReplyProducingMessageHandler {
public static final String TEMPORARY_FILE_SUFFIX =".writing";
public volatile String temporaryFileSuffix =".writing";
private final Log logger = LogFactory.getLog(this.getClass());
@@ -89,6 +89,14 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
this.autoCreateDirectory = autoCreateDirectory;
}
public void setTemporaryFileSuffix(String temporaryFileSuffix) {
this.temporaryFileSuffix = temporaryFileSuffix;
}
public String getTemporaryFileSuffix() {
return temporaryFileSuffix;
}
/**
* Provide the {@link FileNameGenerator} strategy to use when generating
* the destination file's name.
@@ -139,7 +147,7 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
Assert.notNull(payload, "message payload must not be null");
String generatedFileName = this.fileNameGenerator.generateFileName(requestMessage);
File originalFileFromHeader = this.retrieveOriginalFileFromHeader(requestMessage);
File tempFile = new File(this.destinationDirectory, generatedFileName + TEMPORARY_FILE_SUFFIX);
File tempFile = new File(this.destinationDirectory, generatedFileName + temporaryFileSuffix);
File resultFile = new File(this.destinationDirectory, generatedFileName);
try {
if (payload instanceof File) {

View File

@@ -48,6 +48,7 @@ public abstract class AbstractRemoteFileInboundChannelAdapterParser extends Abst
IntegrationNamespaceUtils.setValueIfAttributeDefined(synchronizerBuilder, element, "remote-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(synchronizerBuilder, element, "delete-remote-files");
IntegrationNamespaceUtils.setValueIfAttributeDefined(synchronizerBuilder, element, "remote-file-separator");
IntegrationNamespaceUtils.setValueIfAttributeDefined(synchronizerBuilder, element, "temporary-file-suffix");
this.configureFilter(synchronizerBuilder, element, parserContext);
// build the MessageSource

View File

@@ -50,6 +50,7 @@ abstract class FileWritingMessageHandlerBeanDefinitionBuilder {
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "delete-source-files");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "temporary-file-suffix");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
String fileNameGenerator = element.getAttribute("filename-generator");
if (StringUtils.hasText(fileNameGenerator)) {

View File

@@ -57,6 +57,8 @@ public class FileWritingMessageHandlerFactoryBean implements FactoryBean<FileWri
private volatile Long sendTimeout;
private volatile Integer order;
private volatile String temporaryFileSuffix;
private final Object initializationMonitor = new Object();
@@ -68,6 +70,10 @@ public class FileWritingMessageHandlerFactoryBean implements FactoryBean<FileWri
public void setDirectory(File directory) {
this.directory = directory;
}
public void setTemporaryFileSuffix(String temporaryFileSuffix) {
this.temporaryFileSuffix = temporaryFileSuffix;
}
public void setOutputChannel(MessageChannel outputChannel) {
this.outputChannel = outputChannel;
@@ -153,6 +159,7 @@ public class FileWritingMessageHandlerFactoryBean implements FactoryBean<FileWri
if (this.order != null) {
this.handler.setOrder(this.order);
}
this.handler.setTemporaryFileSuffix(this.temporaryFileSuffix);
this.handler.setBeanFactory(this.beanFactory);
this.handler.afterPropertiesSet();
}

View File

@@ -46,6 +46,7 @@ public class RemoteFileOutboundChannelAdapterParser extends AbstractOutboundChan
BeanDefinitionBuilder handlerBuilder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.file.remote.handler.FileTransferringMessageHandler");
handlerBuilder.addConstructorArgValue(sessionFactoryBuilder.getBeanDefinition());
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "temporary-file-suffix");
// configure remote directory expression
String remoteDirectory = element.getAttribute("remote-directory");

View File

@@ -26,7 +26,6 @@ import org.springframework.integration.Message;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.handler.AbstractMessageHandler;
@@ -45,6 +44,8 @@ import org.springframework.util.StringUtils;
* @since 2.0
*/
public class FileTransferringMessageHandler extends AbstractMessageHandler {
public volatile String temporaryFileSuffix =".writing";
private final SessionFactory sessionFactory;
@@ -73,6 +74,10 @@ public class FileTransferringMessageHandler extends AbstractMessageHandler {
public void setRemoteDirectoryExpression(Expression remoteDirectoryExpression) {
this.directoryExpressionProcessor = new ExpressionEvaluatingMessageProcessor<String>(remoteDirectoryExpression, String.class);
}
public String getTemporaryFileSuffix() {
return temporaryFileSuffix;
}
public void setTemporaryDirectory(File temporaryDirectory) {
Assert.notNull(temporaryDirectory, "temporaryDirectory must not be null");
@@ -86,10 +91,15 @@ public class FileTransferringMessageHandler extends AbstractMessageHandler {
public void setCharset(String charset) {
this.charset = charset;
}
public void setTemporaryFileSuffix(String temporaryFileSuffix) {
this.temporaryFileSuffix = temporaryFileSuffix;
}
protected void onInit() throws Exception {
Assert.notNull(this.directoryExpressionProcessor, "remoteDirectoryExpression is required");
}
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
@@ -174,7 +184,7 @@ public class FileTransferringMessageHandler extends AbstractMessageHandler {
}
String remoteFilePath = remoteDirectory + fileName;
// write remote file first with .writing extension
String tempFilePath = remoteFilePath + FileWritingMessageHandler.TEMPORARY_FILE_SUFFIX;
String tempFilePath = remoteFilePath + this.temporaryFileSuffix;
session.write(fileInputStream, tempFilePath);
fileInputStream.close();
// then rename it to its final name

View File

@@ -53,8 +53,7 @@ public abstract class AbstractInboundFileSynchronizer<F> implements InboundFileS
/**
* Extension used when downloading files. We change it right after we know it's downloaded.
*/
static final String INCOMPLETE_EXTENSION = ".writing";
public volatile String temporaryFileSuffix =".writing";
protected final Log logger = LogFactory.getLog(this.getClass());
@@ -93,6 +92,10 @@ public abstract class AbstractInboundFileSynchronizer<F> implements InboundFileS
Assert.hasText(remoteFileSeparator, "'remoteFileSeparator' must not be empty");
this.remoteFileSeparator = remoteFileSeparator;
}
public void setTemporaryFileSuffix(String temporaryFileSuffix) {
this.temporaryFileSuffix = temporaryFileSuffix;
}
/**
* Specify the full path to the remote directory.
@@ -116,6 +119,10 @@ public abstract class AbstractInboundFileSynchronizer<F> implements InboundFileS
protected final List<F> filterFiles(F[] files) {
return (this.filter != null) ? this.filter.filterFiles(files) : Arrays.asList(files);
}
public String getTemporaryFileSuffix() {
return temporaryFileSuffix;
}
public void synchronizeToLocalDirectory(File localDirectory) {
Session session = null;
@@ -160,7 +167,7 @@ public abstract class AbstractInboundFileSynchronizer<F> implements InboundFileS
}
File localFile = new File(localDirectory, remoteFileName);
if (!localFile.exists()) {
String tempFileName = localFile.getAbsolutePath() + INCOMPLETE_EXTENSION;
String tempFileName = localFile.getAbsolutePath() + this.temporaryFileSuffix;
File tempFile = new File(tempFileName);
InputStream inputStream = null;
FileOutputStream fileOutputStream = new FileOutputStream(tempFile);

View File

@@ -137,7 +137,7 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F> extends M
@SuppressWarnings("unchecked")
private FileListFilter<File> buildFilter() {
Pattern completePattern = Pattern.compile("^.*(?<!" + AbstractInboundFileSynchronizer.INCOMPLETE_EXTENSION + ")$");
Pattern completePattern = Pattern.compile("^.*(?<!" + this.synchronizer.getTemporaryFileSuffix() + ")$");
return new CompositeFileListFilter<File>(Arrays.asList(
new AcceptOnceFileListFilter<File>(),
new RegexPatternFileListFilter(completePattern)));

View File

@@ -198,6 +198,13 @@ Only files matching this regular expression will be picked up by this adapter.
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="temporary-file-suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Extension used when uploading files. We change it right after we know it's uploaded.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="delete-source-files" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[

View File

@@ -17,7 +17,8 @@
<file:outbound-channel-adapter id="simpleAdapter"
channel="testChannel"
directory="${java.io.tmpdir}"/>
directory="${java.io.tmpdir}"
temporary-file-suffix=".foo"/>
<file:outbound-channel-adapter id="adapterWithCustomNameGenerator"
channel="testChannel"

View File

@@ -64,6 +64,7 @@ public class FileOutboundChannelAdapterParserTests {
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
File expected = new File(System.getProperty("java.io.tmpdir"));
File actual = (File) handlerAccessor.getPropertyValue("destinationDirectory");
assertEquals(".foo", handler.getTemporaryFileSuffix());
assertThat(actual, is(expected));
assertThat(handlerAccessor.getPropertyValue("fileNameGenerator"), is(DefaultFileNameGenerator.class));
assertEquals(Boolean.FALSE, handlerAccessor.getPropertyValue("deleteSourceFiles"));

View File

@@ -44,6 +44,13 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="temporary-file-suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Extension used when uploading files. We change it right after we know it's uploaded.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-filename-generator" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
@@ -111,6 +118,13 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="temporary-file-suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Extension used when downloading files. We change it right after we know it's downloaded.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-directory" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>

View File

@@ -19,6 +19,7 @@
filename-pattern="*.txt"
local-directory="."
remote-file-separator="."
temporary-file-suffix=".foo"
remote-directory="foo/bar">
<int:poller fixed-rate="1000"/>
</int-ftp:inbound-channel-adapter>

View File

@@ -55,6 +55,7 @@ public class FtpInboundChannelAdapterParserTests {
FtpInboundFileSynchronizer fisync =
(FtpInboundFileSynchronizer) TestUtils.getPropertyValue(inbound, "synchronizer");
assertEquals(".foo", fisync.getTemporaryFileSuffix());
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals(".", remoteFileSeparator);

View File

@@ -21,6 +21,7 @@
delete-remote-files="false"
filename-regex=".*\.gz$"
remote-directory="/home/ozhurakousky/Downloads"
temporary-file-suffix=".foo"
local-directory="file:local-test-dir">
<int:poller fixed-rate="5000"/>
</int-ftp:inbound-channel-adapter>

View File

@@ -22,6 +22,7 @@
remote-directory="foo/bar"
charset="UTF-8"
remote-file-separator="."
temporary-file-suffix=".foo"
remote-filename-generator="fileNameGenerator"/>
<int:channel id="ftpChannel"/>

View File

@@ -47,6 +47,7 @@ public class FtpOutboundChannelAdapterParserTests {
FileTransferringMessageHandler handler = (FileTransferringMessageHandler) TestUtils.getPropertyValue(consumer, "handler");
String remoteFileSeparator = (String) TestUtils.getPropertyValue(handler, "remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals(".foo", handler.getTemporaryFileSuffix());
assertEquals(".", remoteFileSeparator);
assertEquals(ac.getBean("fileNameGenerator"), TestUtils.getPropertyValue(handler, "fileNameGenerator"));
assertEquals("UTF-8", TestUtils.getPropertyValue(handler, "charset"));

View File

@@ -24,6 +24,7 @@
delete-remote-files="true"
local-directory="."
remote-directory="foo/bar"
temporary-file-suffix=".foo"
filter="entryListFilter">
<int:poller fixed-rate="1000"/>
</int-ftp:inbound-channel-adapter>

View File

@@ -70,6 +70,13 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="temporary-file-suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Extension used when uploading files. We change it right after we know it's uploaded.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-filename-generator" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
@@ -132,6 +139,13 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="temporary-file-suffix" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Extension used when downloading files. We change it right after we know it's downloaded.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="channel" use="required" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>

View File

@@ -43,6 +43,7 @@
local-directory="file:local-test-dir"
auto-create-local-directory="false"
remote-file-separator="."
temporary-file-suffix=".bar"
delete-remote-files="false">
<poller fixed-rate="1000"/>
</sftp:inbound-channel-adapter>

View File

@@ -59,8 +59,10 @@ public class InboundChannelAdapterParserTests {
SftpInboundFileSynchronizingMessageSource source =
(SftpInboundFileSynchronizingMessageSource) TestUtils.getPropertyValue(adapter, "source");
assertNotNull(source);
SftpInboundFileSynchronizer synchronizer = (SftpInboundFileSynchronizer) TestUtils.getPropertyValue(source, "synchronizer");
String remoteFileSeparator = (String) TestUtils.getPropertyValue(synchronizer, "remoteFileSeparator");
assertEquals(".bar", synchronizer.getTemporaryFileSuffix());
assertNotNull(remoteFileSeparator);
assertEquals(".", remoteFileSeparator);
PollableChannel requestChannel = context.getBean("requestChannel", PollableChannel.class);

View File

@@ -26,6 +26,7 @@
charset="UTF-8"
remote-filename-generator="fileNameGenerator"
remote-file-separator="."
temporary-file-suffix=".bar"
remote-directory="foo/bar"/>
<int-sftp:outbound-channel-adapter id="sftpOutboundAdapterWithExpression"

View File

@@ -53,6 +53,7 @@ public class OutboundChannelAdapterParserTests {
String remoteFileSeparator = (String) TestUtils.getPropertyValue(handler, "remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals(".", remoteFileSeparator);
assertEquals(".bar", handler.getTemporaryFileSuffix());
Expression remoteDirectoryExpression = (Expression) TestUtils.getPropertyValue(handler, "directoryExpressionProcessor.expression");
assertNotNull(remoteDirectoryExpression);
assertTrue(remoteDirectoryExpression instanceof LiteralExpression);

View File

@@ -35,7 +35,7 @@ public class SftpInboundOutboundSanitySample {
@Test
//@Ignore
@Ignore
public void testInbound() throws Exception{
File fileA = new File("local-test-dir/a.test");
if (fileA.exists()){
@@ -56,11 +56,11 @@ public class SftpInboundOutboundSanitySample {
new ClassPathXmlApplicationContext("SftpInboundReceiveSample-ignored.xml", this.getClass());
System.in.read();
//Thread.sleep(30000);
// fileA = new File("local-test-dir/a.test");
// fileB = new File("local-test-dir/b.test");
// assertTrue(fileA.exists());
// assertTrue(fileB.exists());
Thread.sleep(5000);
fileA = new File("local-test-dir/a.test");
fileB = new File("local-test-dir/b.test");
assertTrue(fileA.exists());
assertTrue(fileB.exists());
}
@Test

View File

@@ -11,7 +11,7 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="192.168.28.146"/>
<property name="host" value="localhost"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftp_rsa"/>
<property name="privateKeyPassphrase" value="springintegration"/>
<property name="port" value="22"/>
@@ -22,10 +22,11 @@
channel="receiveChannel"
session-factory="sftpSessionFactory"
local-directory="file:local-test-dir"
remote-directory="/home/ozhurakousky/foo/bar"
remote-directory="/Users/ozhurakousky/workspace-sts-2.3.3.M2/si/spring-integration/spring-integration-sftp/remote-test-dir"
auto-startup="true"
temporary-file-suffix=".foo"
delete-remote-files="false"
filename-regex=".*\.txt$">
filename-regex=".*\.test$">
<int:poller fixed-rate="3000" max-messages-per-poll="1" />
</int-sftp:inbound-channel-adapter>

View File

@@ -9,7 +9,7 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="192.168.1.155"/>
<property name="host" value="localhost"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftp_rsa"/>
<property name="privateKeyPassphrase" value="springintegration"/>
<property name="port" value="22"/>
@@ -22,7 +22,8 @@
session-factory="sftpSessionFactory"
channel="ftpChannel"
charset="UTF-8"
temporary-file-suffix=".foo"
remote-filename-generator-expression="payload.getName() + '-foo'"
remote-directory="/home/ozhurakousky"/>
remote-directory="/Users/ozhurakousky/workspace-sts-2.3.3.M2/si/spring-integration/spring-integration-sftp/remote-target-dir"/>
</beans>

View File

@@ -32,7 +32,6 @@ import org.mockito.stubbing.Answer;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.integration.file.remote.session.SessionFactory;
@@ -114,7 +113,7 @@ public class SftpSendingMessageHandlerTests {
public Object answer(InvocationOnMock invocation)
throws Throwable {
File file = new File((String)invocation.getArguments()[1]);
assertTrue(file.getName().endsWith(FileWritingMessageHandler.TEMPORARY_FILE_SUFFIX));
assertTrue(file.getName().endsWith(".writing"));
FileCopyUtils.copy((InputStream)invocation.getArguments()[0], new FileOutputStream(file));
return null;
}
@@ -125,7 +124,7 @@ public class SftpSendingMessageHandlerTests {
public Object answer(InvocationOnMock invocation)
throws Throwable {
File file = new File((String) invocation.getArguments()[0]);
assertTrue(file.getName().endsWith(FileWritingMessageHandler.TEMPORARY_FILE_SUFFIX));
assertTrue(file.getName().endsWith(".writing"));
File renameToFile = new File((String) invocation.getArguments()[1]);
file.renameTo(renameToFile);
return null;