Reputation: 344
I'm trying to implement a connection pool using https://commons.apache.org/proper/commons-pool/ with JSch and use it in a Spring rest controller. I coded based on this stackoverflow answer: https://stackoverflow.com/a/53101465/5617549
I'm trying to figure out if the sftp code that I use it with does not have any threading problem. Is there any test that I can perform? Or is there an obvious mistake on my usage?
This is what I have so far:
@Service
public class JschFileTransferService implements FileTransferService {
private final ObjectPool<Session> sshConnectionPool;
public JschFileTransferService(ObjectPool<Session> sshConnectionPool) {
this.sshConnectionPool = sshConnectionPool;
}
@Override
public Boolean sendFile(String data) {
try {
Session session = sshConnectionPool.borrowObject();
try {
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp channelSftp = (ChannelSftp) channel;
InputStream inputStream = new ByteArrayInputStream(data.getBytes());
String fileName = UUID.randomUUID() + "_" + Instant.now();
channelSftp.put(inputStream, "./sample/" + fileName);
return true;
} catch (Exception e) {
sshConnectionPool.invalidateObject(session);
session = null;
throw new FileTransferException(FILE_TRANSFER_GENERAL_ERROR, "Unable to perform file transfer");
} finally {
if (session != null) {
sshConnectionPool.returnObject(session);
}
}
} catch (Exception e) {
throw new FileTransferException(FILE_TRANSFER_GENERAL_ERROR, "Unable to get ssh connection");
}
}
}
public class JschSessionFactory extends BasePooledObjectFactory<Session> {
@Override
public Session create() throws Exception {
try {
JSch jsch = new JSch();
String user = "some-user";
String host = "some-server";
int port = 22;
jsch.addIdentity(".ssh/id_rsa");
Session session = jsch.getSession(user, host, port);
session.connect();
return session;
} catch (JSchException e) {
throw new SshException(SSH_FATAL_ERROR, "Unable to connect/ssh to server");
}
}
@Override
public PooledObject<Session> wrap(Session session) {
return new DefaultPooledObject<>(session);
}
}
@Configuration
public class SshConfiguration{
@Bean
public ObjectPool<Session> createSshConnectionPool(){
PooledObjectFactory<Session> pooledObjectFactory = PoolUtils.synchronizedPooledFactory(new JschSessionFactory());
return PoolUtils.synchronizedPool(new GenericObjectPool<>(pooledObjectFactory));
}
}
Upvotes: 0
Views: 686
Reputation: 8886
I would just packetcap your code while stepping through with a debugger. Does the TCP/ssh connection happen at channel.connect();
? I doubt this is happening, but it's worth verifying. Ssh does allow channel multiplexing so it's probably fine the way you have it above.
Don't forget: the only real way to tell would be to benchmark pool vs un-pooled. Don't skip this step.
Another useful thing may be to only ever hand the executing code an open connection. If there's a way to test the connection before handing if off, that may be useful.
Otherwise I don't see anything inherently wrong with the above code.
Upvotes: 0