Merge SMB Adapter

This commit is contained in:
Gunnar Hillert
2012-06-15 21:49:34 -04:00
38 changed files with 3149 additions and 6 deletions

26
.gitignore vendored
View File

@@ -1,6 +1,20 @@
*.class
# Package Files #
*.jar
*.war
*.ear
*.iml
*.ipr
*.iws
*.msg
*/src/main/java/META-INF
.classpath
.DS_Store
.gradle
.idea
.project
.settings
bin
build
build.log
derby.log
lib
logs
nohup.out
out
target

View File

@@ -0,0 +1,8 @@
log4j.rootCategory=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.category.org.springframework=WARN
log4j.category.org.springframework.integration=DEBUG

View File

@@ -0,0 +1,253 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-smb</artifactId>
<version>2.1.1.BUILD-SNAPSHOT</version>
<name>Spring Integration SMB Support</name>
<parent>
<!--
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration</artifactId>
<version>2.1.1.BUILD-SNAPSHOT</version>
-->
<groupId>baag</groupId>
<artifactId>baag-maven-root</artifactId>
<version>1.4-SNAPSHOT</version>
<!-- The relative path of the parent pom.xml file within the check out.
The default value is ../pom.xml which points to spring-integration
parent POM. While we maintain the module locally at Baader,
we must point it to parent baag-maven-root (for Nexus, Jenkins etc.) -->
<relativePath>../../Skripte/Maven/Wurzel/</relativePath>
</parent>
<properties>
<spring.core.version>3.0.5.RELEASE</spring.core.version>
<spring.integration.version>2.1.1.BUILD-SNAPSHOT</spring.integration.version>
</properties>
<issueManagement/>
<scm>
<connection>scm:svn:https://eiche.baag/svn/3rdparty/spring-integration-smb/trunk/</connection>
<developerConnection>scm:svn:https://eiche.baag/svn/3rdparty/spring-integration-smb/trunk/</developerConnection>
<url>https://eiche.baag/svn/3rdparty/spring-integration-smb/trunk/</url>
</scm>
<developers>
<developer>
<id>msp</id>
<name>Markus Spann</name>
<email>markus.spann@baaderbank.de</email>
<timezone>+1</timezone>
</developer>
</developers>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/java</directory>
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
<testResource>
<directory>src/test/resources</directory>
<includes>
<include>**/*</include>
</includes>
</testResource>
</testResources>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<forkMode>never</forkMode>
<includes>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*Abstract*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<!-- http://maven.apache.org/plugins/maven-eclipse-plugin/ -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<additionalBuildcommands combine.children="append">
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<additionalProjectnatures combine.children="append">
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
</configuration>
</plugin>
<plugin>
<!-- http://code.google.com/p/maven-license-plugin/ -->
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<version>1.10.b1</version>
<configuration>
<basedir>${basedir}</basedir> <!-- base directory for the search -->
<header>${basedir}/src/main/resources/license_header.txt</header>
<aggregate>true</aggregate> <!-- check headers for all modules of multi-modules projects. -->
<includes>
<include>src/**/*.java</include>
</includes>
<useDefaultExcludes>true</useDefaultExcludes>
<properties>
<year>${project.inceptionYear}</year>
</properties>
<encoding>UTF-8</encoding>
<strictCheck>true</strictCheck>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.samba.jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.core.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.core.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.core.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.core.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.core.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${spring.integration.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
<version>${spring.integration.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-test</artifactId>
<version>${spring.integration.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- Hamcrest - library of matchers for building test expressions -->
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,51 @@
/**
* Copyright 2002-2012 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
*
* http://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;
/**
* Parser for the SMB 'inbound-channel-adapter' element.
*
* @author Markus Spann
* @since 2.1.1
*/
public class SmbInboundChannelAdapterParser extends AbstractRemoteFileInboundChannelAdapterParser {
private static final String BASE_PACKAGE = "org.springframework.integration.smb";
@Override
protected String getMessageSourceClassname() {
return BASE_PACKAGE + ".inbound.SmbInboundFileSynchronizingMessageSource";
}
@Override
protected String getInboundFileSynchronizerClassname() {
return BASE_PACKAGE + ".inbound.SmbInboundFileSynchronizer";
}
@Override
protected String getSimplePatternFileListFilterClassname() {
return BASE_PACKAGE + ".filters.SmbSimplePatternFileListFilter";
}
@Override
protected String getRegexPatternFileListFilterClassname() {
return BASE_PACKAGE + ".filters.SmbRegexPatternFileListFilter";
}
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright 2002-2012 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
*
* http://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;
import org.springframework.integration.file.config.RemoteFileOutboundChannelAdapterParser;
/**
* Provides namespace support for using SMB.
*
* @author Markus Spann
* @since 2.1.1
*/
public class SmbNamespaceHandler extends AbstractIntegrationNamespaceHandler {
public void init() {
registerBeanDefinitionParser("inbound-channel-adapter", new SmbInboundChannelAdapterParser());
registerBeanDefinitionParser("outbound-channel-adapter", new RemoteFileOutboundChannelAdapterParser()); // TODO need implementation for SMB?
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright 2002-2012 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
*
* http://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.regex.Pattern;
import jcifs.smb.SmbFile;
import org.springframework.integration.file.filters.AbstractRegexPatternFileListFilter;
/**
* Implementation of {@link AbstractRegexPatternFileListFilter} for SMB.
*
* @author Markus Spann
* @since 2.1.1
*/
public class SmbRegexPatternFileListFilter extends AbstractRegexPatternFileListFilter<SmbFile> {
private final String toString;
public SmbRegexPatternFileListFilter(String _pattern) {
this(Pattern.compile(_pattern));
}
public SmbRegexPatternFileListFilter(Pattern _pattern) {
super(_pattern);
toString = getClass().getName() + "[pattern='" + _pattern + "']";
}
/**
* Gets the specified SMB file's name.
* @param _file SMB file object
* @return file name
* @see org.springframework.integration.file.filters.AbstractRegexPatternFileListFilter#getFilename(java.lang.Object)
*/
@Override
protected String getFilename(SmbFile _file) {
return (_file != null) ? _file.getName() : null;
}
@Override
public String toString() {
return toString;
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright 2002-2012 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
*
* http://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 jcifs.smb.SmbFile;
import org.springframework.integration.file.filters.AbstractSimplePatternFileListFilter;
/**
* Implementation of {@link AbstractSimplePatternFileListFilter} for SMB.
*
* @author Markus Spann
*/
public class SmbSimplePatternFileListFilter extends AbstractSimplePatternFileListFilter<SmbFile> {
private final String toString;
public SmbSimplePatternFileListFilter(String _pathPattern) {
super(_pathPattern);
toString = getClass().getName() + "[pattern='" + _pathPattern + "']";
}
/**
* Gets the specified SMB file's name.
* @param _file SMB file object
* @return file name
* @see org.springframework.integration.file.filters.AbstractSimplePatternFileListFilter#getFilename(java.lang.Object)
*/
@Override
protected String getFilename(SmbFile _file) {
return (_file != null) ? _file.getName() : null;
}
@Override
public String toString() {
return toString;
}
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright 2002-2012 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
*
* http://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 jcifs.smb.SmbFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer;
/**
* An implementation of {@link AbstractInboundFileSynchronizer} for SMB.
*
* @author Markus Spann
* @since 2.1.1
*/
public class SmbInboundFileSynchronizer extends AbstractInboundFileSynchronizer<SmbFile> {
private final Log logger = LogFactory.getLog(SmbInboundFileSynchronizer.class);
private final String toString;
/**
* Create a synchronizer with the {@link SessionFactory} used to acquire
* {@link org.springframework.integration.file.remote.session.Session} instances.
*/
public SmbInboundFileSynchronizer(SessionFactory<SmbFile> _sessionFactory) {
super(_sessionFactory);
toString = getClass().getName() + "[sessionFactory=" + _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
public String toString() {
return toString;
}
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright 2002-2012 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
*
* http://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 jcifs.smb.SmbFile;
import org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer;
import org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource;
/**
* A {@link org.springframework.integration.core.MessageSource} implementation for SMB.
*
* @author Markus Spann
* @since 2.1.1
*/
public class SmbInboundFileSynchronizingMessageSource extends AbstractInboundFileSynchronizingMessageSource<SmbFile> {
// CHECKSTYLE:OFF
private final static String componentType = "smb:inbound-channel-adapter";
// CHECKSTYLE:ON
private final String toString;
public SmbInboundFileSynchronizingMessageSource(AbstractInboundFileSynchronizer<SmbFile> _synchronizer) {
this(_synchronizer, null);
}
public SmbInboundFileSynchronizingMessageSource(AbstractInboundFileSynchronizer<SmbFile> _synchronizer, Comparator<File> _comparator) {
super(_synchronizer, _comparator);
toString = getClass().getName() + "[componentType=" + componentType + ", synchronizer=" + _synchronizer + ", comparator=" + _comparator + "]";
}
@Override
public String getComponentType() {
return componentType;
}
@Override
public String toString() {
return toString;
}
}

View File

@@ -0,0 +1,183 @@
/**
* Copyright 2002-2012 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
*
* http://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.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* 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
* @since 2.1.1
*/
public class SmbConfig {
private String host;
private int port;
private String domain;
private String username;
private String password;
private String shareAndDir;
private boolean replaceFile = false;
private boolean useTempFile = false;
public SmbConfig() {
}
public SmbConfig(String _host, int _port, String _domain, String _username, String _password, String _shareAndDir) throws UnsupportedEncodingException {
this();
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 host;
}
public void setPort(int _port) {
Assert.isTrue(_port >= 0, "port must be >= 0");
this.port = _port;
}
public int getPort() {
return port;
}
public void setDomain(String _domain) {
Assert.notNull(_domain);
this.domain = _domain;
}
public String getDomain() {
return domain;
}
public void setUsername(String _username) {
Assert.hasText(_username, "username should be a non-empty string");
this.username = _username;
}
public String getUsername() {
return username;
}
public void setPassword(String _password) {
Assert.notNull(_password, "password should not be null");
this.password = _password;
}
public String getPassword() {
return password;
}
public void setShareAndDir(String _shareAndDir) {
Assert.notNull(_shareAndDir, "shareAndDir should not be null");
this.shareAndDir = _shareAndDir;
}
public String getShareAndDir() {
return shareAndDir;
}
public void setReplaceFile(boolean _replaceFile) {
this.replaceFile = _replaceFile;
}
public boolean isReplaceFile() {
return replaceFile;
}
void setUseTempFile(boolean _useTempFile) {
this.useTempFile = _useTempFile;
}
public boolean isUseTempFile() {
return useTempFile;
}
String getDomainUserPass(boolean _includePassword) {
String domainUserPass;
String user = _includePassword ? this.username : "********";
if (StringUtils.hasText(this.domain)) {
domainUserPass = String.format("%s;%s", this.domain, user);
} else {
domainUserPass = user;
}
if (StringUtils.hasText(this.password)) {
domainUserPass += ":" + 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);
if (domainUserPass != null) {
try {
domainUserPass = URLEncoder.encode(domainUserPass, "UTF8");
// CHECKSTYLE:OFF
} catch (UnsupportedEncodingException _ex) {
// CHECKSTYLE:ON
}
}
return String.format("smb://%s@%s/%s", domainUserPass, getHostPort(), StringUtils.cleanPath(this.shareAndDir));
}
@Override
public String toString() {
return getClass().getSimpleName()
+ "[url=" + getUrl(false)
+ ", replaceFile=" + replaceFile
+ "]";
}
}

View File

@@ -0,0 +1,448 @@
/**
* Copyright 2002-2012 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
*
* http://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.util.Arrays;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.NestedIOException;
import org.springframework.integration.file.remote.session.Session;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
/**
* 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="http://en.wikipedia.org/wiki/Server_Message_Block">Server Message Block</a>
* for more details.
*
* Inspired by the sprint-integration-ftp implementation done by Mark Fisher and Oleg Zhurakousky.
*
* @author Markus Spann
* @author Mark Fisher
* @author Oleg Zhurakousky
*
* @since 2.1.1
*/
public class SmbSession implements Session<SmbFile> {
private final Log logger = LogFactory.getLog(SmbSession.class);
private static final String FILE_SEPARATOR = System.getProperty("file.separator");
static {
configureJcifs();
}
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 user name
* @param _password case-sensitive password
* @param _shareAndDir server root SMB directory
* @param _replaceFile replace existing files if true
* @param _useTempFile make use temporary files when writing
* @throws IOException in case of I/O errors
*/
SmbSession(String _host, int _port, String _domain, String _user, String _password, String _shareAndDir, boolean _replaceFile, boolean _useTempFile) throws IOException {
this(new SmbShare(new SmbConfig(_host, _port, _domain, _user, _password, _shareAndDir)));
smbShare.setReplaceFile(_replaceFile);
smbShare.setUseTempFile(_useTempFile);
}
/**
* Constructor for an SMB session.
* @param _smbShare SMB share resource
*/
public SmbSession(SmbShare _smbShare) {
Assert.notNull(_smbShare, "smbShare must not be null");
smbShare = _smbShare;
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
* @see org.springframework.integration.file.remote.session.Session#remove(java.lang.String)
*/
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.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.
* @see org.springframework.integration.file.remote.session.Session#list(java.lang.String)
*/
public SmbFile[] list(String _path) throws IOException {
SmbFile[] files = new SmbFile[0];
try {
SmbFile smbDir = createSmbDirectoryObject(_path);
if (!smbDir.exists()) {
logger.warn("Remote directory [" + _path + "] does not exist. Cannot list resources.");
return files;
} else if (!smbDir.isDirectory()) {
throw new NestedIOException("Resource [" + _path + "] is not a directory. Cannot list resources.");
}
files = smbDir.listFiles();
} catch (SmbException _ex) {
throw new NestedIOException("Failed to list resources in [" + _path + "].", _ex);
}
String msg = "Successfully listed " + files.length + " resource(s) in [" + _path + "]";
if (logger.isDebugEnabled()) {
logger.debug(msg + ": " + Arrays.toString(files));
} else {
logger.info(msg + ".");
}
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.
* @see org.springframework.integration.file.remote.session.Session#read(java.lang.String, java.io.OutputStream)
*/
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 NestedIOException("Resource [" + _path + "] is not a file.");
}
FileCopyUtils.copy(remoteFile.getInputStream(), _outputStream);
} catch (SmbException _ex) {
throw new NestedIOException("Failed to read resource [" + _path + "].", _ex);
}
logger.info("Successfully read resource [" + _path + "].");
}
/**
* Writes contents of the specified {@link InputStream} to the remote resource
* specified by path. Remote directories are created implicitely 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
* @see org.springframework.integration.file.remote.session.Session#write(java.io.InputStream, java.lang.String)
*/
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);
if (smbShare.isUseTempFile()) {
String tempFileName = _path + smbShare.newTempFileSuffix();
SmbFile tempFile = createSmbFileObject(tempFileName);
tempFile.createNewFile();
Assert.isTrue(tempFile.canWrite(), "Temporary file [" + tempFileName + "] is not writable.");
FileCopyUtils.copy(_inputStream, tempFile.getOutputStream());
if (targetFile.exists() && smbShare.isReplaceFile()) {
targetFile.delete();
}
tempFile.renameTo(targetFile);
} else {
FileCopyUtils.copy(_inputStream, targetFile.getOutputStream());
}
} catch (SmbException _ex) {
throw new NestedIOException("Failed to write resource [" + _path + "].", _ex);
}
logger.info("Successfully wrote remote file [" + _path + "].");
}
/**
* Convenience method to write a local file object to a remote location.
* @see org.springframework.integration.smb.session.SmbSession.write(InputStream, String)
*/
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.
* @see org.springframework.integration.smb.session.SmbSession.write(InputStream, String)
*/
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
* @see org.springframework.integration.file.remote.session.Session#mkdir(java.lang.String)
*/
public boolean mkdir(String _path) throws IOException {
try {
SmbFile dir = createSmbDirectoryObject(_path);
if (!dir.exists()) {
dir.mkdirs();
logger.info("Successfully created remote directory [" + _path + "] in share [" + smbShare + "].");
} else {
logger.info("Remote directory [" + _path + "] exists in share [" + smbShare + "].");
}
return true;
} catch (SmbException _ex) {
throw new NestedIOException("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
* @see org.springframework.integration.file.remote.session.Session#exists(java.lang.String)
*/
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;
}
/**
* Renames a remote resource.
* @param _pathFrom remote source path
* @param _pathTo remote target path
* @throws IOException on error conditions returned by a CIFS server
* @see org.springframework.integration.file.remote.session.Session#rename(java.lang.String, java.lang.String)
*/
public void rename(String _pathFrom, String _pathTo) throws IOException {
try {
SmbFile smbFileFrom = createSmbFileObject(_pathFrom);
SmbFile smbFileTo = createSmbFileObject(_pathTo);
if (smbShare.isReplaceFile() && smbFileTo.exists()) {
smbFileTo.delete();
}
smbFileFrom.renameTo(smbFileTo);
} catch (SmbException _ex) {
throw new NestedIOException("Failed to rename [" + _pathFrom + "] to [" + _pathTo + "].", _ex);
}
logger.info("Successfully renamed remote resource [" + _pathFrom + "] to [" + _pathTo + "].");
}
/**
* Closes this SMB session.
* @see org.springframework.integration.file.remote.session.Session#close()
*/
public void close() {
smbShare.doClose();
}
/**
* 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
* @see org.springframework.integration.file.remote.session.Session#isOpen()
*/
public boolean isOpen() {
if (!smbShare.isOpened()) {
return false;
}
try {
smbShare.listFiles();
} catch (Exception _ex) {
close();
}
return 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 {
String path = StringUtils.cleanPath(_path);
if (!StringUtils.hasText(path)) {
return smbShare;
}
SmbFile smbFile = new SmbFile(smbShare, path);
boolean appendFileSeparator = !path.endsWith(FILE_SEPARATOR);
if (appendFileSeparator) {
try {
appendFileSeparator = smbFile.isDirectory() || (_isDirectory != null && _isDirectory);
} catch (Exception _ex) {
appendFileSeparator = false;
}
}
if (appendFileSeparator) {
smbFile = createSmbFileObject(path + 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.
*/
public SmbFile createSmbFileObject(String _path) throws IOException {
return createSmbFileObject(_path, null);
}
/**
* Creates an SMB file object pointing to a remote directory.
*/
public SmbFile createSmbDirectoryObject(String _path) throws IOException {
return createSmbFileObject(_path, true);
}
/**
* Static configuration of the JCIFS library.
* The log level of this class is mapped to a suitable <code>jcifs.util.loglevel</code>
*/
static void configureJcifs() {
// TODO jcifs.Config.setProperty("jcifs.smb.client.useExtendedSecurity", "false");
// TODO jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", "false");
// set JCIFS SMB client library' log level unless already configured by system property
final String sysPropLogLevel = "jcifs.util.loglevel";
if (jcifs.Config.getProperty(sysPropLogLevel) == null) {
// set log level according to this class' logger's log level.
Log log = LogFactory.getLog(SmbSession.class);
if (log.isTraceEnabled()) {
jcifs.Config.setProperty(sysPropLogLevel, "N");
} else if (log.isDebugEnabled()) {
jcifs.Config.setProperty(sysPropLogLevel, "3");
} else {
jcifs.Config.setProperty(sysPropLogLevel, "1");
}
}
}
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright 2002-2012 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
*
* http://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 jcifs.smb.SmbFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
/**
* The SMB session factory.
*
* @author Markus Spann
* @since 2.1.1
*/
public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFile> {
private final Log logger = LogFactory.getLog(this.getClass());
public SmbSessionFactory() {
logger.debug("New " + getClass().getName() + " created.");
}
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 = new SmbShare((SmbConfig) this);
smbShare.setReplaceFile(this.isReplaceFile());
smbShare.setUseTempFile(this.isUseTempFile());
logger.info(String.format("SMB share init: %s/%s", getHostPort(), getShareAndDir()));
smbShare.init();
logger.debug("SMB share initialized.");
return new SmbSession(smbShare);
}
@Override
public String toString() {
return super.toString();
}
}

View File

@@ -0,0 +1,104 @@
/**
* Copyright 2002-2012 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
*
* http://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.concurrent.atomic.AtomicBoolean;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.NestedIOException;
import org.springframework.util.Assert;
public class SmbShare extends SmbFile {
private final Log logger = LogFactory.getLog(SmbShare.class);
private final AtomicBoolean open = new AtomicBoolean(false);
private final AtomicBoolean replaceFile = new AtomicBoolean(false);
private final AtomicBoolean useTempFile = new AtomicBoolean(false);
public SmbShare(String _url) throws IOException {
super(_url);
}
public SmbShare(SmbConfig _smbConfig) throws IOException {
this(_smbConfig.validate().getUrl());
}
public void init() throws NestedIOException {
boolean canRead = false;
try {
if (!exists()) {
logger.info("SMB root directory does not exist. Creating it.");
mkdirs();
}
canRead = canRead();
} catch (SmbException _ex) {
throw new NestedIOException("Unable to initialize share: " + this, _ex);
}
Assert.isTrue(canRead, "Share is not accessible " + this);
open.set(true);
}
public boolean isReplaceFile() {
return replaceFile.get();
}
public void setReplaceFile(boolean _replace) {
this.replaceFile.set(_replace);
}
public boolean isUseTempFile() {
return useTempFile.get();
}
public void setUseTempFile(boolean _useTempFile) {
this.useTempFile.set(_useTempFile);
}
/**
* Checks whether the share is accessible.
* Note: jcifs.smb.SmbFile defines a package-protected method isOpen().
* @return true if open
*/
boolean isOpened() {
return open.get();
}
/**
* Set the open state to closed.
* Note: jcifs.smb.SmbFile defines a package-protected method close().
*/
void doClose() {
open.set(false);
}
public String newTempFileSuffix() {
return "-" + Long.toHexString(Double.doubleToLongBits(Math.random())) + ".tmp";
}
@Override
public String toString() {
return super.toString();
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright 2002-2012 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
*
* http://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.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public abstract class SmbUtils {
private SmbUtils() {
}
/**
* Read the specified file into a byte array.
* @param _file file
* @return byte array of file contents
* @throws IOException
*/
public static byte[] readFile(File _file) throws IOException {
FileInputStream stream = new FileInputStream(_file);
try {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
return bb.array();
/* Instead of using default, pass in a decoder. */
// return Charset.defaultCharset().decode(bb).toString();
} finally {
stream.close();
}
}
}

View File

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

View File

@@ -0,0 +1,2 @@
http\://www.springframework.org/schema/integration/smb/spring-integration-smb-2.0.xsd=org/springframework/integration/smb/config/spring-integration-smb-2.0.xsd
http\://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd=org/springframework/integration/smb/config/spring-integration-smb-2.0.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

View File

@@ -0,0 +1,13 @@
Copyright 2002-2012 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
http://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.

View File

@@ -0,0 +1,244 @@
<?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:beans="http://www.springframework.org/schema/beans"
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="http://www.springframework.org/schema/integration/spring-integration-2.0.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 implemenation 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: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
[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-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="id" type="xsd:string"/>
<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="cache-sessions" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specify whether the Sessions should be cached. Default is true.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="channel" use="optional" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
Identifies channel attached to this adapter. Depending on the type of the adapter
this channel could be the receiving channel (e.g., outbound-channel-adapter) or channel where
messages will be sent to by this adapter (e.g., inbound-channel-adapter).
</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:complexType>
</xsd:schema>

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

View File

@@ -0,0 +1,283 @@
/**
* Copyright 2002-2012 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
*
* http://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 junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
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
*/
public abstract class AbstractBaseTest {
/** Instance logger. */
private final Log logger = LogFactory.getLog(this.getClass());
protected final Log getLogger() {
return logger;
}
// CHECKSTYLE:OFF
@Rule // requires JUnit 4.7 or later
public final TestName testMethodName = new TestName();
// CHECKSTYLE:ON
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) {
assertNotNull("File object is null.", _file);
if (_exists) {
assertTrue("File [" + _file.getAbsolutePath() + "] does not exist.", _file.exists());
} else {
assertTrue("File [" + _file.getAbsolutePath() + "] exists.", !_file.exists());
}
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
*/
protected static void runTests(Class<? extends AbstractBaseTest> _testClass, String... _methodNames) {
AbstractBaseTest test;
Method[] methods = new Method[_methodNames.length];
String methodName = null;
try {
test = _testClass.newInstance();
for (int i = 0; i < _methodNames.length; i++) {
methodName = _methodNames[i];
methods[i] = _testClass.getMethod(methodName, (Class<?>[]) null);
}
} catch (Exception _ex) {
System.err.println("Test setup failed for " + _testClass + "." + methodName + "().");
_ex.printStackTrace();
return;
}
Method method = null;
try {
for (int i = 0; i < methods.length; i++) {
method = methods[i];
method.invoke(test, (Object[]) null);
}
} catch (Exception _ex) {
System.err.println("Test execution failed for " + _testClass + "." + method.getName() + ".");
_ex.printStackTrace();
}
}
}

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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/smb http://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="sambaguest"/>
<property name="password" value="sambaguest"/>
<property name="shareAndDir" value="smb-share/"/>
<property name="replaceFile" value="true"/>
</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,34 @@
/**
* Copyright 2002-2012 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
*
* http://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 junit.framework.Assert.assertEquals;
import org.junit.Test;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
/**
* @author Markus Spann
*
*/
public class SmbMessageHistoryTests extends AbstractBaseTest {
@Test
public void testMessageHistory() throws Exception {
SourcePollingChannelAdapter adapter = getApplicationContext().getBean("smbInboundChannelAdapter", SourcePollingChannelAdapter.class);
assertEquals("smbInboundChannelAdapter", adapter.getComponentName());
assertEquals("smb:inbound-channel-adapter", adapter.getComponentType());
}
}

View File

@@ -0,0 +1,54 @@
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb http://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"
cache-sessions="false"
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"
cache-sessions="false"
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,40 @@
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb http://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd
http://www.springframework.org/schema/context http://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,62 @@
/**
* Copyright 2002-2012 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
*
* http://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
*
*/
public class SmbParserInboundTests extends AbstractBaseTest {
@Before
public void prepare() {
ensureExists("test-temp/remote-10");
cleanUp();
}
@Test
public void testLocalFilesAutoCreationTrue() throws Exception {
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() throws Exception {
assertFileNotExists(new File("test-temp/local-6"));
new ClassPathXmlApplicationContext(getApplicationContextXmlFile("-fail"), this.getClass());
}
@After
public void cleanUp() {
delete("test-temp/local-10", "test-temp/local-6");
}
public static void main(String[] _args) {
new SmbParserInboundTests().cleanUp();
runTests(SmbParserInboundTests.class, "testLocalFilesAutoCreationTrue", "testLocalFilesAutoCreationFalse");
}
}

View File

@@ -0,0 +1,66 @@
<?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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb
http://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd
">
<bean id="smbSessionFactory"
class="org.springframework.integration.smb.config.SmbInboundChannelAdapterParserTests.TestSessionFactoryBean"/>
<int-smb:inbound-channel-adapter id="smbInbound"
channel="smbChannel"
session-factory="smbSessionFactory"
cache-sessions="false"
charset="UTF-8"
auto-create-local-directory="true"
delete-remote-files="true"
filename-pattern="*.txt"
local-directory="file:test-temp/local-1"
remote-file-separator=""
comparator="comparator"
temporary-file-suffix=".working.tmp"
remote-directory="test-temp/remote-1">
<int:poller fixed-rate="1000"/>
</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"
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:poller fixed-rate="1000"/>
</int-smb:inbound-channel-adapter>
<int-smb:inbound-channel-adapter id="simpleAdapter"
channel="smbChannel"
session-factory="smbSessionFactory"
local-directory="file:test-temp/local-3"
remote-directory="test-temp/remote-3">
<int:poller fixed-rate="1000"/>
</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>
</beans>

View File

@@ -0,0 +1,120 @@
/**
* Copyright 2002-2012 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
*
* http://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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.util.Comparator;
import java.util.Map;
import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.smb.AbstractBaseTest;
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;
/**
* @author Markus Spann
*/
public class SmbInboundChannelAdapterParserTests extends AbstractBaseTest {
@SuppressWarnings("unchecked")
@Test(timeout = 10000)
public void testSmbInboundChannelAdapterComplete() throws Exception{
ApplicationContext ac =
new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), this.getClass());
SourcePollingChannelAdapter adapter = ac.getBean("smbInbound", SourcePollingChannelAdapter.class);
Comparator<File> comparator = TestUtils.getPropertyValue(adapter, "source.fileSource.toBeReceived.q.comparator", Comparator.class);
assertNotNull(comparator);
assertEquals("smbInbound", adapter.getComponentName());
assertEquals("smb:inbound-channel-adapter", adapter.getComponentType());
assertNotNull(TestUtils.getPropertyValue(adapter, "poller"));
assertEquals(ac.getBean("smbChannel"), TestUtils.getPropertyValue(adapter, "outputChannel"));
SmbInboundFileSynchronizingMessageSource inbound =
(SmbInboundFileSynchronizingMessageSource) TestUtils.getPropertyValue(adapter, "source");
SmbInboundFileSynchronizer fisync =
(SmbInboundFileSynchronizer) TestUtils.getPropertyValue(inbound, "synchronizer");
assertEquals(".working.tmp", TestUtils.getPropertyValue(fisync, "temporaryFileSuffix", String.class));
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals("", remoteFileSeparator);
SmbSimplePatternFileListFilter filter = (SmbSimplePatternFileListFilter) TestUtils.getPropertyValue(fisync, "filter");
assertNotNull(filter);
Object sessionFactory = TestUtils.getPropertyValue(fisync, "sessionFactory");
assertTrue(SmbSessionFactory.class.isAssignableFrom(sessionFactory.getClass()));
}
@Test(timeout = 10000)
public void cachingSessionFactoryByDefault() throws Exception{
ApplicationContext ac = new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), this.getClass());
SourcePollingChannelAdapter adapter = ac.getBean("simpleAdapter", SourcePollingChannelAdapter.class);
Object sessionFactory = TestUtils.getPropertyValue(adapter, "source.synchronizer.sessionFactory");
assertEquals(CachingSessionFactory.class, sessionFactory.getClass());
SmbInboundFileSynchronizer fisync =
TestUtils.getPropertyValue(adapter, "source.synchronizer", SmbInboundFileSynchronizer.class);
String remoteFileSeparator = (String) TestUtils.getPropertyValue(fisync, "remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals("/", remoteFileSeparator);
}
@Test(timeout = 10000)
public void testSmbInboundChannelAdapterCompleteNoId() throws Exception{
ApplicationContext ac =
new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), this.getClass());
Map<String, SourcePollingChannelAdapter> spcas = ac.getBeansOfType(SourcePollingChannelAdapter.class);
SourcePollingChannelAdapter adapter = null;
for (String key : spcas.keySet()) {
if (!key.equals("smbInbound") && !key.equals("simpleAdapter")){
adapter = spcas.get(key);
}
}
assertNotNull(adapter);
}
public static class TestSessionFactoryBean implements FactoryBean<SmbSessionFactory> {
public SmbSessionFactory getObject() throws Exception {
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,44 @@
<?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 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb http://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/"
p:replaceFile="false"
/>
<int-smb:inbound-channel-adapter id="smbInboundChannelAdapter"
channel="smbInboundChannel"
session-factory="smbSessionFactory"
cache-sessions="true"
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,137 @@
/**
* Copyright 2002-2012 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
*
* http://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 junit.framework.Assert.assertTrue;
import java.io.File;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.smb.AbstractBaseTest;
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;
/**
* 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
*/
public class SmbInboundOutboundSample extends AbstractBaseTest {
private static final String INBOUND_APPLICATION_CONTEXT_XML = "SmbInboundChannelAdapterSample-context.xml";
private static final String OUTBOUND_APPLICATION_CONTEXT_XML = "SmbOutboundChannelAdapterSample-context.xml";
@org.junit.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");
assertTrue(consumer instanceof SourcePollingChannelAdapter);
Object messageSource = TestUtils.getPropertyValue(consumer, "source");
assertTrue(messageSource instanceof SmbInboundFileSynchronizingMessageSource);
// retrieve the session factory bean to place a couple of test files remotely using a new session
SmbSessionFactory smbSessionFactory = ac.getBean("smbSessionFactory", SmbSessionFactory.class);
smbSessionFactory.setReplaceFile(true);
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();
}
}
@org.junit.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");
assertTrue(consumer instanceof EventDrivenConsumer);
Object messageSource = TestUtils.getPropertyValue(consumer, "handler");
assertTrue(messageSource instanceof FileTransferringMessageHandler);
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);
smbSessionFactory.setReplaceFile(false);
SmbSession smbSession = smbSessionFactory.getSession();
for (int i = 0; i < fileNames.length; i++) {
String remoteFile = testRemoteDir + fileNames[i];
assertTrue("Remote file [" + remoteFile + "] does not exist.", smbSession.exists(remoteFile));
}
}
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) {
runTests(SmbInboundOutboundSample.class, "testSmbOutboundChannelAdapter", "testSmbInboundChannelAdapter");
}
}

View File

@@ -0,0 +1,52 @@
<?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 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb http://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/"/>
<property name="replaceFile" value="false"/>
</bean>
<int-smb:outbound-channel-adapter id="smbOutboundChannelAdapter"
channel="smbPubSubChannel"
session-factory="smbSessionFactory"
cache-sessions="false"
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 2002-2012 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
*
* http://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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertSame;
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.core.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.smb.AbstractBaseTest;
import org.springframework.integration.smb.session.SmbSessionFactory;
import org.springframework.integration.test.util.TestUtils;
/**
* @author Markus Spann
* @since 2.1.1
*/
public class SmbOutboundChannelAdapterParserTests extends AbstractBaseTest {
@Test
public void testSmbOutboundChannelAdapterComplete() throws Exception {
ApplicationContext ac = getApplicationContext();
Object consumer = ac.getBean("smbOutboundChannelAdapter");
assertTrue(consumer instanceof EventDrivenConsumer);
PublishSubscribeChannel channel = ac.getBean("smbPubSubChannel", PublishSubscribeChannel.class);
assertEquals(channel, TestUtils.getPropertyValue(consumer, "inputChannel"));
assertEquals("smbOutboundChannelAdapter", ((EventDrivenConsumer) consumer).getComponentName());
Object messageHandler = TestUtils.getPropertyValue(consumer, "handler");
String remoteFileSeparator = (String) TestUtils.getPropertyValue(messageHandler, "remoteFileSeparator");
assertNotNull(remoteFileSeparator);
assertEquals(".working.tmp", TestUtils.getPropertyValue(messageHandler, "temporaryFileSuffix", String.class));
assertEquals(".", remoteFileSeparator);
assertEquals(ac.getBean("fileNameGenerator"), TestUtils.getPropertyValue(messageHandler, "fileNameGenerator"));
assertEquals("UTF-8", TestUtils.getPropertyValue(messageHandler, "charset"));
assertNotNull(TestUtils.getPropertyValue(messageHandler, "temporaryDirectory"));
Object sessionFactoryProp = TestUtils.getPropertyValue(messageHandler, "sessionFactory");
assertEquals(SmbSessionFactory.class, sessionFactoryProp.getClass());
SmbSessionFactory smbSessionFactory = (SmbSessionFactory) sessionFactoryProp;
assertEquals("localhost", TestUtils.getPropertyValue(smbSessionFactory, "host"));
assertEquals(0, TestUtils.getPropertyValue(smbSessionFactory, "port"));
assertEquals(23, 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();
assertSame(TestUtils.getPropertyValue(ac.getBean("smbOutboundChannelAdapter2"), "handler"), iterator.next());
assertSame(messageHandler, iterator.next());
}
@Test
public void cachingByDefault() {
ApplicationContext ac = new ClassPathXmlApplicationContext(getApplicationContextXmlFile(), this.getClass());
Object adapter = ac.getBean("simpleAdapter");
Object sfProperty = TestUtils.getPropertyValue(adapter, "handler.sessionFactory");
assertEquals(CachingSessionFactory.class, sfProperty.getClass());
Object innerSfProperty = TestUtils.getPropertyValue(sfProperty, "sessionFactory");
assertEquals(SmbSessionFactory.class, innerSfProperty.getClass());
}
}

View File

@@ -0,0 +1,28 @@
<?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 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/smb http://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/"
p:replaceFile="false"
/>
<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,134 @@
/**
* Copyright 2002-2012 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
*
* http://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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import jcifs.smb.SmbFile;
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.integration.Message;
import org.springframework.integration.smb.AbstractBaseTest;
import org.springframework.integration.smb.filters.SmbRegexPatternFileListFilter;
import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory;
/**
* @author Markus Spann
* @since 2.1.1
*/
public class SmbInboundRemoteFileSystemSynchronizerTest extends AbstractBaseTest {
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/");
smbSessionFactory.setReplaceFile(true);
}
@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,167 @@
/**
* Copyright 2002-2012 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
*
* http://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 jcifs.smb.SmbFile;
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.expression.common.LiteralExpression;
import org.springframework.integration.Message;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.handler.FileTransferringMessageHandler;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.smb.AbstractBaseTest;
import org.springframework.integration.smb.session.SmbSession;
import org.springframework.integration.smb.session.SmbSessionFactory;
/**
* @author Markus Spann
*/
public class SmbSendingMessageHandlerTest extends AbstractBaseTest {
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/");
smbSessionFactory.setReplaceFile(true);
}
@Test
public void testHandleFileContentMessage() throws Exception {
File file = createNewFile("remote-target-dir/handlerContent.test");
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(smbSessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(new FileNameGenerator() {
public String generateFileName(Message<?> message) {
return "handlerContent.test";
}
});
handler.afterPropertiesSet();
handler.handleMessage(new GenericMessage<String>("hello"));
assertFileExists(file);
}
@Test
public void testHandleFileAsByte() throws Exception {
File file = createNewFile("remote-target-dir/handlerContent.test");
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(smbSessionFactory);
handler.setRemoteDirectoryExpression(new LiteralExpression("remote-target-dir"));
handler.setFileNameGenerator(new FileNameGenerator() {
public String generateFileName(Message<?> message) {
return "handlerContent.test";
}
});
handler.afterPropertiesSet();
handler.handleMessage(new GenericMessage<byte[]>("hello".getBytes()));
assertFileExists(file);
}
@Test
public void testHandleFileMessage() throws Exception {
File file = createNewFile("remote-target-dir/template.mf.test");
FileTransferringMessageHandler<?> handler = new FileTransferringMessageHandler<SmbFile>(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>() {
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(new Answer<Object>() {
public Object answer(InvocationOnMock _invocation) throws Throwable {
InputStream inputStream = (InputStream) _invocation.getArguments()[0];
String path = (String) _invocation.getArguments()[1];
writeToFile(inputStream, path);
return null;
}
}).when(smbSession).write(Mockito.any(InputStream.class), Mockito.anyString());
// when(smbSession.write(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(null);
// when(smbSession.write(Mockito.any(File.class), Mockito.anyString())).thenReturn(null);
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock _invocation) throws Throwable {
String path = (String) _invocation.getArguments()[0];
new File(path).mkdirs();
return null;
}
}).when(smbSession).mkdir(Mockito.anyString());
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock _invocation) throws Throwable {
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,59 @@
/**
* Copyright 2002-2012 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
*
* http://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.junit.Assert.fail;
import org.junit.Test;
public class MySmbSessionTest {
@Test
public void testRemove() {
fail("Not yet implemented");
}
@Test
public void testRead() {
fail("Not yet implemented");
}
@Test
public void testWrite() {
fail("Not yet implemented");
}
@Test
public void testMkdir() {
fail("Not yet implemented");
}
@Test
public void testRename() {
fail("Not yet implemented");
}
@Test
public void testClose() {
fail("Not yet implemented");
}
@Test
public void testIsOpen() {
fail("Not yet implemented");
}
}

View File

@@ -0,0 +1,9 @@
log4j.rootCategory=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.category.org.springframework=WARN
log4j.category.org.springframework.integration=DEBUG
log4j.category.org.springframework.integration.file=DEBUG

View File

@@ -0,0 +1,16 @@
Bundle-SymbolicName: org.springframework.integration.smb
Bundle-Name: Spring Integration SMB Support
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Import-Template:
org.apache.commons.logging;version="[1.1.1, 2.0.0)",
org.apache.commons.net.*;version="[2.0.0, 3.0.0)",
org.springframework.integration.*;version="[2.0.5, 2.0.6)",
org.springframework.beans.*;version="[3.0.5, 4.0.0)",
org.springframework.context;version="[3.0.5, 4.0.0)",
org.springframework.core.*;version="[3.0.5, 4.0.0)",
org.springframework.scheduling.*;version="[3.0.5, 4.0.0)",
org.springframework.util;version="[3.0.5, 4.0.0)",
javax.*;version="0",
org.w3c.dom.*;version="0"