GH-212: Smb with custom transport configuration
Fixes https://github.com/spring-projects/spring-integration-extensions/issues/212 * Updated to be able to use min/max SMB version property settings * cleanup of formatting of file * Updated based on review comments * Updated readme for new functionality * Some polishing of readme and follow current naming conventions * Updated, missed naming convention on Javadoc * Updated per review comments * Enhancement - exposing the jcifs.CIFSContext interface * fixed check style build errors * Added JUnit test
This commit is contained in:
committed by
Artem Bilan
parent
d4f42cb6b8
commit
672a196da7
@@ -29,6 +29,7 @@ Put the following block into pom.xml if using Maven:
|
||||
|
||||
##### Version 1.2
|
||||
* 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`
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -84,3 +85,21 @@ public SmbSessionFactory smbSessionFactory() {
|
||||
return smbSession;
|
||||
}
|
||||
````
|
||||
|
||||
### Intializing SmbSessionFactory with a custom implementation of the jcifs.CIFSContext interface
|
||||
|
||||
NOTE: Setting of the SMB protocol min/max versions must be done in your implementation of jcifs.CIFSContext
|
||||
|
||||
````java
|
||||
@Bean
|
||||
public SmbSessionFactory smbSessionFactory(new myCIFSContext()) {
|
||||
SmbSessionFactory smbSession = new SmbSessionFactory();
|
||||
smbSession.setHost("myHost");
|
||||
smbSession.setPort(445);
|
||||
smbSession.setDomain("myDomain");
|
||||
smbSession.setUsername("myUser");
|
||||
smbSession.setPassword("myPassword");
|
||||
smbSession.setShareAndDir("myShareAndDir");
|
||||
return smbSession;
|
||||
}
|
||||
````
|
||||
|
||||
@@ -23,7 +23,9 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import jcifs.CIFSContext;
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
/**
|
||||
@@ -36,10 +38,23 @@ public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFi
|
||||
|
||||
private static Log logger = LogFactory.getLog(SmbSessionFactory.class);
|
||||
|
||||
private CIFSContext context = null;
|
||||
|
||||
public SmbSessionFactory() {
|
||||
logger.debug("New " + getClass().getName() + " created.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SMB session factory with a custom client context configuration.
|
||||
* @param _context that holds the client configuration, shared services as well as the active credentials
|
||||
* @since 1.2
|
||||
*/
|
||||
public SmbSessionFactory(CIFSContext _context) {
|
||||
Assert.notNull(_context, "_context can't be null");
|
||||
this.context = _context;
|
||||
logger.debug("New " + getClass().getName() + " created with CIFSContext.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SmbSession getSession() {
|
||||
try {
|
||||
@@ -51,13 +66,20 @@ public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFi
|
||||
}
|
||||
|
||||
protected SmbSession createSession() throws IOException {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("jcifs.smb.client.minVersion", this.getSmbMinVersion().name());
|
||||
props.setProperty("jcifs.smb.client.maxVersion", this.getSmbMaxVersion().name());
|
||||
SmbShare smbShare;
|
||||
if (this.context != null) {
|
||||
smbShare = new SmbShare(this, this.context);
|
||||
}
|
||||
else {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("jcifs.smb.client.minVersion", this.getSmbMinVersion().name());
|
||||
props.setProperty("jcifs.smb.client.maxVersion", this.getSmbMaxVersion().name());
|
||||
|
||||
SmbShare smbShare = new SmbShare(this, props);
|
||||
smbShare.setReplaceFile(isReplaceFile());
|
||||
smbShare.setUseTempFile(isUseTempFile());
|
||||
smbShare = new SmbShare(this, props);
|
||||
}
|
||||
|
||||
smbShare.setReplaceFile(this.isReplaceFile());
|
||||
smbShare.setUseTempFile(this.isUseTempFile());
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("SMB share init: %s/%s", getHostPort(), getShareAndDir()));
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.core.NestedIOException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jcifs.CIFSContext;
|
||||
import jcifs.config.PropertyConfiguration;
|
||||
import jcifs.context.BaseContext;
|
||||
import jcifs.context.SingletonContext;
|
||||
@@ -71,6 +72,17 @@ public class SmbShare extends SmbFile {
|
||||
_smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the jCIFS library with a custom client context configuration.
|
||||
* @param _smbConfig the SMB share configuration
|
||||
* @param _context that holds the client configuration, shared services as well as the active credentials
|
||||
* @throws IOException if an invalid SMB URL was constructed by jCIFS
|
||||
* @since 1.2
|
||||
*/
|
||||
public SmbShare(SmbConfig _smbConfig, CIFSContext _context) throws IOException {
|
||||
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()), _context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the jCIFS library with custom properties such as
|
||||
* 'jcifs.smb.client.minVersion' and 'jcifs.smb.client.maxVersion'
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.session;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
|
||||
import org.springframework.integration.smb.AbstractBaseTests;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
import jcifs.CIFSContext;
|
||||
import jcifs.context.SingletonContext;
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
/**
|
||||
* @author Gregory Bragg
|
||||
*/
|
||||
public class SmbSessionFactoryWithCIFSContextTests extends AbstractBaseTests {
|
||||
|
||||
private SmbSession smbSession;
|
||||
|
||||
private SmbSessionFactory smbSessionFactory;
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception {
|
||||
smbSession = mock(SmbSession.class);
|
||||
|
||||
smbSessionFactory = new TestSmbSessionFactory(SingletonContext.getInstance());
|
||||
assertNotNull("TestSmbSessionFactory object is null.", smbSessionFactory);
|
||||
|
||||
smbSessionFactory.setHost("localhost");
|
||||
smbSessionFactory.setPort(445);
|
||||
smbSessionFactory.setDomain("");
|
||||
smbSessionFactory.setUsername("sambaguest");
|
||||
smbSessionFactory.setPassword("sambaguest");
|
||||
smbSessionFactory.setShareAndDir("smb-share/");
|
||||
smbSessionFactory.setReplaceFile(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleFileContentMessage() {
|
||||
File file = createNewFile("remote-target-dir/handlerContent.test");
|
||||
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(smbSessionFactory);
|
||||
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
|
||||
handler.setFileNameGenerator(message -> "handlerContent.test");
|
||||
handler.setAutoCreateDirectory(true);
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
handler.handleMessage(new GenericMessage<String>("hello"));
|
||||
assertFileExists(file);
|
||||
}
|
||||
|
||||
class TestSmbSessionFactory extends SmbSessionFactory {
|
||||
private CIFSContext context = null;
|
||||
|
||||
protected TestSmbSessionFactory(CIFSContext _context) {
|
||||
assertNotNull("CIFSContext object is null.", _context);
|
||||
this.context = _context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SmbSession createSession() {
|
||||
try {
|
||||
// test for a constructor with a CIFSContext
|
||||
SmbShare smbShare = new SmbShare(this, this.context);
|
||||
assertNotNull("SmbShare object is null.", smbShare);
|
||||
assertThat(smbShare.toString()).isEqualTo("smb://sambaguest:sambaguest@localhost:445/smb-share/");
|
||||
|
||||
// the rest has been copied from SmbSendingMessageHandlerTests
|
||||
when(smbSession.remove(Mockito.anyString())).thenReturn(true);
|
||||
when(smbSession.list(Mockito.anyString())).thenReturn(new SmbFile[0]);
|
||||
|
||||
doAnswer(new Answer<Object>() {
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock _invocation) throws Throwable {
|
||||
String path = (String) _invocation.getArguments()[0];
|
||||
OutputStream os = (OutputStream) _invocation.getArguments()[1];
|
||||
writeToFile((this.getClass().getSimpleName() + " : TEST : " + path).getBytes(), os);
|
||||
return null;
|
||||
}
|
||||
}).when(smbSession).read(Mockito.anyString(), Mockito.any(OutputStream.class));
|
||||
|
||||
doAnswer(_invocation -> {
|
||||
InputStream inputStream = (InputStream) _invocation.getArguments()[0];
|
||||
String path = (String) _invocation.getArguments()[1];
|
||||
writeToFile(inputStream, path);
|
||||
return null;
|
||||
}).when(smbSession)
|
||||
.write(Mockito.any(InputStream.class), Mockito.anyString());
|
||||
|
||||
// when(smbSession.write(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(null);
|
||||
// when(smbSession.write(Mockito.any(File.class), Mockito.anyString())).thenReturn(null);
|
||||
|
||||
doAnswer(new Answer<Object>() {
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock _invocation) {
|
||||
String path = (String) _invocation.getArguments()[0];
|
||||
new File(path).mkdirs();
|
||||
return null;
|
||||
}
|
||||
}).when(smbSession).mkdir(Mockito.anyString());
|
||||
|
||||
doAnswer(_invocation -> {
|
||||
String pathFrom = (String) _invocation.getArguments()[0];
|
||||
String pathTo = (String) _invocation.getArguments()[1];
|
||||
new File(pathFrom).renameTo(new File(pathTo));
|
||||
return null;
|
||||
}).when(smbSession)
|
||||
.rename(Mockito.anyString(), Mockito.anyString());
|
||||
|
||||
doNothing().when(smbSession).close();
|
||||
when(smbSession.isOpen()).thenReturn(true);
|
||||
return smbSession;
|
||||
}
|
||||
catch (Exception _ex) {
|
||||
throw new RuntimeException("Failed to create mock session.", _ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user