Migrate SMB extension project to respective module

* Removed deprecated replaceFile and useTempFile session configs
* Refactored to use AssertJ instead of JUnit asserts as per PR feedback
* Code clean up for SMB module
This commit is contained in:
Gregory Bragg
2022-05-05 15:47:41 -04:00
committed by Artem Bilan
parent 392455eb34
commit 7ad71d38d9
46 changed files with 3785 additions and 0 deletions

View File

@@ -70,6 +70,7 @@ ext {
h2Version = '2.1.210'
jacksonVersion = '2.13.2'
jaxbVersion = '3.0.2'
jcifsVersion = '2.1.29'
jeroMqVersion = '0.5.2'
jmsApiVersion = '3.0.0'
jpaApiVersion = '3.0.2'
@@ -874,6 +875,16 @@ project('spring-integration-sftp') {
}
}
project('spring-integration-smb') {
description = 'Spring Integration SMB Support'
dependencies {
api project(':spring-integration-file')
api "org.codelibs:jcifs:$jcifsVersion"
testImplementation project(':spring-integration-file').sourceSets.test.output
}
}
project('spring-integration-stomp') {
description = 'Spring Integration STOMP Support'
dependencies {

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2012-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.config;
import org.springframework.integration.file.config.AbstractRemoteFileInboundChannelAdapterParser;
import org.springframework.integration.file.filters.AbstractPersistentAcceptOnceFileListFilter;
import org.springframework.integration.file.filters.FileListFilter;
import org.springframework.integration.file.remote.synchronizer.InboundFileSynchronizer;
import org.springframework.integration.smb.filters.SmbPersistentAcceptOnceFileListFilter;
import org.springframework.integration.smb.filters.SmbRegexPatternFileListFilter;
import org.springframework.integration.smb.filters.SmbSimplePatternFileListFilter;
import org.springframework.integration.smb.inbound.SmbInboundFileSynchronizer;
import org.springframework.integration.smb.inbound.SmbInboundFileSynchronizingMessageSource;
/**
* Parser for the SMB 'inbound-channel-adapter' element.
*
* @author Markus Spann
* @author Artem Bilan
* @author Prafull Kumar Soni
*
* @since 6.0
*/
public class SmbInboundChannelAdapterParser extends AbstractRemoteFileInboundChannelAdapterParser {
@Override
protected String getMessageSourceClassname() {
return SmbInboundFileSynchronizingMessageSource.class.getName();
}
@Override
protected Class<? extends InboundFileSynchronizer> getInboundFileSynchronizerClass() {
return SmbInboundFileSynchronizer.class;
}
@Override
protected Class<? extends FileListFilter<?>> getSimplePatternFileListFilterClass() {
return SmbSimplePatternFileListFilter.class;
}
@Override
protected Class<? extends FileListFilter<?>> getRegexPatternFileListFilterClass() {
return SmbRegexPatternFileListFilter.class;
}
@Override
protected Class<? extends AbstractPersistentAcceptOnceFileListFilter<?>> getPersistentAcceptOnceFileListFilterClass() {
return SmbPersistentAcceptOnceFileListFilter.class;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2012-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.config;
import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHandler;
/**
* Provides namespace support for using SMB.
*
* @author Markus Spann
* @author Artem Bilan
*
* @since 6.0
*/
public class SmbNamespaceHandler extends AbstractIntegrationNamespaceHandler {
public void init() {
registerBeanDefinitionParser("inbound-channel-adapter", new SmbInboundChannelAdapterParser());
registerBeanDefinitionParser("outbound-channel-adapter", new SmbOutboundChannelAdapterParser());
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2017-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.config;
import org.springframework.integration.file.config.RemoteFileOutboundChannelAdapterParser;
import org.springframework.integration.file.remote.RemoteFileOperations;
import org.springframework.integration.smb.session.SmbRemoteFileTemplate;
/**
* The parser for {@code <Int-smb:outbound-channel-adapter>}.
*
* @author Artem Bilan
*
* @since 6.0
*/
public class SmbOutboundChannelAdapterParser extends RemoteFileOutboundChannelAdapterParser {
@Override
protected Class<? extends RemoteFileOperations<?>> getTemplateClass() {
return SmbRemoteFileTemplate.class;
}
}

View File

@@ -0,0 +1,4 @@
/**
* SMB-specific file list filter classes.
*/
package org.springframework.integration.smb.config;

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2018-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.filters;
import org.springframework.integration.file.filters.AbstractPersistentAcceptOnceFileListFilter;
import org.springframework.integration.metadata.ConcurrentMetadataStore;
import jcifs.smb.SmbFile;
/**
* Implementation of {@link AbstractPersistentAcceptOnceFileListFilter} for SMB.
*
* @author Prafull Kumar Soni
*
* @since 6.0
*/
public class SmbPersistentAcceptOnceFileListFilter extends AbstractPersistentAcceptOnceFileListFilter<SmbFile> {
public SmbPersistentAcceptOnceFileListFilter(ConcurrentMetadataStore store, String prefix) {
super(store, prefix);
}
@Override
protected long modified(SmbFile file) {
return file.getLastModified();
}
@Override
protected String fileName(SmbFile file) {
return file.getName();
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2012-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.filters;
import java.io.UncheckedIOException;
import java.util.regex.Pattern;
import org.springframework.integration.file.filters.AbstractRegexPatternFileListFilter;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
/**
* Implementation of {@link AbstractRegexPatternFileListFilter} for SMB.
*
* @author Markus Spann
* @author Prafull Kumar Soni
*
* @since 6.0
*/
public class SmbRegexPatternFileListFilter extends AbstractRegexPatternFileListFilter<SmbFile> {
public SmbRegexPatternFileListFilter(String pattern) {
this(Pattern.compile(pattern));
}
public SmbRegexPatternFileListFilter(Pattern pattern) {
super(pattern);
}
/**
* Gets the specified SMB file's name.
* @param file SMB file object
* @return file name
* @see AbstractRegexPatternFileListFilter#getFilename(java.lang.Object)
*/
@Override
protected String getFilename(SmbFile file) {
return (file != null ? file.getName() : null);
}
@Override
protected boolean isDirectory(SmbFile file) {
try {
return file.isDirectory();
}
catch (SmbException e) {
throw new UncheckedIOException(e);
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2018-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.filters;
import java.io.UncheckedIOException;
import org.springframework.integration.file.filters.AbstractSimplePatternFileListFilter;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
/**
* Implementation of {@link AbstractSimplePatternFileListFilter} for SMB.
*
* @author Markus Spann
* @author Prafull Kumar Soni
*
* @since 6.0
*/
public class SmbSimplePatternFileListFilter extends AbstractSimplePatternFileListFilter<SmbFile> {
public SmbSimplePatternFileListFilter(String pathPattern) {
super(pathPattern);
}
/**
* Gets the specified SMB file's name.
* @param file SMB file object
* @return file name
* @see AbstractSimplePatternFileListFilter#getFilename(java.lang.Object)
*/
@Override
protected String getFilename(SmbFile file) {
return (file != null) ? file.getName() : null;
}
@Override
protected boolean isDirectory(SmbFile file) {
try {
return file.isDirectory();
}
catch (SmbException e) {
throw new UncheckedIOException(e);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2018-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.filters;
import java.util.Map;
import java.util.function.Function;
import org.springframework.integration.file.filters.AbstractMarkerFilePresentFileListFilter;
import org.springframework.integration.file.filters.FileListFilter;
import jcifs.smb.SmbFile;
/**
* Implementation of {@link AbstractMarkerFilePresentFileListFilter} for SMB.
*
* @author Prafull Kumar Soni
*
* @since 6.0
*/
public class SmbSystemMarkerFilePresentFileListFilter extends AbstractMarkerFilePresentFileListFilter<SmbFile> {
public SmbSystemMarkerFilePresentFileListFilter(FileListFilter<SmbFile> filter) {
super(filter);
}
public SmbSystemMarkerFilePresentFileListFilter(FileListFilter<SmbFile> filter, String suffix) {
super(filter, suffix);
}
public SmbSystemMarkerFilePresentFileListFilter(FileListFilter<SmbFile> filter, Function<String, String> function) {
super(filter, function);
}
public SmbSystemMarkerFilePresentFileListFilter(
Map<FileListFilter<SmbFile>, Function<String, String>> filtersAndFunctions) {
super(filtersAndFunctions);
}
@Override
protected String getFilename(SmbFile file) {
return file.getName();
}
}

View File

@@ -0,0 +1,4 @@
/**
* SMB Namespace support classes.
*/
package org.springframework.integration.smb.filters;

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2012-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.inbound;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer;
import jcifs.smb.SmbFile;
/**
* An implementation of {@link AbstractInboundFileSynchronizer} for SMB.
*
* @author Markus Spann
* @author Artem Bilan
*
* @since 6.0
*/
public class SmbInboundFileSynchronizer extends AbstractInboundFileSynchronizer<SmbFile> {
/**
* Create a synchronizer with the {@link SessionFactory} used to acquire
* {@link org.springframework.integration.file.remote.session.Session} instances.
* @param sessionFactory the {@link SessionFactory} to use.
*/
public SmbInboundFileSynchronizer(SessionFactory<SmbFile> sessionFactory) {
super(sessionFactory);
}
@Override
protected boolean isFile(SmbFile _file) {
try {
return _file != null && _file.isFile();
}
catch (Exception _ex) {
logger.warn("Unable to get resource status [" + _file + "].", _ex);
}
return false;
}
@Override
protected String getFilename(SmbFile _file) {
return _file != null ? _file.getName() : null;
}
@Override
protected long getModified(SmbFile file) {
return file.getLastModified();
}
@Override
protected String protocol() {
return "smb";
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2012-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.inbound;
import java.io.File;
import java.util.Comparator;
import org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer;
import org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource;
import jcifs.smb.SmbFile;
/**
* A {@link org.springframework.integration.core.MessageSource} implementation for SMB.
*
* @author Markus Spann
*
* @since 6.0
*/
public class SmbInboundFileSynchronizingMessageSource extends AbstractInboundFileSynchronizingMessageSource<SmbFile> {
public SmbInboundFileSynchronizingMessageSource(AbstractInboundFileSynchronizer<SmbFile> _synchronizer) {
this(_synchronizer, null);
}
public SmbInboundFileSynchronizingMessageSource(AbstractInboundFileSynchronizer<SmbFile> _synchronizer,
Comparator<File> _comparator) {
super(_synchronizer, _comparator);
}
@Override
public String getComponentType() {
return "smb:inbound-channel-adapter";
}
}

View File

@@ -0,0 +1,4 @@
/**
* Inbound Channel Adapters implementations for SMB protocol.
*/
package org.springframework.integration.smb.inbound;

View File

@@ -0,0 +1,47 @@
/*
* 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 jcifs.smb.SmbFile;
/**
* The SMB specific {@link FileTransferringMessageHandler} extension. Based on the
* {@link SmbRemoteFileTemplate}.
*
* @author Gregory Bragg
* @author Artem Bilan
*
* @since 6.0
*
* @see SmbRemoteFileTemplate
*/
public class SmbMessageHandler extends FileTransferringMessageHandler<SmbFile> {
public SmbMessageHandler(SessionFactory<SmbFile> sessionFactory) {
this(sessionFactory, FileExistsMode.REPLACE);
}
public SmbMessageHandler(SessionFactory<SmbFile> sessionFactory, FileExistsMode mode) {
super(new SmbRemoteFileTemplate(sessionFactory), mode);
}
}

View File

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

View File

@@ -0,0 +1,225 @@
/*
* Copyright 2012-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.session;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import jcifs.DialectVersion;
/**
* Data holder class for a SMB share configuration.
*
* SmbFile URLs syntax:
* smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]]
*
* @author Markus Spann
* @author Prafull Kumar Soni
* @author Artem Bilan
* @author Gregory Bragg
*
* @since 6.0
*/
public class SmbConfig {
private String host;
private int port;
private String domain;
private String username;
private String password;
private String shareAndDir;
/**
* Defaults to and follows the jCIFS library default of 'SMB1'.
*/
private DialectVersion smbMinVersion = DialectVersion.SMB1;
/**
* Defaults to and follows the jCIFS library default of 'SMB210'.
*/
private DialectVersion smbMaxVersion = DialectVersion.SMB210;
public SmbConfig() {
}
public SmbConfig(String _host, int _port, String _domain, String _username, String _password, String _shareAndDir) {
setHost(_host);
setPort(_port);
setDomain(_domain);
setUsername(_username);
setPassword(_password);
setShareAndDir(_shareAndDir);
}
public void setHost(String _host) {
Assert.hasText(_host, "host must not be empty");
this.host = _host;
}
public String getHost() {
return this.host;
}
public void setPort(int _port) {
Assert.isTrue(_port >= 0, "port must be >= 0");
this.port = _port;
}
public int getPort() {
return this.port;
}
public void setDomain(String _domain) {
Assert.notNull(_domain, "_domain can't be null");
this.domain = _domain;
}
public String getDomain() {
return this.domain;
}
public void setUsername(String _username) {
Assert.hasText(_username, "username should be a non-empty string");
this.username = _username;
}
public String getUsername() {
return this.username;
}
public void setPassword(String _password) {
Assert.notNull(_password, "password should not be null");
this.password = _password;
}
public String getPassword() {
return this.password;
}
public void setShareAndDir(String _shareAndDir) {
Assert.notNull(_shareAndDir, "shareAndDir should not be null");
this.shareAndDir = _shareAndDir;
}
public String getShareAndDir() {
return this.shareAndDir;
}
/**
* Gets the desired minimum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @return one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
*/
public DialectVersion getSmbMinVersion() {
return this.smbMinVersion;
}
/**
* Sets the desired minimum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @param _smbMinVersion one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
*/
public void setSmbMinVersion(DialectVersion _smbMinVersion) {
this.smbMinVersion = _smbMinVersion;
}
/**
* Gets the desired maximum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @return one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
*/
public DialectVersion getSmbMaxVersion() {
return this.smbMaxVersion;
}
/**
* Sets the desired maximum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @param _smbMaxVersion one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
*/
public void setSmbMaxVersion(DialectVersion _smbMaxVersion) {
this.smbMaxVersion = _smbMaxVersion;
}
String getDomainUserPass(boolean _includePassword) {
String domainUserPass;
if (StringUtils.hasText(this.domain)) {
domainUserPass = String.format("%s;%s", this.domain, this.username);
}
else {
domainUserPass = this.username;
}
if (StringUtils.hasText(this.password)) {
domainUserPass += ":" + (_includePassword ? this.password : "********");
}
return domainUserPass;
}
String getHostPort() {
return this.host + (this.port > 0 ? String.format(":%d", this.port) : "");
}
/**
* Validates the object. Throws run-time exception if found to be invalid.
* @return the object
*/
public final SmbConfig validate() {
Assert.hasText(getHost(), () -> "host must not be empty in " + this);
Assert.isTrue(getPort() >= 0, () -> "port must be >= 0 in " + this);
Assert.hasText(getShareAndDir(), () -> "share must not be empty in " + this);
return this;
}
public final String getUrl() {
return getUrl(true);
}
public final String getUrl(boolean _includePassword) {
String domainUserPass = getDomainUserPass(_includePassword);
String path = StringUtils.cleanPath(this.shareAndDir);
if (!path.startsWith("/")) {
path = "/" + path;
}
try {
return new URI("smb", domainUserPass, this.host, this.port, path, null, null)
.toASCIIString();
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public String toString() {
return getClass().getSimpleName()
+ "[url=" + getUrl(false)
+ "]";
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2017-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.session;
import org.springframework.integration.file.remote.RemoteFileTemplate;
import org.springframework.integration.file.remote.session.SessionFactory;
import jcifs.smb.SmbFile;
/**
* The SMB-specific {@link RemoteFileTemplate} implementation.
*
* @author Artem Bilan
*
* @since 6.0
*/
public class SmbRemoteFileTemplate extends RemoteFileTemplate<SmbFile> {
/**
* Construct a {@link SmbRemoteFileTemplate} with the supplied session factory.
* @param sessionFactory the session factory.
*/
public SmbRemoteFileTemplate(SessionFactory<SmbFile> sessionFactory) {
super(sessionFactory);
}
}

View File

@@ -0,0 +1,488 @@
/*
* Copyright 2012-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.session;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileOutputStream;
/**
* Implementation of the {@link Session} interface for Server Message Block (SMB)
* also known as Common Internet File System (CIFS). The Samba project set out to
* create non-Windows implementations of SMB. Often Samba is thus used synonymously to SMB.
*
* SMB is an application-layer network protocol that manages shared access to files, printers
* and other networked resources.
*
* See <a href="https://en.wikipedia.org/wiki/Server_Message_Block">Server Message Block</a>
* for more details.
*
* @author Markus Spann
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Artem Bilan
* @author Prafull Kumar Soni
* @author Gregory Bragg
* @author Adam Jones
*
* @since 6.0
*/
public class SmbSession implements Session<SmbFile> {
private static final Log logger = LogFactory.getLog(SmbSession.class);
private static final String FILE_SEPARATOR = System.getProperty("file.separator");
private static final String SMB_FILE_SEPARATOR = "/";
private final SmbShare smbShare;
/**
* Constructor for an SMB session.
* @param _host server NetBIOS name, DNS name, or IP address, case-insensitive
* @param _port port
* @param _domain case-sensitive domain name
* @param _user case-sensitive username
* @param _password case-sensitive password
* @param _shareAndDir server root SMB directory
* @throws IOException in case of I/O errors
*/
SmbSession(String _host, int _port, String _domain, String _user, String _password, String _shareAndDir)
throws IOException {
this(new SmbShare(new SmbConfig(_host, _port, _domain, _user, _password, _shareAndDir)));
}
/**
* Constructor for an SMB session.
* @param _smbShare SMB share resource
*/
public SmbSession(SmbShare _smbShare) {
Assert.notNull(_smbShare, "smbShare must not be null");
this.smbShare = _smbShare;
if (logger.isDebugEnabled()) {
logger.debug("New " + getClass().getName() + " created.");
}
}
/**
* Deletes the file or directory at the specified path.
* @param _path path to a remote file or directory
* @return true if delete successful, false if resource is non-existent
* @throws IOException on error conditions returned by a CIFS server
*/
@Override
public boolean remove(String _path) throws IOException {
Assert.hasText(_path, "path must not be empty");
boolean removed = false;
SmbFile removeFile = createSmbFileObject(_path);
if (removeFile.exists()) {
removeFile.delete();
removed = true;
}
if (!removed && logger.isInfoEnabled()) {
logger.info("Could not remove non-existing resource [" + _path + "].");
}
else if (logger.isInfoEnabled()) {
logger.info("Successfully removed resource [" + _path + "].");
}
return removed;
}
/**
* Returns the contents of the specified SMB resource as an array of SmbFile objects.
* In case the remote resource does not exist, an empty array is returned.
* @param _path path to a remote directory
* @return array of SmbFile objects
* @throws IOException on error conditions returned by a CIFS server or if the remote resource is not a directory.
*/
@Override
public SmbFile[] list(String _path) throws IOException {
SmbFile[] files = new SmbFile[0];
try {
SmbFile smbDir = createSmbDirectoryObject(_path);
if (!smbDir.exists()) {
if (logger.isWarnEnabled()) {
logger.warn("Remote directory [" + _path + "] does not exist. Cannot list resources.");
}
return files;
}
else if (!smbDir.isDirectory()) {
throw new IOException("Resource [" + _path + "] is not a directory. Cannot list resources.");
}
files = smbDir.listFiles();
}
catch (SmbException _ex) {
throw new IOException("Failed to list resources in [" + _path + "].", _ex);
}
if (logger.isDebugEnabled()) {
logger.debug("Successfully listed " + files.length + " resource(s) in [" + _path + "]"
+ ": " + Arrays.toString(files));
}
else if (logger.isInfoEnabled()) {
logger.info("Successfully listed " + files.length + " resource(s) in [" + _path + "]" + ".");
}
return files;
}
/**
* Reads the remote resource specified by path and copies its contents to the specified
* {@link OutputStream}.
* @param _path path to a remote file
* @param _outputStream output stream
* @throws IOException on error conditions returned by a CIFS server or if the remote resource is not a file.
*/
@Override
public void read(String _path, OutputStream _outputStream) throws IOException {
Assert.hasText(_path, "path must not be empty");
Assert.notNull(_outputStream, "outputStream must not be null");
try {
SmbFile remoteFile = createSmbFileObject(_path);
if (!remoteFile.isFile()) {
throw new IOException("Resource [" + _path + "] is not a file.");
}
FileCopyUtils.copy(remoteFile.getInputStream(), _outputStream);
}
catch (SmbException _ex) {
throw new IOException("Failed to read resource [" + _path + "].", _ex);
}
if (logger.isInfoEnabled()) {
logger.info("Successfully read resource [" + _path + "].");
}
}
/**
* Writes contents of the specified {@link InputStream} to the remote resource
* specified by path. Remote directories are created implicitly as required.
* @param _inputStream input stream
* @param _path remote path (of a file) to write to
* @throws IOException on error conditions returned by a CIFS server
*/
@Override
public void write(InputStream _inputStream, String _path) throws IOException {
Assert.notNull(_inputStream, "inputStream must not be empty");
Assert.hasText(_path, "path must not be null");
try {
mkdirs(_path);
SmbFile targetFile = createSmbFileObject(_path);
FileCopyUtils.copy(_inputStream, targetFile.getOutputStream());
}
catch (SmbException _ex) {
throw new IOException("Failed to write resource [" + _path + "].", _ex);
}
if (logger.isInfoEnabled()) {
logger.info("Successfully wrote remote file [" + _path + "].");
}
}
/**
* Convenience method to write a local file object to a remote location.
* @param _file the local file
* @param _path the remote path to write to
* @return the {@link SmbFile} for remote file
* @throws IOException the IO exception
*/
public SmbFile write(File _file, String _path) throws IOException {
return writeAndClose(new FileInputStream(_file), _path);
}
/**
* Convenience method to write a byte array to a remote location.
* @param _contents the {@code byte[]} to write
* @param _path the remote file to write to
* @return the {@link SmbFile} for remote file
* @throws IOException the IO exception
*/
public SmbFile write(byte[] _contents, String _path) throws IOException {
return writeAndClose(new ByteArrayInputStream(_contents), _path);
}
/**
* Creates the specified remote path if not yet exists.
* If the specified resource is a file rather than a path, creates all directories leading
* to that file.
* @param _path remote path to create
* @return always true (error states are express by exceptions)
* @throws IOException on error conditions returned by a CIFS server
*/
@Override
public boolean mkdir(String _path) throws IOException {
try {
SmbFile dir = createSmbDirectoryObject(_path);
if (!dir.exists()) {
dir.mkdirs();
if (logger.isInfoEnabled()) {
logger.info(
"Successfully created remote directory [" + _path + "] in share [" + this.smbShare + "].");
}
}
else {
if (logger.isInfoEnabled()) {
logger.info("Remote directory [" + _path + "] exists in share [" + this.smbShare + "].");
}
}
return true;
}
catch (SmbException _ex) {
throw new IOException("Failed to create directory [" + _path + "].", _ex);
}
}
/**
* Checks whether the remote resource exists.
* @param _path remote path
* @return true if exists, false otherwise
* @throws IOException on error conditions returned by a CIFS server
*/
@Override
public boolean exists(String _path) throws IOException {
return createSmbFileObject(_path).exists();
}
/**
* Checks whether the remote resource is a file.
* @param _path remote path
* @return true if resource is a file, false otherwise
* @throws IOException on error conditions returned by a CIFS server
*/
public boolean isFile(String _path) throws IOException {
SmbFile resource = createSmbFileObject(_path);
return resource.exists() && resource.isFile();
}
/**
* Checks whether the remote resource is a directory.
* @param _path remote path
* @return true if resource is a directory, false otherwise
* @throws IOException on error conditions returned by a CIFS server
*/
public boolean isDirectory(String _path) throws IOException {
SmbFile resource = createSmbFileObject(_path);
return resource.exists() && resource.isDirectory();
}
/**
* Create all directories in the given remote path reference.
* @param _path path remote path, may be a file in which case the file name is ignored
* @return the path created or null
* @throws IOException on error conditions returned by a CIFS server
*/
String mkdirs(String _path) throws IOException {
int idxPath = _path.lastIndexOf(FILE_SEPARATOR);
if (idxPath > -1) {
String path = _path.substring(0, idxPath + 1);
mkdir(path);
return path;
}
return null;
}
@Override
public void rename(String _pathFrom, String _pathTo) throws IOException {
try {
SmbFile smbFileFrom = createSmbFileObject(_pathFrom);
SmbFile smbFileTo = createSmbFileObject(_pathTo);
if (smbFileTo.exists()) {
smbFileTo.delete();
}
smbFileFrom.renameTo(smbFileTo);
}
catch (SmbException _ex) {
throw new IOException("Failed to rename [" + _pathFrom + "] to [" + _pathTo + "].", _ex);
}
if (logger.isInfoEnabled()) {
logger.info("Successfully renamed remote resource [" + _pathFrom + "] to [" + _pathTo + "].");
}
}
@Override
public void append(InputStream inputStream, String destination) throws IOException {
SmbFile smbFile = createSmbFileObject(destination);
OutputStream fileOutputStream = new SmbFileOutputStream(smbFile, true);
FileCopyUtils.copy(inputStream, fileOutputStream);
}
@Override
public boolean rmdir(String directory) throws IOException {
SmbFile dir = createSmbDirectoryObject(directory);
try {
dir.delete();
}
catch (SmbException e) {
if (logger.isWarnEnabled()) {
logger.info("Failed to remove remote directory [" + directory + "]: " + e);
}
return false;
}
if (logger.isInfoEnabled()) {
logger.info("Successfully removed remote directory [" + directory + "].");
}
return true;
}
@Override
public InputStream readRaw(String source) throws IOException {
SmbFile remoteFile = createSmbFileObject(source);
if (!remoteFile.isFile()) {
throw new IOException("Resource [" + source + "] is not a file.");
}
return remoteFile.getInputStream();
}
@Override
public boolean finalizeRaw() {
return true;
}
@Override
public Object getClientInstance() {
return this.smbShare;
}
@Override
public void close() {
this.smbShare.close();
}
/**
* Checks with this SMB session is open and ready for work by attempting
* to list remote files and checking for error conditions..
* @return true if the session is open, false otherwise
*/
@Override
public boolean isOpen() {
if (!this.smbShare.isOpened()) {
return false;
}
try {
this.smbShare.listFiles();
}
catch (Exception _ex) {
close();
}
return this.smbShare.isOpened();
}
/**
* Convenience method to write the specified input stream to a remote path and return
* the path as an SMB file object.
* @param _inputStream input stream
* @param _path remote path (of a file) to write to
* @return SMB file object
* @throws IOException on error conditions returned by a CIFS server
*/
SmbFile writeAndClose(InputStream _inputStream, String _path) throws IOException {
write(_inputStream, _path);
_inputStream.close();
return createSmbFileObject(_path);
}
/**
* Factory method for new SmbFile objects under this session's share for the specified path.
* @param path remote path
* @param isDirectory Boolean object to indicate the path is a directory, may be null
* @return SmbFile object for path
* @throws IOException in case of I/O errors
*/
private SmbFile createSmbFileObject(String path, Boolean isDirectory) throws IOException {
final String cleanedPath = StringUtils.cleanPath(path);
if (!StringUtils.hasText(cleanedPath)) {
return this.smbShare;
}
SmbFile smbFile = new SmbFile(this.smbShare, cleanedPath);
boolean appendFileSeparator = !cleanedPath.endsWith(SMB_FILE_SEPARATOR);
if (appendFileSeparator) {
try {
appendFileSeparator = smbFile.isDirectory() || (isDirectory != null && isDirectory);
}
catch (SmbException ex) {
appendFileSeparator = false;
}
}
if (appendFileSeparator) {
smbFile = createSmbFileObject(cleanedPath + SMB_FILE_SEPARATOR);
}
if (logger.isDebugEnabled()) {
logger.debug("Created new " + SmbFile.class.getName() + "[" + smbFile + "] for path [" + path + "].");
}
return smbFile;
}
/**
* Creates an SMB file object pointing to a remote file.
* @param _path the remote file path
* @return the {@link SmbFile} for remote path
* @throws IOException the IO exception
*/
public SmbFile createSmbFileObject(String _path) throws IOException {
return createSmbFileObject(_path, null);
}
/**
* Creates an SMB file object pointing to a remote directory.
* @param _path the remote directory path
* @return the {@link SmbFile} for remote path
* @throws IOException the IO exception
*/
public SmbFile createSmbDirectoryObject(String _path) throws IOException {
return createSmbFileObject(_path, true);
}
@Override
public String getHostPort() {
URL url = this.smbShare.getURL();
return url.getHost() + ":" + url.getPort();
}
@Override
public String[] listNames(String path) {
throw new UnsupportedOperationException("Not implemented yet");
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2012-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.session;
import java.io.IOException;
import java.util.Properties;
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;
/**
* The SMB session factory.
*
* @author Markus Spann
* @author Gregory Bragg
* @author Artem Bilan
*
* @since 6.0
*/
public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFile> {
private static final 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
*/
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 {
return createSession();
}
catch (Exception _ex) {
throw new IllegalStateException("Failed to create session.", _ex);
}
}
protected SmbSession createSession() throws IOException {
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 = new SmbShare(this, props);
}
if (logger.isInfoEnabled()) {
logger.info(String.format("SMB share init: %s/%s", getHostPort(), getShareAndDir()));
}
smbShare.init();
logger.debug("SMB share initialized.");
return new SmbSession(smbShare);
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2012-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.session;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import jcifs.CIFSContext;
import jcifs.CIFSException;
import jcifs.config.PropertyConfiguration;
import jcifs.context.BaseContext;
import jcifs.context.SingletonContext;
import jcifs.smb.NtlmPasswordAuthenticator;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
/**
* The {@link SmbFile} extension to represent an SMB share directory.
*
* @author Markus Spann
* @author Gregory Bragg
* @author Adam Jones
*
* @since 6.0
*/
public class SmbShare extends SmbFile {
private static final Log logger = LogFactory.getLog(SmbShare.class);
private final AtomicBoolean open = new AtomicBoolean(false);
private final AtomicBoolean closeContext = new AtomicBoolean(false);
/**
* Initializes the jCIFS library with default properties.
* @param _smbConfig the SMB share configuration
* @throws IOException if an invalid SMB URL was constructed by jCIFS
*/
public SmbShare(SmbConfig _smbConfig) throws IOException {
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
SingletonContext.getInstance().withCredentials(
new NtlmPasswordAuthenticator(
_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
*/
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'
* for setting the minimum/maximum SMB supported versions.
* @param _smbConfig the SMB share configuration
* @param _props the custom property set for jCIFS to initialize
* @throws IOException if an invalid property was set or an invalid SMB URL was constructed by jCIFS
*/
public SmbShare(SmbConfig _smbConfig, Properties _props) throws IOException {
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
new BaseContext(
new PropertyConfiguration(_props)).withCredentials(
new NtlmPasswordAuthenticator(
_smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword())));
this.closeContext.set(true);
}
public void init() throws IOException {
boolean canRead;
try {
if (!exists()) {
logger.info("SMB root directory does not exist. Creating it.");
mkdirs();
}
canRead = canRead();
}
catch (SmbException _ex) {
if (this.closeContext.get()) {
try {
getContext().close();
}
catch (CIFSException e) {
logger.error("Unable to close share: " + this);
}
}
throw new IOException("Unable to initialize share: " + this, _ex);
}
Assert.isTrue(canRead, "Share is not accessible " + this);
this.open.set(true);
}
/**
* Checks whether the share is accessible.
* Note: jcifs.smb.SmbFile defines a package-protected method isOpen().
* @return true if open
*/
boolean isOpened() {
return this.open.get();
}
@Override
public synchronized void close() {
this.open.set(false);
if (this.closeContext.get()) {
try {
getContext().close();
}
catch (CIFSException e) {
logger.error("Unable to close share: " + this);
}
}
super.close();
}
public String newTempFileSuffix() {
return "-" + Long.toHexString(Double.doubleToLongBits(Math.random())) + ".tmp";
}
}

View File

@@ -0,0 +1,4 @@
/**
* SMB Remote Session abstraction support classes.
*/
package org.springframework.integration.smb.session;

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/integration/smb=org.springframework.integration.smb.config.SmbNamespaceHandler

View File

@@ -0,0 +1,4 @@
http\://www.springframework.org/schema/integration/smb/spring-integration-smb-1.0.xsd=org/springframework/integration/smb/config/spring-integration-smb.xsd
http\://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd=org/springframework/integration/smb/config/spring-integration-smb.xsd
https\://www.springframework.org/schema/integration/smb/spring-integration-smb-1.0.xsd=org/springframework/integration/smb/config/spring-integration-smb.xsd
https\://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd=org/springframework/integration/smb/config/spring-integration-smb.xsd

View File

@@ -0,0 +1,4 @@
# Tooling related information for the integration smb namespace
http\://www.springframework.org/schema/integration/smb@name=Integration SMB Namespace
http\://www.springframework.org/schema/integration/smb@prefix=int-smb
http\://www.springframework.org/schema/integration/smb@icon=org/springframework/integration/smb/config/spring-integration-smb.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

View File

@@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/integration/smb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/integration/smb"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="https://www.springframework.org/schema/integration/spring-integration.xsd"/>
<xsd:annotation>
<xsd:documentation><![CDATA[
The handler for namespace 'http://www.springframework.org/schema/integration/smb'
is set to 'org.springframework.integration.smb.config.SmbNamespaceHandler'
in file 'spring.handlers'. SmbNamespaceHandler sets the implementation
of 'inbound-channel-adapter' to class 'SmbInboundChannelAdapterParser'
etc.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an outbound-channel-adapter that writes files to a remote
SMB endpoint.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="base-smb-adapter-type">
<xsd:all>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType" minOccurs="0" maxOccurs="1" />
</xsd:all>
<xsd:attribute name="remote-directory" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Identifies directory path (e.g., "/temp/mytransfers/")
where file will be transferred to.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-directory-expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide SpEL expression which will
compute directory path where file will be
transferred to (e.g., "headers.['remote_dir'] + '/myTransfers'");
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-file-separator" type="xsd:string" default="/">
<xsd:annotation>
<xsd:documentation>
Allows you to provide remote file/directory separator
character. DEFAULT: '/'
</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>
Allows you to specify a reference to a
[org.springframework.integration.file.FileNameGenerator] bean.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.FileNameGenerator"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-filename-generator-expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide SpEL expression which will
compute file name of the remote file (e.g., assuming
payload is java.io.File "payload.getName() + '.transfered'");
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Specifies the order for invocation when this
endpoint is connected as a subscriber to a channel.
This is particularly relevant when that channel
is using a "failover" dispatching strategy, or
when a failure in the delivery to one subscriber
should signal that the message should not be sent
to subscribers with a higher 'order' attribute.
It has no effect when this endpoint itself is a
Polling Consumer for a channel with a queue.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Builds an inbound-channel-adapter that synchronizes a local directory
with the contents of a remote SMB endpoint. The adapter requires
either no or exactly one file selection pattern (may be simple
pattern or regular expression).
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="base-smb-adapter-type">
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="filename-pattern" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide file name pattern to determine
the file names that needs to be scanned and is
based on simple pattern matching algorithm
(e.g., "*.txt, fo*.txt" etc.)
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filename-regex" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide Regular Expression to determine
the file names that needs to be scanned. (e.g., "f[o]+\.txt" etc.)
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="comparator" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specify a Comparator to be used when ordering
Files. If none is provided, the order will be
determined by the java.io.File implementation of
Comparable.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.file.filters.FileListFilter"/>
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
Allows you to specify a reference to
[org.springframework.integration.file.filters.FileListFilter] bean.
</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>
Identifies directory path (e.g., "/temp/mytransfers")
where file will be transferred FROM.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="remote-file-separator" type="xsd:string" default="/">
<xsd:annotation>
<xsd:documentation>
Allows you to provide remote file/directory separator
character. DEFAULT: '/'
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="local-filter" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.file.filters.FileListFilter" />
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
Allows you to specify a reference to a
[org.springframework.integration.file.filters.FileListFilter]
bean. This filter is applied to files after they have been
retrieved. The default is an AcceptOnceFileListFilter which means that,
even if a new instance of a file is retrieved from the remote server,
a message won't be generated. The filter provided here is combined
with a filter that prevents the message source from processing
files that are currently being downloaded.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="local-directory" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
Identifies directory path (e.g., "/local/mytransfers")
where file will be transferred to.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-create-local-directory" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Tells this adapter if local directory must be
auto-created if it doesn't exist. Default is TRUE.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="delete-remote-files" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Specify whether to delete the remote source file after copying.
By default, the remote files will NOT be deleted.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="base-smb-adapter-type">
<xsd:attribute name="session-factory" type="xsd:string" use="required">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.smb.session.SmbSessionFactory"/>
</tool:annotation>
</xsd:appinfo>
<xsd:documentation><![CDATA[
Reference to a org.springframework.integration.smb.session.SmbSessionFactory bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="charset" type="xsd:string" default="UTF-8">
<xsd:annotation>
<xsd:documentation>
Allows you to specify Charset (e.g., US-ASCII, ISO-8859-1, UTF-8).
[UTF-8] is the default.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="integration:channelAdapterAttributes" />
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,276 @@
/*
* Copyright 2012-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;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
/**
* Assorted test utils for the library.
*
* @author Markus Spann
* @author Gregory Bragg
*/
public abstract class AbstractBaseTests {
/** Instance logger. */
private final Log logger = LogFactory.getLog(this.getClass());
protected final Log getLogger() {
return logger;
}
@Rule
public final TestName testMethodName = new TestName();
private String getTestMethodName() {
return getClass().getSimpleName() + '.' + testMethodName.getMethodName() + "()";
}
@Before
public final void logTestBegin() {
getLogger().info("BGN - Test " + getTestMethodName());
}
@After
public final void logTestEnd() {
getLogger().info("END - Test " + getTestMethodName());
}
/**
* Constructs the Spring application context XML file name from simple class name and suffix '-context.xml'.
* @param _suffix optional suffix
* @return application context XML file name
*/
protected final String getApplicationContextXmlFile(String _suffix) {
String fn = getClass().getSimpleName();
if (StringUtils.hasText(_suffix)) {
fn += _suffix;
}
fn += "-context.xml";
getLogger().debug("Returning application context xml file [" + fn + "] for class [" + getClass().getName() + "].");
return fn;
}
/**
* Constructs the Spring application context XML file name from simple class name.
* @return application context XML file name
*/
protected final String getApplicationContextXmlFile() {
return getApplicationContextXmlFile(null);
}
protected final ClassPathXmlApplicationContext getApplicationContext() {
return new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), getClass());
}
/**
* Writes the specified input stream to file.
* @param _inputStream input stream
* @param _path output file path
* @throws IOException in case of I/O errors
*/
public static void writeToFile(InputStream _inputStream, String _path) throws IOException {
FileOutputStream fos = new FileOutputStream(_path);
try {
FileCopyUtils.copy(_inputStream, fos);
}
finally {
fos.close();
}
}
/**
* Writes the specified byte array to the output stream.
* @param _bytes byte array
* @param _outputStream output stream
* @throws IOException in case of I/O errors
*/
public static void writeToFile(byte[] _bytes, OutputStream _outputStream) throws IOException {
FileCopyUtils.copy(_bytes, _outputStream);
}
/**
* Writes the specified byte array to the an output file.
* @param _bytes byte array
* @param _fileName output file
* @throws IOException in case of I/O errors
*/
public static void writeToFile(byte[] _bytes, String _fileName) throws IOException {
FileOutputStream fos = new FileOutputStream(_fileName);
writeToFile(_bytes, fos);
fos.close();
}
/**
* Creates a new file of the given name.
* If the file exists, it will be deleted.
* The file will be deleted on exit of the JVM.
* @param _fileName file name
* @return file object
*/
protected File createNewFile(String _fileName) {
File file = new File(_fileName);
file.deleteOnExit();
if (file.exists()) {
file.delete();
}
getLogger().debug("File object [" + _fileName + "] created: " + file.getAbsolutePath());
assertFileNotExists(file);
return file;
}
/**
* Deletes one or more files or directories.
* @param _files file or directories
*/
protected void delete(String... _files) {
for (String fileName : _files) {
if (fileName == null) {
continue;
}
File file = new File(fileName);
if (file.exists()) {
getLogger().debug("Deleting file [" + fileName + "].");
if (!file.delete()) {
file.deleteOnExit();
}
}
}
}
/**
* Checks if a directory exists, if not creates it and adds it to the DeleteOnExit hook.
* @param _dir directory
*/
protected void ensureExists(String _dir) {
File dir = new File(_dir);
if (!dir.exists()) {
dir.mkdirs();
dir.deleteOnExit();
}
}
/**
* Retrieves class name and method name at the specified stacktrace index.
* @param _index stacktrace index
* @return fully qualified method name
*/
private static String getStackTraceString(int _index) {
StackTraceElement[] arrStackTraceElems = new Throwable().fillInStackTrace().getStackTrace();
final int lIndex = Math.min(arrStackTraceElems.length - 1, Math.max(0, _index));
return arrStackTraceElems[lIndex].getClassName() + "." + arrStackTraceElems[lIndex].getMethodName();
}
/**
* Gets the current method name.
* @return method name
*/
public static String getMethodName() {
return getStackTraceString(2);
}
/**
* Gets the calling method name.
* @return method name
*/
public static String getCallingMethodName() {
return getStackTraceString(3);
}
/**
* Asserts that the specified file exists.
* @param _file file object
* @return the file object
*/
public static final File assertFileExists(File _file) {
return assertFileExists(_file, true);
}
public static final File assertFileNotExists(File _file) {
return assertFileExists(_file, false);
}
/**
* Asserts that the specified file exists or does not exists.
* @param _file file object
* @param _exists true if should exist, false otherwise
* @return the file object
*/
private static File assertFileExists(File _file, boolean _exists) {
assertThat(_file).as("File object is null.").isNotNull();
if (_exists) {
assertThat(_file.exists()).as("File [" + _file.getAbsolutePath() + "] does not exist.").isTrue();
}
else {
assertThat(!_file.exists()).as("File [" + _file.getAbsolutePath() + "] exists.").isTrue();
}
return _file;
}
public static final File assertFileExists(String _file) {
return assertFileExists(new File(_file));
}
/**
* Invokes one or more test methods on the specified test class.
* Catches exceptions during test setup (using reflection) and test invocation.
* @param _testClass test class object
* @param _methodNames String method names to invoke in order, no parameters expected
*/
@SuppressWarnings("deprecation")
protected static void runTests(Class<? extends AbstractBaseTests> _testClass, String... _methodNames)
throws Exception {
AbstractBaseTests test;
Method[] methods = new Method[_methodNames.length];
String methodName = null;
test = _testClass.newInstance();
for (int i = 0; i < _methodNames.length; i++) {
methodName = _methodNames[i];
methods[i] = _testClass.getMethod(methodName, (Class<?>[]) null);
}
Method method = null;
for (int i = 0; i < methods.length; i++) {
method = methods[i];
method.invoke(test, (Object[]) null);
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2002-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;
import java.util.Scanner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.smb.outbound.SmbMessageHandler;
import org.springframework.integration.smb.session.SmbSessionFactory;
import org.springframework.messaging.support.GenericMessage;
import jcifs.DialectVersion;
/**
* Starts the Spring Context and will initialize the Spring Integration routes.
*
* @author Gunnar Hillert
* @author Artem Bilan
* @author Gregory Bragg
*
* @since 1.0
*
*/
public final class Main {
private static final Log LOGGER = LogFactory.getLog(Main.class);
private Main() { }
/**
* Load the Spring Integration Application Context
*
* @param args - command line arguments
*/
public static void main(final String... args) {
final Scanner scanner = new Scanner(System.in);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("\n================================================================="
+ "\n "
+ "\n Welcome to the Spring Integration SMB Test Client "
+ "\n "
+ "\n For more information please visit: "
+ "\n https://github.com/SpringSource/spring-integration-extensions "
+ "\n "
+ "\n=================================================================");
}
final GenericXmlApplicationContext context = new GenericXmlApplicationContext();
LOGGER.info("Please enter the: ");
LOGGER.info("\t- SMB Host");
LOGGER.info("\t- SMB Share and Directory");
LOGGER.info("\t- SMB Username");
LOGGER.info("\t- SMB Password");
LOGGER.info("Host: ");
final String host = scanner.nextLine();
LOGGER.info("Share and Directory (e.g. myFile/path/to/): ");
final String shareAndDir = scanner.nextLine();
LOGGER.info("Username (e.g. guest): ");
final String username = scanner.nextLine();
LOGGER.info("Password (can be empty): ");
final String password = scanner.nextLine();
context.getEnvironment().getSystemProperties().put("host", host);
context.getEnvironment().getSystemProperties().put("shareAndDir", shareAndDir);
context.getEnvironment().getSystemProperties().put("username", username);
context.getEnvironment().getSystemProperties().put("password", password);
context.load("classpath:META-INF/spring/integration/*-context.xml");
context.registerShutdownHook();
context.refresh();
if (LOGGER.isInfoEnabled()) {
LOGGER.info("\n========================================================="
+ "\n "
+ "\n Please press 'q + Enter' to quit the application. "
+ "\n "
+ "\n=========================================================");
}
SmbSessionFactory smbSessionFactory = context.getBean("smbSession", SmbSessionFactory.class);
smbSessionFactory.setSmbMinVersion(DialectVersion.SMB210);
smbSessionFactory.setSmbMaxVersion(DialectVersion.SMB311);
LOGGER.info("Polling from Share: " + smbSessionFactory.getUrl());
// Create a test text file on the SMB file share
SmbMessageHandler handlerTxt = new SmbMessageHandler(smbSessionFactory);
handlerTxt.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handlerTxt.setFileNameGenerator(message -> "handlerContent.txt");
handlerTxt.setAutoCreateDirectory(true);
handlerTxt.setUseTemporaryFileName(false);
handlerTxt.setBeanFactory(context.getBeanFactory());
handlerTxt.afterPropertiesSet();
handlerTxt.handleMessage(new GenericMessage<String>("hello, my text"));
// Create a test binary file on the SMB file share using a temporary filename
SmbMessageHandler handlerBin = new SmbMessageHandler(smbSessionFactory);
handlerBin.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handlerBin.setFileNameGenerator(message -> "handlerContent.bin");
handlerBin.setAutoCreateDirectory(true);
handlerBin.setUseTemporaryFileName(true);
handlerBin.setBeanFactory(context.getBeanFactory());
handlerBin.afterPropertiesSet();
handlerBin.handleMessage(new GenericMessage<byte[]>("hello, my bytes".getBytes()));
while (true) {
final String input = scanner.nextLine();
if ("q".equals(input.trim())) {
scanner.close();
context.close();
break;
}
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Exiting application...bye.");
}
System.exit(0);
}
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
<int:message-history/>
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
<property name="host" value="localhost"/>
<property name="port" value="0"/>
<property name="domain" value=""/>
<property name="username" value="sambagu@est"/>
<property name="password" value="sambag%uest"/>
<property name="shareAndDir" value="smb-share/"/>
</bean>
<int-smb:inbound-channel-adapter id="smbInboundChannelAdapter"
session-factory="smbSessionFactory"
channel="smbInboundChannel"
auto-create-local-directory="true"
local-directory="file:test-temp/local-5"
remote-directory="test-temp/remote-9"
delete-remote-files="false">
<int:poller fixed-rate="1000"/>
</int-smb:inbound-channel-adapter>
<int:channel id="smbInboundChannel">
<int:queue/>
</int:channel>
</beans>

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2012-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;
import static org.assertj.core.api.Assertions.assertThat;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.smb.session.SmbSessionFactory;
/**
* @author Markus Spann
* @author Prafull Kumar Soni
* @author Artem Bilan
* @author Gregory Bragg
*/
public class SmbMessageHistoryTests extends AbstractBaseTests {
@Test
public void testMessageHistory() throws URISyntaxException {
ClassPathXmlApplicationContext applicationContext = getApplicationContext();
SourcePollingChannelAdapter adapter = applicationContext
.getBean("smbInboundChannelAdapter", SourcePollingChannelAdapter.class);
assertThat("smbInboundChannelAdapter").isEqualTo(adapter.getComponentName());
assertThat("smb:inbound-channel-adapter").isEqualTo(adapter.getComponentType());
SmbSessionFactory smbSessionFactory = applicationContext.getBean(SmbSessionFactory.class);
String url = smbSessionFactory.getUrl();
URI uri = new URI(url);
assertThat("sambagu%40est:sambag%25uest").isEqualTo(uri.getRawUserInfo());
assertThat("sambagu@est:sambag%uest").isEqualTo(uri.getUserInfo());
applicationContext.close();
}
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
<property name="host" value="localhost"/>
<property name="domain" value=""/>
<property name="username" value="sambaguest"/>
<property name="password" value="sambaguest"/>
<property name="shareAndDir" value="smb-share/"/>
</bean>
<int-smb:inbound-channel-adapter id="adapterSmb"
session-factory="smbSessionFactory"
channel="smbIn"
filename-pattern="foo"
local-directory="test-temp/local-10"
remote-directory="test-temp/remote-10"
auto-create-local-directory="true"
delete-remote-files="false">
<int:poller ref="smbPoller" />
</int-smb:inbound-channel-adapter>
<int-smb:inbound-channel-adapter id="adapterSmb2"
session-factory="smbSessionFactory"
channel="smbIn"
filter="filter"
local-directory="test-temp"
remote-directory="test-temp/remote-11"
auto-create-local-directory="true"
delete-remote-files="false">
<int:poller ref="smbPoller" />
</int-smb:inbound-channel-adapter>
<bean id="filter" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.file.filters.FileListFilter"/>
</bean>
<int:poller fixed-rate="3000" id="smbPoller" />
<int:channel id="smbIn">
<int:queue/>
</int:channel>
</beans>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
<property name="host" value="localhost"/>
<property name="domain" value=""/>
<property name="username" value="sambaguest"/>
<property name="password" value="sambaguest"/>
<property name="shareAndDir" value="smb-share/"/>
</bean>
<int-smb:inbound-channel-adapter id="adapterSmbDontAutoCreate"
channel="smbIn"
session-factory="smbSessionFactory"
filter="filter"
local-directory="file:test-temp/local-6"
remote-directory="test-temp/remote-12"
auto-create-local-directory="false"
delete-remote-files="false">
<int:poller fixed-rate="1000"/>
</int-smb:inbound-channel-adapter>
<bean id="filter" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.file.entries.EntryListFilter"/>
</bean>
<int:channel id="smbIn">
<int:queue/>
</int:channel>
</beans>

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2012-2018 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;
import java.io.File;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Markus Spann
* @author Prafull Kumar Soni
*
*/
public class SmbParserInboundTests extends AbstractBaseTests {
@Before
public void prepare() {
ensureExists("test-temp/remote-10");
cleanUp();
}
@Test
public void testLocalFilesAutoCreationTrue() {
assertFileNotExists(new File("test-temp/local-10"));
new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), this.getClass());
assertFileExists(new File("test-temp/local-10"));
assertFileNotExists(new File("test-temp/local-6"));
}
@Test(expected = BeanCreationException.class)
public void testLocalFilesAutoCreationFalse() {
assertFileNotExists(new File("test-temp/local-6"));
new ClassPathXmlApplicationContext(getApplicationContextXmlFile("-fail"), this.getClass())
.close();
}
@After
public void cleanUp() {
delete("test-temp/local-10", "test-temp/local-6");
}
public static void main(String[] _args) throws Exception {
new SmbParserInboundTests().cleanUp();
runTests(SmbParserInboundTests.class, "testLocalFilesAutoCreationTrue", "testLocalFilesAutoCreationFalse");
}
}

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb
https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
<bean id="smbSessionFactory"
class="org.springframework.integration.smb.config.SmbInboundChannelAdapterParserTests.TestSessionFactoryBean"/>
<bean id="acceptAllFilter" class="org.springframework.integration.file.filters.AcceptAllFileListFilter"/>
<int-smb:inbound-channel-adapter id="smbInbound"
auto-startup="false"
channel="smbChannel"
session-factory="smbSessionFactory"
charset="UTF-8"
auto-create-local-directory="true"
delete-remote-files="true"
filename-pattern="*.txt"
local-filter="acceptAllFilter"
local-directory="file:test-temp/local-1"
remote-file-separator=""
comparator="comparator"
temporary-file-suffix=".working.tmp"
remote-directory="test-temp/remote-1">
</int-smb:inbound-channel-adapter>
<bean id="comparator" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="java.util.Comparator"/>
</bean>
<int-smb:inbound-channel-adapter
channel="smbChannel"
auto-startup="false"
session-factory="smbSessionFactory"
charset="UTF-8"
auto-create-local-directory="true"
delete-remote-files="true"
filter="entryListFilter"
local-directory="file:test-temp/local-2"
remote-directory="test-temp/remote-2">
</int-smb:inbound-channel-adapter>
<int-smb:inbound-channel-adapter id="simpleAdapter"
channel="smbChannel"
auto-startup="false"
session-factory="smbSessionFactory"
local-directory="file:test-temp/local-3"
remote-directory="test-temp/remote-3">
</int-smb:inbound-channel-adapter>
<int:channel id="smbChannel">
<int:queue/>
</int:channel>
<bean id="entryListFilter" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.file.filters.FileListFilter"/>
</bean>
<int:poller fixed-rate="10000" default="true"/>
</beans>

View File

@@ -0,0 +1,140 @@
/*
* Copyright 2012-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.config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.file.filters.CompositeFileListFilter;
import org.springframework.integration.file.filters.FileListFilter;
import org.springframework.integration.smb.filters.SmbPersistentAcceptOnceFileListFilter;
import org.springframework.integration.smb.filters.SmbSimplePatternFileListFilter;
import org.springframework.integration.smb.inbound.SmbInboundFileSynchronizer;
import org.springframework.integration.smb.inbound.SmbInboundFileSynchronizingMessageSource;
import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Markus Spann
* @author Gunnar Hillert
* @author Artem Bilan
* @author Prafull Kumar Soni
* @author Gregory Bragg
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class SmbInboundChannelAdapterParserTests {
@Autowired
ApplicationContext applicationContext;
@Test(timeout = 100000)
public void testSmbInboundChannelAdapterComplete() {
final SourcePollingChannelAdapter adapter = this.applicationContext.getBean("smbInbound", SourcePollingChannelAdapter.class);
final PriorityBlockingQueue<?> queue = TestUtils.getPropertyValue(adapter, "source.fileSource.toBeReceived", PriorityBlockingQueue.class);
assertThat(queue.comparator()).isNotNull();
assertThat("smbInbound").isEqualTo(adapter.getComponentName());
assertThat("smb:inbound-channel-adapter").isEqualTo(adapter.getComponentType());
assertThat(applicationContext.getBean("smbChannel")).isEqualTo(TestUtils.getPropertyValue(adapter, "outputChannel"));
SmbInboundFileSynchronizingMessageSource inbound =
(SmbInboundFileSynchronizingMessageSource) TestUtils.getPropertyValue(adapter, "source");
SmbInboundFileSynchronizer fisync =
(SmbInboundFileSynchronizer) TestUtils.getPropertyValue(inbound, "synchronizer");
assertThat(".working.tmp").isEqualTo(TestUtils.getPropertyValue(fisync, "temporaryFileSuffix", String.class));
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
assertThat(remoteFileSeparator).isNotNull();
assertThat("").isEqualTo(remoteFileSeparator);
FileListFilter<?> filter = TestUtils.getPropertyValue(fisync, "filter", FileListFilter.class);
assertThat(filter).isNotNull();
assertThat(filter).isInstanceOf(CompositeFileListFilter.class);
Set<?> fileFilters = TestUtils.getPropertyValue(filter, "fileFilters", Set.class);
Iterator<?> filtersIterator = fileFilters.iterator();
assertThat(filtersIterator.next()).isInstanceOf(SmbSimplePatternFileListFilter.class);
assertThat(filtersIterator.next()).isInstanceOf(SmbPersistentAcceptOnceFileListFilter.class);
Object sessionFactory = TestUtils.getPropertyValue(fisync, "remoteFileTemplate.sessionFactory");
assertThat(SmbSessionFactory.class.isAssignableFrom(sessionFactory.getClass())).isTrue();
FileListFilter<?> acceptAllFilter = this.applicationContext.getBean("acceptAllFilter", FileListFilter.class);
assertThat(TestUtils.getPropertyValue(inbound, "fileSource.scanner.filter.fileFilters", Collection.class)
.contains(acceptAllFilter)).isTrue();
}
@Test
public void testNoCachingSessionFactoryByDefault() {
SourcePollingChannelAdapter adapter = applicationContext.getBean("simpleAdapter", SourcePollingChannelAdapter.class);
Object sessionFactory = TestUtils.getPropertyValue(adapter, "source.synchronizer.remoteFileTemplate.sessionFactory");
assertThat(sessionFactory).isInstanceOf(SmbSessionFactory.class);
SmbInboundFileSynchronizer fisync =
TestUtils.getPropertyValue(adapter, "source.synchronizer", SmbInboundFileSynchronizer.class);
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
assertThat(remoteFileSeparator).isNotNull();
assertThat("/").isEqualTo(remoteFileSeparator);
}
@Test(timeout = 10000)
public void testSmbInboundChannelAdapterCompleteNoId() {
Map<String, SourcePollingChannelAdapter> spcas = applicationContext.getBeansOfType(SourcePollingChannelAdapter.class);
SourcePollingChannelAdapter adapter = null;
for (String key : spcas.keySet()) {
if (!key.equals("smbInbound") && !key.equals("simpleAdapter")) {
adapter = spcas.get(key);
}
}
assertThat(adapter).isNotNull();
}
public static class TestSessionFactoryBean implements FactoryBean<SmbSessionFactory> {
public SmbSessionFactory getObject() {
SmbSessionFactory smbFactory = mock(SmbSessionFactory.class);
SmbSession session = mock(SmbSession.class);
when(smbFactory.getSession()).thenReturn(session);
return smbFactory;
}
public Class<?> getObjectType() {
return SmbSessionFactory.class;
}
public boolean isSingleton() {
return true;
}
}
}

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
<bean id="smbSessionFactory"
class="org.springframework.integration.smb.session.SmbSessionFactory"
p:host="localhost"
p:port="0"
p:domain="sambaguest"
p:username="sambaguest"
p:password="sambaguest"
p:shareAndDir="smb-share/"/>
<int-smb:inbound-channel-adapter id="smbInboundChannelAdapter"
channel="smbInboundChannel"
session-factory="smbSessionFactory"
charset="UTF-8"
remote-directory="test-temp/remote-4"
remote-file-separator="/"
filename-regex=".*\.txt$"
delete-remote-files="true"
temporary-file-suffix=".working.tmp"
auto-create-local-directory="true"
local-directory="file:test-temp/local-4">
<int:poller fixed-rate="5000" error-channel="nullChannel"/>
</int-smb:inbound-channel-adapter>
<int:channel id="smbInboundChannel">
<int:queue/>
</int:channel>
</beans>

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2012-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.config;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.smb.AbstractBaseTests;
import org.springframework.integration.smb.inbound.SmbInboundFileSynchronizingMessageSource;
import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.GenericMessage;
/**
* System tests that perform SMB access without any mocking.
* These tests are annotated with '@Ignore', as they requires real SMB share configured
* in the application context/smbClientFactory in order to succeed.
* The test cases create directories and files autonomously and perform clean-up
* on a best effort basis.
*
* @author Markus Spann
* @author Gunnar Hillert
* @author Gregory Bragg
*/
public class SmbInboundOutboundSample extends AbstractBaseTests {
private static final String INBOUND_APPLICATION_CONTEXT_XML = "SmbInboundChannelAdapterSample-context.xml";
private static final String OUTBOUND_APPLICATION_CONTEXT_XML = "SmbOutboundChannelAdapterSample-context.xml";
@Ignore("Actual SMB share must be configured in file [" + INBOUND_APPLICATION_CONTEXT_XML + "].")
@Test
public void testSmbInboundChannelAdapter() throws Exception {
String testLocalDir = "test-temp/local-4/";
String testRemoteDir = "test-temp/remote-4/";
ApplicationContext ac = new ClassPathXmlApplicationContext(INBOUND_APPLICATION_CONTEXT_XML, this.getClass());
Object consumer = ac.getBean("smbInboundChannelAdapter");
assertThat(consumer).isInstanceOf(SourcePollingChannelAdapter.class);
Object messageSource = TestUtils.getPropertyValue(consumer, "source");
assertThat(messageSource).isInstanceOf(SmbInboundFileSynchronizingMessageSource.class);
// retrieve the session factory bean to place a couple of test files remotely using a new session
SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class);
SmbSession smbSession = smbSessionFactory.getSession();
// place text files onto the share
smbSession.mkdir(testRemoteDir);
String[] fileNames = createTestFileNames(5);
for (int i = 0; i < fileNames.length; i++) {
smbSession.write(("File [" + fileNames[i] + "] written by test case [" + getMethodName() + "].").getBytes(),
testRemoteDir + fileNames[i]);
}
// allow time for the files to arrive locally
Thread.sleep(5000);
// confirm the local presence of all test files
for (int i = 0; i < fileNames.length; i++) {
assertFileExists(testLocalDir + fileNames[i]).deleteOnExit();
}
}
@Ignore("Actual SMB share must be configured in file [" + OUTBOUND_APPLICATION_CONTEXT_XML + "].")
@Test
public void testSmbOutboundChannelAdapter() throws Exception {
String testRemoteDir = "test-temp/remote-8/";
String testLocalDir = "test-temp/local-8/";
new File(testLocalDir).mkdirs();
String[] fileNames = createTestFileNames(5);
for (int i = 0; i < fileNames.length; i++) {
writeToFile(("File [" + fileNames[i] + "] written by test case [" + getMethodName() + "].").getBytes(),
testLocalDir + fileNames[i]);
}
ApplicationContext ac = new ClassPathXmlApplicationContext(OUTBOUND_APPLICATION_CONTEXT_XML, this.getClass());
Object consumer = ac.getBean("smbOutboundChannelAdapter");
assertThat(consumer).isInstanceOf(EventDrivenConsumer.class);
Object messageSource = TestUtils.getPropertyValue(consumer, "handler");
assertThat(messageSource).isInstanceOf(FileTransferringMessageHandler.class);
MessageChannel smbChannel = ac.getBean("smbOutboundChannel", MessageChannel.class);
for (int i = 0; i < fileNames.length; i++) {
smbChannel.send(new GenericMessage<File>(new File(testLocalDir + fileNames[i])));
}
Thread.sleep(3000);
// retrieve the session factory bean to check the test files are present in the remote location
SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class);
SmbSession smbSession = smbSessionFactory.getSession();
for (int i = 0; i < fileNames.length; i++) {
String remoteFile = testRemoteDir + fileNames[i];
assertThat(smbSession.exists(remoteFile)).as("Remote file [" + remoteFile + "] does not exist.").isTrue();
}
}
private String[] createTestFileNames(int _nbTestFiles) {
String[] fileNames = new String[_nbTestFiles];
for (int i = 0; i < fileNames.length; i++) {
fileNames[i] = "test-file-" + i + ".txt";
}
return fileNames;
}
public static void main(String[] _args) throws Exception {
runTests(SmbInboundOutboundSample.class, "testSmbOutboundChannelAdapter", "testSmbInboundChannelAdapter");
}
}

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
<property name="host" value="localhost"/>
<property name="port" value="0"/>
<property name="domain" value=""/>
<property name="username" value="sambaguest"/>
<property name="password" value="sambaguest"/>
<property name="shareAndDir" value="smb-share/"/>
</bean>
<int-smb:outbound-channel-adapter id="smbOutboundChannelAdapter"
channel="smbPubSubChannel"
session-factory="smbSessionFactory"
remote-directory="test-temp/remote-5"
charset="UTF-8"
remote-file-separator="."
temporary-file-suffix=".working.tmp"
remote-filename-generator="fileNameGenerator"
order="23"/>
<int-smb:outbound-channel-adapter id="smbOutboundChannelAdapter2"
channel="smbPubSubChannel"
session-factory="smbSessionFactory"
remote-directory="test-temp/remote-6"
charset="UTF-8"
remote-file-separator="."
temporary-file-suffix=".working.tmp"
remote-filename-generator="fileNameGenerator"
order="12"/>
<int-smb:outbound-channel-adapter id="simpleAdapter"
channel="smbPubSubChannel"
session-factory="smbSessionFactory"
remote-directory="test-temp/remote-7"/>
<int:publish-subscribe-channel id="smbPubSubChannel"/>
<bean id="fileNameGenerator" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.file.FileNameGenerator"/>
</bean>
</beans>

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2012-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.config;
import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.smb.AbstractBaseTests;
import org.springframework.integration.smb.session.SmbSessionFactory;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageHandler;
/**
* @author Markus Spann
* @author Gunnar Hillert
* @author Artem Bilan
* @author Prafull Kumar Soni
* @author Gregory Bragg
*/
public class SmbOutboundChannelAdapterParserTests extends AbstractBaseTests {
@Test
public void testSmbOutboundChannelAdapterComplete() {
ApplicationContext ac = getApplicationContext();
Object consumer = ac.getBean("smbOutboundChannelAdapter");
assertThat(consumer).isInstanceOf(EventDrivenConsumer.class);
PublishSubscribeChannel channel = ac.getBean("smbPubSubChannel", PublishSubscribeChannel.class);
assertThat(channel).isEqualTo(TestUtils.getPropertyValue(consumer, "inputChannel"));
assertThat("smbOutboundChannelAdapter").isEqualTo(((EventDrivenConsumer) consumer).getComponentName());
Object messageHandler = TestUtils.getPropertyValue(consumer, "handler");
String remoteFileSeparator = (String) TestUtils.getPropertyValue(messageHandler, "remoteFileTemplate.remoteFileSeparator");
assertThat(remoteFileSeparator).isNotNull();
assertThat(".working.tmp").isEqualTo(TestUtils.getPropertyValue(messageHandler, "remoteFileTemplate.temporaryFileSuffix", String.class));
assertThat(".").isEqualTo(remoteFileSeparator);
assertThat(ac.getBean("fileNameGenerator")).isEqualTo(TestUtils.getPropertyValue(messageHandler, "remoteFileTemplate.fileNameGenerator"));
assertThat("UTF-8").isEqualTo(TestUtils.getPropertyValue(messageHandler, "remoteFileTemplate.charset", Charset.class).name());
Object sessionFactoryProp = TestUtils.getPropertyValue(messageHandler, "remoteFileTemplate.sessionFactory");
assertThat(SmbSessionFactory.class).isEqualTo(sessionFactoryProp.getClass());
SmbSessionFactory smbSessionFactory = (SmbSessionFactory) sessionFactoryProp;
assertThat("localhost").isEqualTo(TestUtils.getPropertyValue(smbSessionFactory, "host"));
assertThat(0).isEqualTo(TestUtils.getPropertyValue(smbSessionFactory, "port"));
assertThat(23).isEqualTo(TestUtils.getPropertyValue(messageHandler, "order"));
// verify subscription order
@SuppressWarnings("unchecked")
Set<MessageHandler> handlers = (Set<MessageHandler>) TestUtils.getPropertyValue(
TestUtils.getPropertyValue(channel, "dispatcher"), "handlers");
Iterator<MessageHandler> iterator = handlers.iterator();
assertThat(TestUtils.getPropertyValue(ac.getBean("smbOutboundChannelAdapter2"), "handler")).isSameAs(iterator.next());
assertThat(messageHandler).isSameAs(iterator.next());
}
@Test
public void noCachingByDefault() {
ApplicationContext ac = new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), this.getClass());
Object adapter = ac.getBean("simpleAdapter");
Object sfProperty = TestUtils.getPropertyValue(adapter, "handler.remoteFileTemplate.sessionFactory");
assertThat(SmbSessionFactory.class).isEqualTo(sfProperty.getClass());
}
}

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
<bean id="smbSessionFactory"
class="org.springframework.integration.smb.session.SmbSessionFactory"
p:host="localhost"
p:port="0"
p:domain="sambaguest"
p:username="sambaguest"
p:password="sambaguest"
p:shareAndDir="smb-share/"/>
<int:channel id="smbOutboundChannel" />
<int-smb:outbound-channel-adapter id="smbOutboundChannelAdapter"
session-factory="smbSessionFactory"
remote-directory="test-temp/remote-8"
channel="smbOutboundChannel"/>
</beans>

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2012-2017 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.inbound;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.integration.smb.AbstractBaseTests;
import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory;
import jcifs.smb.SmbFile;
/**
* @author Markus Spann
* @author Gunnar Hillert
* @since 1.0
*/
public class SmbInboundRemoteFileSystemSynchronizerTests extends AbstractBaseTests {
private SmbSession smbSession;
private SmbSessionFactory smbSessionFactory;
private String testLocalDir = "test-temp/local-9/";
private String testRemoteDir = "test-temp/remote-9/";
@Before
public void prepare() {
delete(testLocalDir);
ensureExists(testRemoteDir);
smbSession = mock(SmbSession.class);
smbSessionFactory = new TestSmbSessionFactory();
smbSessionFactory.setHost("localhost");
smbSessionFactory.setPort(0);
smbSessionFactory.setDomain("");
smbSessionFactory.setUsername("sambaguest");
smbSessionFactory.setPassword("sambaguest");
smbSessionFactory.setShareAndDir("smb-share/");
}
// @Test
// public void testCopyFileToLocalDir() throws Exception {
// File localDirectoy = new File(testLocalDir);
// assertFileNotExists(localDirectoy);
//
// SmbInboundFileSynchronizer synchronizer = spy(new SmbInboundFileSynchronizer(smbSessionFactory));
// synchronizer.setDeleteRemoteFiles(true);
// synchronizer.setRemoteDirectory(testRemoteDir);
// synchronizer.setFilter(new SmbRegexPatternFileListFilter(".*\\.test$"));
//
// SmbInboundFileSynchronizingMessageSource messageSource = new SmbInboundFileSynchronizingMessageSource(synchronizer);
// messageSource.setAutoCreateLocalDirectory(true);
//
// messageSource.setLocalDirectory(localDirectoy);
// messageSource.afterPropertiesSet();
//
// String[] testFiles = new String[] {"a.test", "b.test"};
//
// for (String testFile : testFiles) {
// Message<File> message = messageSource.receive();
// assertNotNull(message);
// assertEquals(testFile, message.getPayload().getName());
// assertFileExists(new File(testLocalDir + "/" + testFile));
// }
//
// Message<File> nothing = messageSource.receive();
// assertNull(nothing);
//
// // two times because on the third receive (above) the internal queue will be empty
// verify(synchronizer, times(2)).synchronizeToLocalDirectory(localDirectoy);
// }
class TestSmbSessionFactory extends SmbSessionFactory {
@Override
protected SmbSession createSession() {
try {
List<SmbFile> smbFiles = new ArrayList<SmbFile>();
for (String fileName : new File(testRemoteDir).list()) {
SmbFile file = smbSession.createSmbFileObject(fileName);
smbFiles.add(file);
doAnswer(new Answer<Object>() {
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.eq(testRemoteDir + "/" + fileName), Mockito.any(OutputStream.class));
}
when(smbSession.list(testRemoteDir)).thenReturn(smbFiles.toArray(new SmbFile[] { }));
when(smbSession.remove(Mockito.anyString())).thenReturn(true);
return smbSession;
}
catch (Exception _ex) {
throw new RuntimeException("Failed to create mock session.", _ex);
}
}
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright 2012-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 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.After;
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.smb.AbstractBaseTests;
import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.util.FileSystemUtils;
import jcifs.smb.SmbFile;
/**
* @author Markus Spann
* @author Artem Bilan
* @author Prafull Kumar Soni
* @author Gregory Bragg
*/
public class SmbSendingMessageHandlerTests extends AbstractBaseTests {
private SmbSession smbSession;
private SmbSessionFactory smbSessionFactory;
@Before
public void prepare() {
smbSession = mock(SmbSession.class);
smbSessionFactory = new TestSmbSessionFactory();
smbSessionFactory.setHost("localhost");
smbSessionFactory.setPort(0);
smbSessionFactory.setDomain("");
smbSessionFactory.setUsername("sambaguest");
smbSessionFactory.setPassword("sambaguest");
smbSessionFactory.setShareAndDir("smb-share/");
}
@After
public void cleanup() {
FileSystemUtils.deleteRecursively(new File("remote-target-dir"));
}
@Test
public void testHandleFileContentMessage() {
File file = createNewFile("remote-target-dir/handlerContent.test");
SmbMessageHandler handler = new SmbMessageHandler(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<>("hello"));
assertFileExists(file);
}
@Test
public void testHandleFileAsByte() {
File file = createNewFile("remote-target-dir/handlerContent.test");
SmbMessageHandler handler = new SmbMessageHandler(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<>("hello".getBytes()));
assertFileExists(file);
}
// @Test
// public void testHandleFileMessage() throws Exception {
// File file = createNewFile("remote-target-dir/template.mf.test");
// SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
// handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
// handler.setFileNameGenerator(new FileNameGenerator() {
// public String generateFileName(Message<?> message) {
// return ((File) message.getPayload()).getName() + ".test";
// }
// });
// handler.afterPropertiesSet();
// handler.handleMessage(new GenericMessage<File>(new File("template.mf")));
// assertFileExists(file);
// }
class TestSmbSessionFactory extends SmbSessionFactory {
@Override
protected SmbSession createSession() {
try {
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((Answer<Object>) _invocation -> {
String path = (String) _invocation.getArguments()[0];
return new File(path).mkdirs();
}).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);
}
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright 2012-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.session;
import static org.assertj.core.api.Assertions.assertThat;
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.After;
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 org.springframework.util.FileSystemUtils;
import jcifs.CIFSContext;
import jcifs.context.SingletonContext;
import jcifs.smb.SmbFile;
/**
* @author Gregory Bragg
* @author Artem Bilan
*/
public class SmbSessionFactoryWithCIFSContextTests extends AbstractBaseTests {
private SmbSession smbSession;
private SmbSessionFactory smbSessionFactory;
@Before
public void prepare() {
smbSession = mock(SmbSession.class);
smbSessionFactory = new TestSmbSessionFactory(SingletonContext.getInstance());
assertThat(smbSessionFactory).as("TestSmbSessionFactory object is null.").isNotNull();
smbSessionFactory.setHost("localhost");
smbSessionFactory.setPort(445);
smbSessionFactory.setDomain("");
smbSessionFactory.setUsername("sambaguest");
smbSessionFactory.setPassword("sambaguest");
smbSessionFactory.setShareAndDir("smb-share/");
}
@After
public void cleanup() {
FileSystemUtils.deleteRecursively(new File("remote-target-dir"));
}
@Test
public void testHandleFileContentMessage() {
File file = createNewFile("remote-target-dir/handlerContent.test");
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<>(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<>("hello"));
assertFileExists(file);
}
class TestSmbSessionFactory extends SmbSessionFactory {
private CIFSContext context;
protected TestSmbSessionFactory(CIFSContext _context) {
assertThat(_context).as("CIFSContext object is null.").isNotNull();
this.context = _context;
}
@Override
protected SmbSession createSession() {
try {
// test for a constructor with a CIFSContext
SmbShare smbShare = new SmbShare(this, this.context);
assertThat(smbShare).as("SmbShare object is null.").isNotNull();
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(_invocation -> {
String path = (String) _invocation.getArguments()[0];
return new File(path).mkdirs();
}).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);
}
}
}
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright 2012-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.session;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.util.Properties;
import org.junit.Test;
import jcifs.DialectVersion;
import jcifs.smb.SmbFile;
/**
*
* @author Gunnar Hillert
* @author Gregory Bragg
*
*/
public class SmbSessionTests {
@Test
public void testCreateSmbFileObjectWithBackSlash1() throws IOException {
System.setProperty("file.separator", "\\");
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\\");
assertThat("smb://myshare/blubba/").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithBackSlash2() throws IOException {
System.setProperty("file.separator", "\\");
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\\");
assertThat("smb://myshare/blubba/").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithBackSlash3() throws IOException {
System.setProperty("file.separator", "\\");
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");
assertThat("smb://myshare:445/another").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithBackSlash4() throws IOException {
System.setProperty("file.separator", "/");
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\\");
assertThat("smb://myshare/blubba/").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
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");
assertThat("smb://myshare/blubba").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
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(".");
assertThat("smb://myshare:445/shared/").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
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");
assertThat("smb://myshare:445/anotherShare").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithSmb3Versions1() throws IOException {
Properties props = new Properties();
SmbConfig config = new SmbConfig();
config.setHost("myshare");
config.setPort(445);
config.setShareAndDir("shared/");
config.setSmbMinVersion(DialectVersion.SMB300);
config.setSmbMaxVersion(DialectVersion.SMB311);
props.setProperty("jcifs.smb.client.minVersion", config.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", config.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(config, props);
SmbSession smbSession = new SmbSession(smbShare);
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
assertThat("smb://myshare/blubba").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithSmb3Versions2() throws IOException {
Properties props = new Properties();
SmbConfig config = new SmbConfig();
config.setHost("myshare");
config.setPort(445);
config.setShareAndDir("shared/");
config.setSmbMinVersion(DialectVersion.SMB302);
config.setSmbMaxVersion(DialectVersion.SMB311);
props.setProperty("jcifs.smb.client.minVersion", config.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", config.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(config, props);
SmbSession smbSession = new SmbSession(smbShare);
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
assertThat("smb://myshare/blubba").isEqualTo(smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithSmb3Versions3() throws IOException {
Properties props = new Properties();
SmbConfig config = new SmbConfig();
config.setHost("myshare");
config.setPort(445);
config.setShareAndDir("shared/");
config.setSmbMinVersion(DialectVersion.SMB311);
config.setSmbMaxVersion(DialectVersion.SMB311);
props.setProperty("jcifs.smb.client.minVersion", config.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", config.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(config, props);
SmbSession smbSession = new SmbSession(smbShare);
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
assertThat("smb://myshare/blubba").isEqualTo(smbFile.getPath());
smbSession.close();
}
}

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file https://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder />
<!--
smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]]
-->
<bean id="smbSession" class="org.springframework.integration.smb.session.SmbSessionFactory">
<property name="host" value="${host}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<property name="shareAndDir" value="${shareAndDir}"/>
</bean>
<int-smb:inbound-channel-adapter local-directory="target/smb-transfer-work"
session-factory="smbSession" remote-directory="."
auto-create-local-directory="true" delete-remote-files="false"
channel="inboundChannel">
<int:poller fixed-rate="10000" max-messages-per-poll="1"/>
</int-smb:inbound-channel-adapter>
<int:channel id="inboundChannel">
<int:interceptors>
<int:wire-tap channel="loggit"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="loggit" level="INFO"
logger-name="org.springframework.integration.samples.smb"
expression="'File Name: ' + payload.name + '(' + payload.length() + ')'"/>
<int-file:outbound-channel-adapter channel="inboundChannel" directory="target/smb-out"/>
</beans>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %p [%t] [%c] - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="org.springframework.integration" level="warn"/>
<Logger name="org.springframework.integration.smb" level="info"/>
<Root level="warn">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>