GH-206: jCIFS to the latest version for SMB2/3
Fixes https://github.com/spring-projects/spring-integration-extensions/issues/206 Updated test to better reflect reality, getCanonicalPath() -> getPath() Updated readme doc with more information, guidance Updated to address deprecated constructor in jCIFS library * Polishing code, versions, checkstyle, Copyrights year * Add `@author` to affected classes
This commit is contained in:
committed by
Artem Bilan
parent
2b0f44ebbb
commit
376a34c031
@@ -1,4 +1,4 @@
|
||||
Spring Integration Smb Support
|
||||
Spring Integration SMB Support
|
||||
==============================
|
||||
|
||||
## Introduction
|
||||
@@ -7,3 +7,54 @@ This module add Spring Integration support for [Server Message Block][] (SMB).
|
||||
|
||||
[Server Message Block]: https://en.wikipedia.org/wiki/Server_Message_Block
|
||||
|
||||
## Version
|
||||
|
||||
[Versions in Maven Repository](http://central.maven.org/maven2/org/springframework/integration/spring-integration-smb/)
|
||||
|
||||
## Using Maven
|
||||
|
||||
Put the following block into pom.xml if using Maven:
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-smb</artifactId>
|
||||
<version>1.0.0.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
## Changes
|
||||
|
||||
* Updated to use the latest version of the [JCIFS](https://github.com/codelibs/jcifs) library
|
||||
* SMB2 (2.02 protocol level) support, some SMB3 support
|
||||
|
||||
## Overview
|
||||
|
||||
The Java CIFS Client Library has been chosen as a Java implementation for the CIFS/SMB networking protocol.
|
||||
Its `SmbFile` abstraction is simply wrapped to the Spring Integration "Remote File" foundations like `SmbSession`, `SmbRemoteFileTemplate`, etc.
|
||||
|
||||
The SMB Channel Adapters and support classes implementations are fully similar to existing components for (S)FTP or AWS S3 protocols.
|
||||
So, if you familiar with those components, it is pretty straightforward to use this extension. But any way here are several words about existing components:
|
||||
|
||||
### SMB Inbound Channel Adapter
|
||||
|
||||
To download SMB files locally the `SmbInboundFileSynchronizingMessageSource` is provided.
|
||||
It is simple extension of the `AbstractInboundFileSynchronizingMessageSource` which requires `SmbInboundFileSynchronizer` injection.
|
||||
For filtering remote files you still can use any existing `FileListFilter` implementations, but particular `SmbRegexPatternFileListFilter` and `SmbSimplePatternFileListFilter` are provided.
|
||||
For XML configuration the `<int-smb:inbound-channel-adapter>` component is provided.
|
||||
|
||||
### 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`.
|
||||
In case of Java configuration that `FileTransferringMessageHandler` should be supplied with the `SmbSessionFactory` (or `SmbRemoteFileTemplate`).
|
||||
|
||||
@ServiceActivator(inputChannel = "storeToSmb")
|
||||
@Bean
|
||||
public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) {
|
||||
FileTransferringMessageHandler<SmbFile> handler =
|
||||
new FileTransferringMessageHandler<>(smbSessionFactory);
|
||||
handler.setRemoteDirectoryExpression(
|
||||
new LiteralExpression("remote-target-dir"));
|
||||
handler.setFileNameGenerator(m ->
|
||||
m.getHeaders().get(FileHeaders.FILENAME, String.class) + ".test");
|
||||
handler.setAutoCreateDirectory(true);
|
||||
return handler;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ plugins {
|
||||
id 'idea'
|
||||
id 'jacoco'
|
||||
id 'checkstyle'
|
||||
id 'org.sonarqube' version '2.6.2'
|
||||
id 'org.sonarqube' version '2.7'
|
||||
}
|
||||
|
||||
description = 'Spring Integration SMB Support'
|
||||
@@ -56,9 +56,9 @@ compileTestJava {
|
||||
ext {
|
||||
idPrefix = 'smb'
|
||||
|
||||
jcifsVersion = '1.3.18.3'
|
||||
log4jVersion = '2.11.0'
|
||||
springIntegrationVersion = '5.0.13.BUILD-SNAPSHOT'
|
||||
jcifsVersion = '2.1.7'
|
||||
log4jVersion = '2.11.2'
|
||||
springIntegrationVersion = '5.0.13.RELEASE'
|
||||
|
||||
|
||||
linkHomepage = 'https://github.com/SpringSource/spring-integration-extensions'
|
||||
@@ -81,12 +81,12 @@ sourceSets {
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.7.8"
|
||||
toolVersion = "0.8.2"
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
configFile = file("$rootDir/src/checkstyle/checkstyle.xml")
|
||||
toolVersion = "8.9"
|
||||
toolVersion = "8.19"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1 +1 @@
|
||||
version=1.0.1.BUILD-SNAPSHOT
|
||||
version=1.1.0.BUILD-SNAPSHOT
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
||||
"https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
|
||||
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
|
||||
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||
<suppressions>
|
||||
<suppress files="package-info\.java" checks=".*" />
|
||||
<suppress files="[\\/]test[\\/]" checks="RequireThis" />
|
||||
<suppress files="[\\/]test[\\/]" checks="FinalClass" />
|
||||
<suppress files="[\\/]test[\\/]" checks="AvoidStaticImport" />
|
||||
<suppress files="[\\/]test[\\/]" checks="InnerTypeLast" />
|
||||
<suppress files="CachingSessionFactory" checks="FinalClass" /> <!-- Tests spy -->
|
||||
<suppress files="[\\/]test[\\/]" checks="Javadoc*" />
|
||||
</suppressions>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "https://www.puppycrawl.com/dtds/configuration_1_2.dtd">
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* 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.
|
||||
@@ -53,6 +53,7 @@ import jcifs.smb.SmbFileOutputStream;
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
* @author Prafull Kumar Soni
|
||||
* @author Gregory Bragg
|
||||
*
|
||||
*/
|
||||
public class SmbSession implements Session<SmbFile> {
|
||||
@@ -63,10 +64,6 @@ public class SmbSession implements Session<SmbFile> {
|
||||
|
||||
private static final String SMB_FILE_SEPARATOR = "/";
|
||||
|
||||
static {
|
||||
configureJcifs();
|
||||
}
|
||||
|
||||
private final SmbShare smbShare;
|
||||
|
||||
/**
|
||||
@@ -458,7 +455,7 @@ public class SmbSession implements Session<SmbFile> {
|
||||
return this.smbShare;
|
||||
}
|
||||
|
||||
SmbFile smbFile = new SmbFile(this.smbShare, cleanedPath, SmbFile.FILE_SHARE_READ);
|
||||
SmbFile smbFile = new SmbFile(this.smbShare, cleanedPath);
|
||||
|
||||
boolean appendFileSeparator = !cleanedPath.endsWith(SMB_FILE_SEPARATOR);
|
||||
if (appendFileSeparator) {
|
||||
@@ -498,32 +495,6 @@ public class SmbSession implements Session<SmbFile> {
|
||||
return createSmbFileObject(_path, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static configuration of the JCIFS library.
|
||||
* The log level of this class is mapped to a suitable <code>jcifs.util.loglevel</code>
|
||||
*/
|
||||
static void configureJcifs() {
|
||||
// TODO jcifs.Config.setProperty("jcifs.smb.client.useExtendedSecurity", "false");
|
||||
// TODO jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", "false");
|
||||
|
||||
// set JCIFS SMB client library' log level unless already configured by system property
|
||||
final String sysPropLogLevel = "jcifs.util.loglevel";
|
||||
|
||||
if (jcifs.Config.getProperty(sysPropLogLevel) == null) {
|
||||
// set log level according to this class' logger's log level.
|
||||
Log log = LogFactory.getLog(SmbSession.class);
|
||||
if (log.isTraceEnabled()) {
|
||||
jcifs.Config.setProperty(sysPropLogLevel, "N");
|
||||
}
|
||||
else if (log.isDebugEnabled()) {
|
||||
jcifs.Config.setProperty(sysPropLogLevel, "3");
|
||||
}
|
||||
else {
|
||||
jcifs.Config.setProperty(sysPropLogLevel, "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] listNames(String path) {
|
||||
throw new UnsupportedOperationException("Not implemented yet");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* 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.
|
||||
@@ -26,12 +26,14 @@ import org.springframework.core.NestedIOException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jcifs.context.SingletonContext;
|
||||
import jcifs.smb.NtlmPasswordAuthenticator;
|
||||
import jcifs.smb.SmbException;
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
/**
|
||||
* @author Markus Spann
|
||||
* @since 1.0
|
||||
* @author Gregory Bragg
|
||||
*/
|
||||
public class SmbShare extends SmbFile {
|
||||
|
||||
@@ -43,12 +45,20 @@ public class SmbShare extends SmbFile {
|
||||
|
||||
private final AtomicBoolean useTempFile = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* @deprecated as of release 1.1.0, use {@link #SmbShare(SmbConfig)} instead.
|
||||
* @param url do not use
|
||||
* @throws IOException do not use
|
||||
*/
|
||||
@Deprecated
|
||||
public SmbShare(String url) throws IOException {
|
||||
super(StringUtils.cleanPath(url));
|
||||
}
|
||||
|
||||
public SmbShare(SmbConfig _smbConfig) throws IOException {
|
||||
this(_smbConfig.validate().getUrl());
|
||||
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
|
||||
SingletonContext.getInstance().withCredentials(new NtlmPasswordAuthenticator(
|
||||
_smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword())));
|
||||
}
|
||||
|
||||
public void init() throws NestedIOException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* 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.
|
||||
@@ -27,81 +27,111 @@ import jcifs.smb.SmbFile;
|
||||
/**
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Gregory Bragg
|
||||
*
|
||||
*/
|
||||
public class SmbSessionTests {
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectWithBackSlash1() throws IOException {
|
||||
|
||||
System.setProperty("file.separator", "\\");
|
||||
SmbShare smbShare = new SmbShare("smb://myshare/shared/");
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared/");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba\\");
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath());
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectWithBackSlash2() throws IOException {
|
||||
|
||||
System.setProperty("file.separator", "\\");
|
||||
SmbShare smbShare = new SmbShare("smb://myshare\\shared\\");
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared\\");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba\\");
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath());
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectWithBackSlash3() throws IOException {
|
||||
|
||||
System.setProperty("file.separator", "\\");
|
||||
SmbShare smbShare = new SmbShare("smb://myshare\\shared\\");
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared\\");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject("..\\another");
|
||||
assertEquals("smb://myshare/another/", smbFile.getCanonicalPath());
|
||||
assertEquals("smb://myshare:445/another", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectWithBackSlash4() throws IOException {
|
||||
|
||||
System.setProperty("file.separator", "/");
|
||||
SmbShare smbShare = new SmbShare("smb://myshare/shared/");
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared/");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba\\");
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath());
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectwithMissingTrailingSlash1() throws IOException {
|
||||
|
||||
SmbShare smbShare = new SmbShare("smb://myshare/shared");
|
||||
public void testCreateSmbFileObjectWithMissingTrailingSlash1() throws IOException {
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
|
||||
assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath());
|
||||
|
||||
assertEquals("smb://myshare/blubba", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectwithMissingTrailingSlash2() throws IOException {
|
||||
|
||||
SmbShare smbShare = new SmbShare("smb://myshare/shared/");
|
||||
public void testCreateSmbFileObjectWithMissingTrailingSlash2() throws IOException {
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared/");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject(".");
|
||||
assertEquals("smb://myshare/shared/", smbFile.getCanonicalPath());
|
||||
|
||||
assertEquals("smb://myshare:445/shared/", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSmbFileObjectwithMissingTrailingSlash3() throws IOException {
|
||||
|
||||
SmbShare smbShare = new SmbShare("smb://myshare/shared/");
|
||||
public void testCreateSmbFileObjectWithMissingTrailingSlash3() throws IOException {
|
||||
SmbConfig config = new SmbConfig();
|
||||
config.setHost("myshare");
|
||||
config.setPort(445);
|
||||
config.setShareAndDir("shared/");
|
||||
SmbShare smbShare = new SmbShare(config);
|
||||
SmbSession smbSession = new SmbSession(smbShare);
|
||||
|
||||
SmbFile smbFile = smbSession.createSmbFileObject("../anotherShare");
|
||||
assertEquals("smb://myshare/anotherShare/", smbFile.getCanonicalPath());
|
||||
|
||||
assertEquals("smb://myshare:445/anotherShare", smbFile.getPath());
|
||||
smbSession.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user