Hi Josh,
the solution using the JCIFS library is pretty easy. As I have no time to open source the whole adapter here are the two main classes:
SmbSession.java
Code:
package org.springframework.integration.smb.session;
import ...
/**
* Default SMB {@link Session} implementation.
*/
class SmbSession implements Session {
private final static Log logger = LogFactory.getLog(SmbSession.class);
private final NtlmPasswordAuthentication ntlmAuth;
private boolean isOpen;
/**
* The default constructor.
* @param ntlmAuth NTLM user credentials
*/
public SmbSession(NtlmPasswordAuthentication ntlmAuth) {
Assert.notNull(ntlmAuth, "ntlmAuth must not be null");
this.ntlmAuth = ntlmAuth;
this.isOpen = true;
}
/**
* @see org.springframework.integration.file.remote.session.Session#remove(java.lang.String)
*/
public boolean remove(String path) throws IOException {
try {
SmbFile file = new SmbFile(path, ntlmAuth);
file.delete();
} catch( SmbAuthException ex ) {
// handle authentication related issue here
isOpen = false;
throw new NestedIOException("Failed to remove resource " + path, ex);
} catch( SmbException ex ) {
// any special SMB related exception handling
throw new NestedIOException("Failed to remove resource " + path, ex);
}
if (logger.isDebugEnabled()){
logger.debug("Successfully removed resource " + path);
}
return true;
}
/**
* @see org.springframework.integration.file.remote.session.Session#list(java.lang.String)
*/
@SuppressWarnings("unchecked")
public SmbFile[] list(String path) throws IOException {
try {
SmbFile file = new SmbFile(path, ntlmAuth);
SmbFile[] list = file.listFiles();
if (list == null) {
throw new NestedIOException("Failed to list resource - unable to resolve " + path);
}
return list;
} catch( SmbAuthException ex ) {
// handle authentication related issue here
isOpen = false;
throw new NestedIOException("Failed to list resource " + path, ex);
} catch( SmbException ex ) {
// any special SMB related exception handling
throw new NestedIOException("Failed to list resource " + path, ex);
}
}
/**
* @see org.springframework.integration.file.remote.session.Session#read(java.lang.String, java.io.OutputStream)
*/
public void read(String source, OutputStream os) throws IOException {
try {
SmbFile file = new SmbFile(source, ntlmAuth);
InputStream is = file.getInputStream();
FileCopyUtils.copy(is, os);
} catch( SmbAuthException ex ) {
// handle authentication related issue here
isOpen = false;
throw new NestedIOException("Failed to read resource " + source, ex);
} catch( SmbException ex ) {
// any special SMB related exception handling
throw new NestedIOException("Failed to read resource " + source, ex);
}
if (logger.isDebugEnabled()){
logger.debug("Successfully read resource " + source);
}
}
/**
* @see org.springframework.integration.file.remote.session.Session#write(java.io.InputStream, java.lang.String)
*/
public void write(InputStream inputStream, String destination) throws IOException {
try {
SmbFile file = new SmbFile(destination, ntlmAuth);
OutputStream os = file.getOutputStream();
FileCopyUtils.copy(inputStream, os);
} catch( SmbAuthException ex ) {
// handle authentication related issue here
isOpen = false;
throw new NestedIOException("Failed to write resource " + destination, ex);
} catch( SmbException ex ) {
// any special SMB related exception handling
throw new NestedIOException("Failed to write resource " + destination, ex);
}
if (logger.isDebugEnabled()){
logger.debug("Successfully written resource " + destination);
}
}
/**
* @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 source = new SmbFile(pathFrom, ntlmAuth);
SmbFile dest = new SmbFile(pathTo, ntlmAuth);
source.renameTo(dest);
} catch( SmbAuthException ex ) {
// handle authentication related issue here
isOpen = false;
throw new NestedIOException("Failed to rename from " + pathFrom + " to " + pathTo, ex);
} catch( SmbException ex ) {
// any special SMB related exception handling
throw new NestedIOException("Failed to rename from " + pathFrom + " to " + pathTo, ex);
}
if (logger.isDebugEnabled()){
logger.debug("Resource " + pathFrom + " was successfully renamed to " + pathTo);
}
}
/**
* @see org.springframework.integration.file.remote.session.Session#mkdir(java.lang.String)
*/
public void mkdir(String directory) throws IOException {
try {
SmbFile file = new SmbFile(directory, ntlmAuth);
file.mkdirs();
} catch( SmbAuthException ex ) {
// handle authentication related issue here
isOpen = false;
throw new NestedIOException("Failed to create directory " + directory, ex);
} catch( SmbException ex ) {
// any special SMB related exception handling
throw new NestedIOException("Failed to create directory " + directory, ex);
}
if (logger.isDebugEnabled()){
logger.debug("Successfully created " + directory);
}
}
/**
* @see org.springframework.integration.file.remote.session.Session#close()
*/
public void close() {
isOpen = false;
}
/**
* @see org.springframework.integration.file.remote.session.Session#isOpen()
*/
public boolean isOpen() {
return isOpen;
}
}
DefaultSmbSessionFactory.java
Code:
package org.springframework.integration.smb.session;
import ...
/**
* Factory for creating {@link SmbSession} instances.
*/
public class DefaultSmbSessionFactory implements SessionFactory {
private volatile String domain;
private volatile String user;
private volatile String password;
public void setDomain(String domain) {
this.domain = domain;
}
public void setUser(String user) {
this.user = user;
}
public void setPassword(String password) {
this.password = password;
}
public Session getSession() {
Assert.notNull(this.domain, "domain must not be null");
Assert.hasText(this.user, "user must not be empty");
Assert.isTrue(StringUtils.hasText(this.password), "password is required");
try {
NtlmPasswordAuthentication ntlmAuth = new NtlmPasswordAuthentication(domain, user, password);
SmbSession smbSession = new SmbSession(ntlmAuth);
return smbSession;
}
catch (Exception e) {
throw new IllegalStateException("failed to create SMB Session", e);
}
}
}
The rest is straight forward. You might want to integrate it in future versions of Spring Integration.
There is one thing remaining:
- All the FTP/SFTP/HTTP/HTTPS adapters require a local directory for their inbound-channel-adapter, right?
- Is it possible to download directly e.g. from FTP to another outbound channel, in my case SMB...?
- Is there a solution to prevent an inbound channel from transferring a file already existing on another outbound channel?
Regards
Gunnar