GH-246 Deprecate SmbCfg.replaceFile & useTempFile

Fixes https://github.com/spring-projects/spring-integration-extensions/issues/246

The `replaceFile` & `useTempFile` options are not `SmbSession` responsibility.
The `FileTransferringMessageHandler` covers a functionality of `replace` and `tmFile`.

* Implement an `SmbMessageHandler` to hide a `replaceFile` setting on the `SmbSessionFactory`
to retain backward compatibility
* Mention an `SmbMessageHandler` in the README

Updates after further unit testing
Updated for initial PR review requested changes
removed comment to satisfy PR review
Updated to satisfy PR review requests for changes
More updates after further PR review
Updated again based on PR review comments
* Suppress deprecations in the tests for these deprecated options
* Add `package-info.java` to `outbound`
* Delegate from one ctor to another in the `SmbMessageHandler`
This commit is contained in:
Gregory Bragg
2022-04-29 16:07:02 -04:00
committed by Artem Bilan
parent 3bd896caed
commit 9ef8e04ead
14 changed files with 112 additions and 32 deletions

View File

@@ -13,12 +13,11 @@ This module adds Spring Integration support for [Server Message Block][] (SMB).
## Using Maven ## Using Maven
Put the following block into pom.xml if using Maven: Put the following block into pom.xml if using Maven, set the `<version>` tag to the desired release:
<dependency> <dependency>
<groupId>org.springframework.integration</groupId> <groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-smb</artifactId> <artifactId>spring-integration-smb</artifactId>
<version>1.2.0.RELEASE</version>
</dependency> </dependency>
## Changes ## Changes
@@ -30,6 +29,11 @@ Put the following block into pom.xml if using Maven:
##### Version 1.2 ##### Version 1.2
* Ability to set the SMB min/max versions in the `SmbSessionFactory` via configuration in the JCIFS library * Ability to set the SMB min/max versions in the `SmbSessionFactory` via configuration in the JCIFS library
* Ability to use a custom implementation of the `jcifs.CIFSContext` interface in the `SmbSessionFactory` * Ability to use a custom implementation of the `jcifs.CIFSContext` interface in the `SmbSessionFactory`
##### Version 1.2.2
* Updated to use the latest version of the [JCIFS](https://github.com/codelibs/jcifs) library
* Added implementation for `SmbMessageHandler`
* Deprecated legacy `replaceFile` and `useTempFile` flags in `SmbConfig`
## Overview ## Overview
@@ -48,15 +52,14 @@ For XML configuration the `<int-smb:inbound-channel-adapter>` component is provi
### SMB Outbound Channel Adapter ### SMB Outbound Channel Adapter
There is no (yet) some SMB specific requirements for files transferring to SMB, so for XML `<int-smb:outbound-channel-adapter>` component we simply reuse an existing `FileTransferringMessageHandler`. For writing files to a SMB share, and for XML `<int-smb:outbound-channel-adapter>` component we use the `SmbMessageHandler`.
In case of Java configuration that `FileTransferringMessageHandler` should be supplied with the `SmbSessionFactory` (or `SmbRemoteFileTemplate`). In case of Java configuration a `SmbMessageHandler` should be supplied with the `SmbSessionFactory` (or `SmbRemoteFileTemplate`).
````java ````java
@ServiceActivator(inputChannel = "storeToSmb")
@Bean @Bean
@ServiceActivator(inputChannel = "storeToSmbShare")
public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) { public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) {
FileTransferringMessageHandler<SmbFile> handler = SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
new FileTransferringMessageHandler<>(smbSessionFactory);
handler.setRemoteDirectoryExpression( handler.setRemoteDirectoryExpression(
new LiteralExpression("remote-target-dir")); new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(m -> handler.setFileNameGenerator(m ->

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2022 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
*
* https://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.smb.outbound;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.integration.smb.session.SmbRemoteFileTemplate;
import org.springframework.integration.smb.session.SmbSessionFactory;
import jcifs.smb.SmbFile;
/**
* The SMB specific {@link FileTransferringMessageHandler} extension. Based on the
* {@link SmbRemoteFileTemplate}.
*
* @author Gregory Bragg
* @author Artem Bilan
*
* @since 1.2.2
*
* @see SmbRemoteFileTemplate
*/
public class SmbMessageHandler extends FileTransferringMessageHandler<SmbFile> {
public SmbMessageHandler(SessionFactory<SmbFile> sessionFactory) {
this(sessionFactory, FileExistsMode.REPLACE);
}
@SuppressWarnings("deprecation")
public SmbMessageHandler(SessionFactory<SmbFile> sessionFactory, FileExistsMode mode) {
super(new SmbRemoteFileTemplate(sessionFactory), mode);
if (sessionFactory instanceof SmbSessionFactory && FileExistsMode.REPLACE.equals(mode)) {
SmbSessionFactory smbSessionFactory = (SmbSessionFactory) sessionFactory;
smbSessionFactory.setReplaceFile(true);
}
}
}

View File

@@ -0,0 +1,4 @@
/**
* Outbound Channel Adapter implementations for SMB protocol.
*/
package org.springframework.integration.smb.outbound;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -131,18 +131,42 @@ public class SmbConfig {
return this.shareAndDir; return this.shareAndDir;
} }
/**
* The replace file option.
* @param _replaceFile true/false
* @deprecated as of 1.2.2 in favor of SmbMessageHandler
*/
@Deprecated
public void setReplaceFile(boolean _replaceFile) { public void setReplaceFile(boolean _replaceFile) {
this.replaceFile = _replaceFile; this.replaceFile = _replaceFile;
} }
/**
* The replace file option.
* @return true/false
* @deprecated as of 1.2.2 in favor of SmbMessageHandler
*/
@Deprecated
public boolean isReplaceFile() { public boolean isReplaceFile() {
return this.replaceFile; return this.replaceFile;
} }
/**
* The tmp file option.
* @param _useTempFile true/false
* @deprecated as of 1.2.2 in favor of SmbMessageHandler
*/
@Deprecated
void setUseTempFile(boolean _useTempFile) { void setUseTempFile(boolean _useTempFile) {
this.useTempFile = _useTempFile; this.useTempFile = _useTempFile;
} }
/**
* The tmp file option.
* @return true/false
* @deprecated as of 1.2.2 in favor of SmbMessageHandler
*/
@Deprecated
public boolean isUseTempFile() { public boolean isUseTempFile() {
return this.useTempFile; return this.useTempFile;
} }

View File

@@ -22,7 +22,7 @@ import org.springframework.integration.file.remote.session.SessionFactory;
import jcifs.smb.SmbFile; import jcifs.smb.SmbFile;
/** /**
* The SMP-specific {@link RemoteFileTemplate} implementation. * The SMB-specific {@link RemoteFileTemplate} implementation.
* *
* @author Artem Bilan * @author Artem Bilan
*/ */

View File

@@ -33,10 +33,11 @@ import jcifs.smb.SmbFile;
* *
* @author Markus Spann * @author Markus Spann
* @author Gregory Bragg * @author Gregory Bragg
* @author Artem Bilan
*/ */
public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFile> { public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFile> {
private static Log logger = LogFactory.getLog(SmbSessionFactory.class); private static final Log logger = LogFactory.getLog(SmbSessionFactory.class);
private CIFSContext context = null; private CIFSContext context = null;
@@ -65,6 +66,7 @@ public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFi
} }
} }
@SuppressWarnings("deprecation")
protected SmbSession createSession() throws IOException { protected SmbSession createSession() throws IOException {
SmbShare smbShare; SmbShare smbShare;
if (this.context != null) { if (this.context != null) {
@@ -78,8 +80,8 @@ public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFi
smbShare = new SmbShare(this, props); smbShare = new SmbShare(this, props);
} }
smbShare.setReplaceFile(this.isReplaceFile()); smbShare.setReplaceFile(isReplaceFile());
smbShare.setUseTempFile(this.isUseTempFile()); smbShare.setUseTempFile(isUseTempFile());
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info(String.format("SMB share init: %s/%s", getHostPort(), getShareAndDir())); logger.info(String.format("SMB share init: %s/%s", getHostPort(), getShareAndDir()));

View File

@@ -16,7 +16,6 @@
<property name="username" value="sambagu@est"/> <property name="username" value="sambagu@est"/>
<property name="password" value="sambag%uest"/> <property name="password" value="sambag%uest"/>
<property name="shareAndDir" value="smb-share/"/> <property name="shareAndDir" value="smb-share/"/>
<property name="replaceFile" value="true"/>
</bean> </bean>
<int-smb:inbound-channel-adapter id="smbInboundChannelAdapter" <int-smb:inbound-channel-adapter id="smbInboundChannelAdapter"

View File

@@ -15,8 +15,7 @@
p:domain="sambaguest" p:domain="sambaguest"
p:username="sambaguest" p:username="sambaguest"
p:password="sambaguest" p:password="sambaguest"
p:shareAndDir="smb-share/" p:shareAndDir="smb-share/"/>
p:replaceFile="false"/>
<int-smb:inbound-channel-adapter id="smbInboundChannelAdapter" <int-smb:inbound-channel-adapter id="smbInboundChannelAdapter"
channel="smbInboundChannel" channel="smbInboundChannel"

View File

@@ -66,7 +66,6 @@ public class SmbInboundOutboundSample extends AbstractBaseTests {
// retrieve the session factory bean to place a couple of test files remotely using a new session // retrieve the session factory bean to place a couple of test files remotely using a new session
SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class); SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class);
smbSessionFactory.setReplaceFile(true);
SmbSession smbSession = smbSessionFactory.getSession(); SmbSession smbSession = smbSessionFactory.getSession();
// place text files onto the share // place text files onto the share
@@ -118,7 +117,6 @@ public class SmbInboundOutboundSample extends AbstractBaseTests {
// retrieve the session factory bean to check the test files are present in the remote location // retrieve the session factory bean to check the test files are present in the remote location
SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class); SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class);
smbSessionFactory.setReplaceFile(false);
SmbSession smbSession = smbSessionFactory.getSession(); SmbSession smbSession = smbSessionFactory.getSession();
for (int i = 0; i < fileNames.length; i++) { for (int i = 0; i < fileNames.length; i++) {

View File

@@ -14,7 +14,6 @@
<property name="username" value="sambaguest"/> <property name="username" value="sambaguest"/>
<property name="password" value="sambaguest"/> <property name="password" value="sambaguest"/>
<property name="shareAndDir" value="smb-share/"/> <property name="shareAndDir" value="smb-share/"/>
<property name="replaceFile" value="false"/>
</bean> </bean>
<int-smb:outbound-channel-adapter id="smbOutboundChannelAdapter" <int-smb:outbound-channel-adapter id="smbOutboundChannelAdapter"

View File

@@ -15,8 +15,7 @@
p:domain="sambaguest" p:domain="sambaguest"
p:username="sambaguest" p:username="sambaguest"
p:password="sambaguest" p:password="sambaguest"
p:shareAndDir="smb-share/" p:shareAndDir="smb-share/"/>
p:replaceFile="false"/>
<int:channel id="smbOutboundChannel" /> <int:channel id="smbOutboundChannel" />

View File

@@ -64,7 +64,6 @@ public class SmbInboundRemoteFileSystemSynchronizerTests extends AbstractBaseTes
smbSessionFactory.setUsername("sambaguest"); smbSessionFactory.setUsername("sambaguest");
smbSessionFactory.setPassword("sambaguest"); smbSessionFactory.setPassword("sambaguest");
smbSessionFactory.setShareAndDir("smb-share/"); smbSessionFactory.setShareAndDir("smb-share/");
smbSessionFactory.setReplaceFile(true);
} }
// @Test // @Test

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.expression.common.LiteralExpression; import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.smb.AbstractBaseTests; import org.springframework.integration.smb.AbstractBaseTests;
import org.springframework.integration.smb.session.SmbSession; import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory; import org.springframework.integration.smb.session.SmbSessionFactory;
@@ -45,6 +44,7 @@ import jcifs.smb.SmbFile;
* @author Markus Spann * @author Markus Spann
* @author Artem Bilan * @author Artem Bilan
* @author Prafull Kumar Soni * @author Prafull Kumar Soni
* @author Gregory Bragg
*/ */
public class SmbSendingMessageHandlerTests extends AbstractBaseTests { public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
@@ -62,13 +62,12 @@ public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
smbSessionFactory.setUsername("sambaguest"); smbSessionFactory.setUsername("sambaguest");
smbSessionFactory.setPassword("sambaguest"); smbSessionFactory.setPassword("sambaguest");
smbSessionFactory.setShareAndDir("smb-share/"); smbSessionFactory.setShareAndDir("smb-share/");
smbSessionFactory.setReplaceFile(true);
} }
@Test @Test
public void testHandleFileContentMessage() { public void testHandleFileContentMessage() {
File file = createNewFile("remote-target-dir/handlerContent.test"); File file = createNewFile("remote-target-dir/handlerContent.test");
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(smbSessionFactory); SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir")); handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(message -> "handlerContent.test"); handler.setFileNameGenerator(message -> "handlerContent.test");
handler.setAutoCreateDirectory(true); handler.setAutoCreateDirectory(true);
@@ -81,7 +80,7 @@ public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
@Test @Test
public void testHandleFileAsByte() { public void testHandleFileAsByte() {
File file = createNewFile("remote-target-dir/handlerContent.test"); File file = createNewFile("remote-target-dir/handlerContent.test");
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(smbSessionFactory); SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir")); handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(message -> "handlerContent.test"); handler.setFileNameGenerator(message -> "handlerContent.test");
handler.setBeanFactory(mock(BeanFactory.class)); handler.setBeanFactory(mock(BeanFactory.class));
@@ -93,7 +92,7 @@ public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
// @Test // @Test
// public void testHandleFileMessage() throws Exception { // public void testHandleFileMessage() throws Exception {
// File file = createNewFile("remote-target-dir/template.mf.test"); // File file = createNewFile("remote-target-dir/template.mf.test");
// FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(smbSessionFactory); // SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
// handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir")); // handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
// handler.setFileNameGenerator(new FileNameGenerator() { // handler.setFileNameGenerator(new FileNameGenerator() {
// public String generateFileName(Message<?> message) { // public String generateFileName(Message<?> message) {
@@ -115,6 +114,7 @@ public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
doAnswer(new Answer<Object>() { doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock _invocation) throws Throwable { public Object answer(InvocationOnMock _invocation) throws Throwable {
String path = (String) _invocation.getArguments()[0]; String path = (String) _invocation.getArguments()[0];
OutputStream os = (OutputStream) _invocation.getArguments()[1]; OutputStream os = (OutputStream) _invocation.getArguments()[1];
@@ -136,6 +136,7 @@ public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
doAnswer(new Answer<Object>() { doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock _invocation) { public Object answer(InvocationOnMock _invocation) {
String path = (String) _invocation.getArguments()[0]; String path = (String) _invocation.getArguments()[0];
new File(path).mkdirs(); new File(path).mkdirs();

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ public class SmbSessionFactoryWithCIFSContextTests extends AbstractBaseTests {
private SmbSessionFactory smbSessionFactory; private SmbSessionFactory smbSessionFactory;
@Before @Before
public void prepare() throws Exception { public void prepare() {
smbSession = mock(SmbSession.class); smbSession = mock(SmbSession.class);
smbSessionFactory = new TestSmbSessionFactory(SingletonContext.getInstance()); smbSessionFactory = new TestSmbSessionFactory(SingletonContext.getInstance());
@@ -65,7 +65,6 @@ public class SmbSessionFactoryWithCIFSContextTests extends AbstractBaseTests {
smbSessionFactory.setUsername("sambaguest"); smbSessionFactory.setUsername("sambaguest");
smbSessionFactory.setPassword("sambaguest"); smbSessionFactory.setPassword("sambaguest");
smbSessionFactory.setShareAndDir("smb-share/"); smbSessionFactory.setShareAndDir("smb-share/");
smbSessionFactory.setReplaceFile(true);
} }
@Test @Test
@@ -77,12 +76,12 @@ public class SmbSessionFactoryWithCIFSContextTests extends AbstractBaseTests {
handler.setAutoCreateDirectory(true); handler.setAutoCreateDirectory(true);
handler.setBeanFactory(mock(BeanFactory.class)); handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.handleMessage(new GenericMessage<String>("hello")); handler.handleMessage(new GenericMessage<>("hello"));
assertFileExists(file); assertFileExists(file);
} }
class TestSmbSessionFactory extends SmbSessionFactory { class TestSmbSessionFactory extends SmbSessionFactory {
private CIFSContext context = null; private CIFSContext context;
protected TestSmbSessionFactory(CIFSContext _context) { protected TestSmbSessionFactory(CIFSContext _context) {
assertNotNull("CIFSContext object is null.", _context); assertNotNull("CIFSContext object is null.", _context);