This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push:
new 28b0aaa [SSHD-1089] Added wrappers for one-time single session usage
of SFTP/SCP clients
28b0aaa is described below
commit 28b0aaa14844c4f2e9803548901430e93dc93286
Author: Lyor Goldstein <[email protected]>
AuthorDate: Sat Sep 26 10:43:43 2020 +0300
[SSHD-1089] Added wrappers for one-time single session usage of SFTP/SCP
clients
---
CHANGES.md | 1 +
docs/scp.md | 26 +-
docs/sftp.md | 29 +-
.../apache/sshd/common/session/SessionContext.java | 4 +-
.../sshd/common/util/EventListenerUtils.java | 10 +-
.../org/apache/sshd/common/util/ProxyUtils.java | 51 +++
.../AutoCloseableDelegateInvocationHandler.java | 129 +++++++
.../NioChannelDelegateInvocationHandler.java | 95 +++++
.../apache/sshd/util/test/JUnitTestSupport.java | 6 +-
.../java/org/apache/sshd/KeyReExchangeTest.java | 5 +-
.../sshd/common/forward/PortForwardingTest.java | 5 +-
.../apache/sshd/scp/client/CloseableScpClient.java | 12 +-
.../sshd/scp/client/SimpleScpClientImpl.java | 25 +-
.../sshd/scp/client/AbstractScpTestSupport.java | 18 +
.../java/org/apache/sshd/scp/client/ScpTest.java | 80 ++---
.../sshd/sftp/client/FullAccessSftpClient.java | 20 +-
.../org/apache/sshd/sftp/client/SftpClient.java | 10 +
.../sshd/sftp/client/impl/AbstractSftpClient.java | 5 +-
.../sftp/client/impl/SimpleSftpClientImpl.java | 60 +---
.../sftp/client/AbstractSftpClientTestSupport.java | 22 ++
.../java/org/apache/sshd/sftp/client/SftpTest.java | 396 ++++++++++-----------
.../extensions/UnsupportedExtensionTest.java | 8 +-
.../helpers/AbstractCheckFileExtensionTest.java | 4 +-
.../helpers/AbstractMD5HashExtensionTest.java | 4 +-
.../helpers/CopyDataExtensionImplTest.java | 4 +-
.../helpers/CopyFileExtensionImplTest.java | 4 +-
.../helpers/SpaceAvailableExtensionImplTest.java | 4 +-
.../openssh/helpers/OpenSSHExtensionsTest.java | 7 +-
.../sftp/client/fs/SftpDirectoryScannersTest.java | 4 +-
.../client/impl/SftpRemotePathChannelTest.java | 46 ++-
30 files changed, 682 insertions(+), 412 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 1c35b7c..c9d2864 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -32,6 +32,7 @@ or `-key-file` command line option.
* [SSHD-1077](https://issues.apache.org/jira/browse/SSHD-1077) Added command
line option to request specific SFTP version in `SftpCommandMain`
* [SSHD-1079](https://issues.apache.org/jira/browse/SSHD-1079) Experimental
async mode on the local port forwarder
* [SSHD-1086](https://issues.apache.org/jira/browse/SSHD-1086) Added SFTP
aware directory scanning helper classes
+* [SSHD-1089](https://issues.apache.org/jira/browse/SSHD-1089) Added wrappers
for one-time single session usage of SFTP/SCP clients
## Behavioral changes and enhancements
diff --git a/docs/scp.md b/docs/scp.md
index 499241c..b3f131c 100644
--- a/docs/scp.md
+++ b/docs/scp.md
@@ -44,14 +44,32 @@ In order to obtain an `ScpClient` one needs to use an
`ScpClientCreator`:
```java
-ClientSession session = ... obtain an instance ...
-ScpClientCreator creator = ... obtain an instance ...
-ScpClient client = creator.createScpClient(session);
-
+try (ClientSession session = ... obtain an instance ...) {
+ ScpClientCreator creator = ... obtain an instance ...
+ ScpClient client = creator.createScpClient(session);
+ ... use client ...
+}
```
A default `ScpClientCreator` instance is provided as part of the module - see
`ScpClientCreator.instance()`
+If the intended use of the client instance is "one-shot" - i.e., the client
session should be closed when the
+SCP client instance is closed, then it is possible to obtain a special wrapper
that implements this functionality:
+
+```java
+// The underlying session will also be closed when the client is
+try (CloseableScpClient client = createScpClient(...)) {
+ ... use client ...
+}
+
+CloseableScpClient createScpClient(...) {
+ ClientSession session = ... obtain an instance ...;
+ ScpClientCreator creator = ... obtain an instance ...
+ ScpClient client = creator.createScpClient(session);
+ return CloseableScpClient.singleSessionInstance(client);
+}
+```
+
The `ScpClientCreator` can also be used to attach a default
`ScpTransferEventListener` that will be automatically
add to **all** created SCP client instances through that creator - unless
specifically overridden:
diff --git a/docs/sftp.md b/docs/sftp.md
index 7a1b15a..3fd7cc9 100644
--- a/docs/sftp.md
+++ b/docs/sftp.md
@@ -143,14 +143,37 @@ In order to obtain an `SftpClient` instance one needs to
use an `SftpClientFacto
```java
- ClientSession session = ...obtain session...
- SftpClientFactory factory = ...obtain factory...
- SftpClient client = factory.createSftpClient(session);
+ try (ClientSession session = ...obtain session...) {
+ SftpClientFactory factory = ...obtain factory...
+ try (SftpClient client = factory.createSftpClient(session)) {
+ ... use the SFTP client...
+ }
+
+ // NOTE: session is still alive here...
+ }
```
A default client factory implementations is provided in the module - see
`SftpClientFactory.instance()`
+If the intended use of the client instance is "one-shot" - i.e., the client
session should be closed when the
+SFTP client instance is closed, then it is possible to obtain a special
wrapper that implements this functionality:
+
+```java
+
+// The underlying session will also be closed when the client is
+try (SftpClient client = createSftpClient(....)) {
+ ... use the SFTP client...
+}
+
+SftpClient createSftpClient(...) {
+ ClientSession session = ...obtain session...
+ SftpClientFactory factory = ...obtain factory...
+ SftpClient client = factory.createSftpClient(session);
+ return client.singleSessionInstance();
+}
+```
+
### Using a custom `SftpClientFactory`
The code creates `SftpClient`-s and `SftpFileSystem`-s using a default
built-in `SftpClientFactory` instance (see
diff --git
a/sshd-common/src/main/java/org/apache/sshd/common/session/SessionContext.java
b/sshd-common/src/main/java/org/apache/sshd/common/session/SessionContext.java
index 4bc87f6..622c5db 100644
---
a/sshd-common/src/main/java/org/apache/sshd/common/session/SessionContext.java
+++
b/sshd-common/src/main/java/org/apache/sshd/common/session/SessionContext.java
@@ -46,14 +46,14 @@ public interface SessionContext
Closeable {
/**
* Default prefix expected for the client / server identification string
- *
+ *
* @see <A HREF="https://tools.ietf.org/html/rfc4253#section-4.2">RFC 4253
- section 4.2</A>
*/
String DEFAULT_SSH_VERSION_PREFIX = "SSH-2.0-";
/**
* Backward compatible special prefix
- *
+ *
* @see <A HREF="https://tools.ietf.org/html/rfc4253#section-5">RFC 4253 -
section 5</A>
*/
String FALLBACK_SSH_VERSION_PREFIX = "SSH-1.99-";
diff --git
a/sshd-common/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
b/sshd-common/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
index f66f3c6..ffc719f 100644
---
a/sshd-common/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
+++
b/sshd-common/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
@@ -189,13 +189,10 @@ public final class EventListenerUtils {
* @see #proxyWrapper(Class, ClassLoader,
Iterable)
*/
public static <T extends SshdEventListener> T proxyWrapper(
- Class<T> listenerType, ClassLoader loader, final Iterable<?
extends T> listeners) {
- Objects.requireNonNull(listenerType, "No listener type specified");
- ValidateUtils.checkTrue(listenerType.isInterface(), "Target proxy is
not an interface: %s",
- listenerType.getSimpleName());
+ Class<T> listenerType, ClassLoader loader, Iterable<? extends T>
listeners) {
Objects.requireNonNull(listeners, "No listeners container provided");
- Object wrapper = Proxy.newProxyInstance(loader, new Class<?>[] {
listenerType }, (proxy, method, args) -> {
+ return ProxyUtils.newProxyInstance(loader, listenerType, (proxy,
method, args) -> {
Throwable err = null;
for (T l : listeners) {
try {
@@ -207,11 +204,10 @@ public final class EventListenerUtils {
}
if (err != null) {
- throw err;
+ throw ProxyUtils.unwrapInvocationThrowable(err);
}
return null; // we assume always void return value...
});
- return listenerType.cast(wrapper);
}
}
diff --git
a/sshd-common/src/main/java/org/apache/sshd/common/util/ProxyUtils.java
b/sshd-common/src/main/java/org/apache/sshd/common/util/ProxyUtils.java
new file mode 100644
index 0000000..864c5b6
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/ProxyUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.sshd.common.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+
+/**
+ * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
+ */
+public final class ProxyUtils {
+ private ProxyUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
+ public static <T> T newProxyInstance(Class<T> type, InvocationHandler
handler) {
+ return newProxyInstance(type.getClassLoader(), type, handler);
+ }
+
+ public static <T> T newProxyInstance(ClassLoader cl, Class<T> type,
InvocationHandler handler) {
+ Class<?>[] interfaces = { type };
+ Object wrapper = Proxy.newProxyInstance(cl, interfaces, handler);
+ return type.cast(wrapper);
+ }
+
+ public static Throwable unwrapInvocationThrowable(Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ return unwrapInvocationThrowable(((InvocationTargetException)
t).getTargetException());
+ } else {
+ return t;
+ }
+ }
+}
diff --git
a/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/AutoCloseableDelegateInvocationHandler.java
b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/AutoCloseableDelegateInvocationHandler.java
new file mode 100644
index 0000000..e6914d5
--- /dev/null
+++
b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/AutoCloseableDelegateInvocationHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.sshd.common.util.closeable;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Objects;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ProxyUtils;
+import org.apache.sshd.common.util.logging.LoggingUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wraps a target instance and an {@link AutoCloseable} delegate into a proxy
instance that closes both when wrapper
+ * {@link AutoCloseable#close() close} method called.
+ *
+ * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
+ */
+public class AutoCloseableDelegateInvocationHandler implements
InvocationHandler {
+ private final Object proxyTarget;
+ private final AutoCloseable delegate;
+ // Order is important - we want to close the proxy before the delegate
+ private final Object[] closers;
+
+ public AutoCloseableDelegateInvocationHandler(Object proxyTarget,
AutoCloseable delegate) {
+ this.proxyTarget = Objects.requireNonNull(proxyTarget, "No proxy
target to wrap");
+ this.delegate = Objects.requireNonNull(delegate, "No delegate to
auto-close");
+ this.closers = new Object[] { proxyTarget, delegate };
+ }
+
+ public Object getProxyTarget() {
+ return proxyTarget;
+ }
+
+ public AutoCloseable getAutoCloseableDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
+ // If not invoking "close" then propagate to target as-is
+ if (!isCloseMethodInvocation(method, args)) {
+ Object target = getProxyTarget();
+ try {
+ return method.invoke(target, args);
+ } catch (Throwable t) {
+ Class<?> targetType = target.getClass();
+ Logger log = LoggerFactory.getLogger(targetType);
+ LoggingUtils.debug(log, "invoke({}#{}) failed ({}) to execute:
{}",
+ targetType.getSimpleName(), method.getName(),
t.getClass().getSimpleName(), t.getMessage(), t);
+ throw ProxyUtils.unwrapInvocationThrowable(t);
+ }
+ }
+
+ Throwable err = null;
+ for (Object c : closers) {
+ if (!(c instanceof AutoCloseable)) {
+ continue; // OK if proxy target is not AutoCloseable
+ }
+
+ try {
+ method.invoke(c, args);
+ } catch (Throwable t) {
+ Class<? extends Object> closerType = c.getClass();
+ Logger log = LoggerFactory.getLogger(closerType);
+ LoggingUtils.debug(log, "invoke({}#{}) failed ({}) to execute:
{}",
+ closerType.getSimpleName(), method.getName(),
t.getClass().getSimpleName(), t.getMessage(), t);
+ err = GenericUtils.accumulateException(err, t);
+ }
+ }
+
+ if (err != null) {
+ throw ProxyUtils.unwrapInvocationThrowable(err);
+ }
+
+ return null;
+ }
+
+ /**
+ * Wraps a target instance and an {@link AutoCloseable} delegate into a
proxy instance that closes both when wrapper
+ * {@link AutoCloseable#close() close} method called.
+ *
+ * @param <T> The generic {@link AutoCloseable} wrapping interface
+ * @param proxyTarget The (never {@code null}) target instance - if not
{@link AutoCloseable} then it's
+ * {@code close()} method will not be invoked (i.e.,
only the delegate)
+ * @param type The target wrapping interface
+ * @param delegate The (never {@code null}) delegate to close.
<B>Note:</B> the delegate is closed <U>after</U>
+ * the target instance.
+ * @return The wrapping proxy
+ */
+ public static <T extends AutoCloseable> T wrapDelegateCloseable(
+ Object proxyTarget, Class<T> type, AutoCloseable delegate) {
+ return ProxyUtils.newProxyInstance(type, new
AutoCloseableDelegateInvocationHandler(proxyTarget, delegate));
+ }
+
+ public static boolean isCloseMethodInvocation(Method m, Object[] args) {
+ return isCloseMethod(m) && GenericUtils.isEmpty(args);
+ }
+
+ public static boolean isCloseMethod(Method m) {
+ int mods = (m == null) ? 0 : m.getModifiers();
+ return (m != null)
+ && "close".equals(m.getName())
+ && Modifier.isPublic(mods)
+ && (!Modifier.isStatic(mods))
+ && (void.class == m.getReturnType())
+ && GenericUtils.isEmpty(m.getParameterTypes());
+ }
+}
diff --git
a/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/NioChannelDelegateInvocationHandler.java
b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/NioChannelDelegateInvocationHandler.java
new file mode 100644
index 0000000..886eeb2
--- /dev/null
+++
b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/NioChannelDelegateInvocationHandler.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.sshd.common.util.closeable;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.channels.Channel;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ProxyUtils;
+import org.apache.sshd.common.util.logging.LoggingUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wraps a target instance and a {@link Channel} delegate into a proxy
instance that closes both when wrapper
+ * {@link AutoCloseable#close() close} method called. The {@link
Channel#isOpen()} call is invoked only on the delegate
+ *
+ * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
+ */
+public class NioChannelDelegateInvocationHandler extends
AutoCloseableDelegateInvocationHandler {
+ public NioChannelDelegateInvocationHandler(Object proxyTarget, Channel
delegate) {
+ super(proxyTarget, delegate);
+ }
+
+ public Channel getChannelDelegate() {
+ return Channel.class.cast(super.getAutoCloseableDelegate());
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
+ if (!isQueryOpenMethodInvocation(method, args)) {
+ return super.invoke(proxy, method, args);
+ }
+
+ Channel channelDelegate = getChannelDelegate();
+ try {
+ return method.invoke(channelDelegate, args);
+ } catch (Throwable t) {
+ Class<?> targetType = channelDelegate.getClass();
+ Logger log = LoggerFactory.getLogger(targetType);
+ LoggingUtils.debug(log, "invoke({}#{}) failed ({}) to execute: {}",
+ targetType.getSimpleName(), method.getName(),
t.getClass().getSimpleName(), t.getMessage(), t);
+ throw ProxyUtils.unwrapInvocationThrowable(t);
+ }
+ }
+
+ /**
+ * Wraps a target instance and a {@link Channel} delegate into a proxy
instance that closes both when wrapper
+ * {@link Channel#close() close} method called. The {@link
Channel#isOpen()} call is invoked only on the delegate
+ *
+ * @param <T> The generic {@link Channel} wrapping interface
+ * @param proxyTarget The (never {@code null}) target instance - if not
{@link AutoCloseable} then it's
+ * {@code close()} method will not be invoked (i.e.,
only the delegate)
+ * @param type The target wrapping interface
+ * @param delegate The (never {@code null}) delegate to use.
<B>Note:</B> the delegate is closed <U>after</U>
+ * the target instance.
+ * @return The wrapping proxy
+ */
+ public static <T extends Channel> T wrapDelegateChannel(
+ Object proxyTarget, Class<T> type, Channel delegate) {
+ return ProxyUtils.newProxyInstance(type, new
NioChannelDelegateInvocationHandler(proxyTarget, delegate));
+ }
+
+ public static boolean isQueryOpenMethodInvocation(Method m, Object[] args)
{
+ return isQueryOpenMethodInvocation(m) && GenericUtils.isEmpty(args);
+ }
+
+ public static boolean isQueryOpenMethodInvocation(Method m) {
+ int mods = (m == null) ? 0 : m.getModifiers();
+ return (m != null)
+ && "isOpen".equals(m.getName())
+ && Modifier.isPublic(mods)
+ && (!Modifier.isStatic(mods))
+ && (boolean.class == m.getReturnType())
+ && GenericUtils.isEmpty(m.getParameterTypes());
+ }
+}
diff --git
a/sshd-common/src/test/java/org/apache/sshd/util/test/JUnitTestSupport.java
b/sshd-common/src/test/java/org/apache/sshd/util/test/JUnitTestSupport.java
index cd71bc2..a635fc9 100644
--- a/sshd-common/src/test/java/org/apache/sshd/util/test/JUnitTestSupport.java
+++ b/sshd-common/src/test/java/org/apache/sshd/util/test/JUnitTestSupport.java
@@ -608,7 +608,11 @@ public abstract class JUnitTestSupport extends Assert {
long nanoSleep = sleepEnd - sleepStart;
sleepTime = TimeUnit.NANOSECONDS.toMillis(nanoSleep);
- timeout -= sleepTime;
+ if (sleepTime <= 0L) {
+ timeout -= 10L;
+ } else {
+ timeout -= sleepTime;
+ }
}
return false;
diff --git a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
index 2724a8e..a536252 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
@@ -24,7 +24,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
-import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
@@ -52,6 +51,7 @@ import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.session.SessionListener;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ProxyUtils;
import org.apache.sshd.common.util.io.NullOutputStream;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.apache.sshd.core.CoreModuleProperties;
@@ -156,7 +156,6 @@ public class KeyReExchangeTest extends BaseTestSupport {
AtomicBoolean successfulInit = new AtomicBoolean(true);
AtomicBoolean successfulNext = new AtomicBoolean(true);
ClassLoader loader = getClass().getClassLoader();
- Class<?>[] interfaces = { KeyExchange.class };
for (KeyExchangeFactory factory :
client.getKeyExchangeFactories()) {
kexFactories.add(new KeyExchangeFactory() {
@Override
@@ -167,7 +166,7 @@ public class KeyReExchangeTest extends BaseTestSupport {
@Override
public KeyExchange createKeyExchange(Session s) throws
Exception {
KeyExchange proxiedInstance =
factory.createKeyExchange(s);
- return (KeyExchange) Proxy.newProxyInstance(loader,
interfaces, (proxy, method, args) -> {
+ return ProxyUtils.newProxyInstance(loader,
KeyExchange.class, (proxy, method, args) -> {
String name = method.getName();
if ("init".equals(name) &&
(!successfulInit.get())) {
throw new
UnsupportedOperationException("Intentionally failing 'init'");
diff --git
a/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
b/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
index 1210e59..51bcb80 100644
---
a/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
+++
b/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
@@ -24,7 +24,6 @@ import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
@@ -55,6 +54,7 @@ import
org.apache.sshd.client.session.forward.ExplicitPortForwardingTracker;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.MapEntryUtils.NavigableMapBuilder;
+import org.apache.sshd.common.util.ProxyUtils;
import org.apache.sshd.common.util.net.SshdSocketAddress;
import org.apache.sshd.core.CoreModuleProperties;
import org.apache.sshd.server.SshServer;
@@ -180,7 +180,6 @@ public class PortForwardingTest extends BaseTestSupport {
ForwarderFactory factory =
Objects.requireNonNull(sshd.getForwarderFactory(), "No ForwarderFactory");
sshd.setForwarderFactory(new ForwarderFactory() {
- private final Class<?>[] interfaces = { Forwarder.class };
private final Map<String, String> method2req
= NavigableMapBuilder.<String, String>
builder(String.CASE_INSENSITIVE_ORDER)
.put("localPortForwardingRequested",
TcpipForwardHandler.REQUEST)
@@ -193,7 +192,7 @@ public class PortForwardingTest extends BaseTestSupport {
ClassLoader cl = thread.getContextClassLoader();
Forwarder forwarder = factory.create(service);
- return (Forwarder) Proxy.newProxyInstance(cl, interfaces, new
InvocationHandler() {
+ return ProxyUtils.newProxyInstance(cl, Forwarder.class, new
InvocationHandler() {
private final org.slf4j.Logger log =
LoggerFactory.getLogger(Forwarder.class);
@SuppressWarnings("synthetic-access")
diff --git
a/sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
b/sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
index 0171a88..68ddb1c 100644
--- a/sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
+++ b/sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
@@ -21,11 +21,21 @@ package org.apache.sshd.scp.client;
import java.nio.channels.Channel;
+import
org.apache.sshd.common.util.closeable.NioChannelDelegateInvocationHandler;
+
/**
* An {@link ScpClient} wrapper that also closes the underlying session when
closed
*
* @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
*/
public interface CloseableScpClient extends ScpClient, Channel {
- // Marker interface
+ /**
+ * @param client The (never {@code null}) {@link ScpClient} instance
+ * @return A {@link CloseableScpClient} wrapper that also closes
the underlying {@link #getClientSession()}
+ * when closed
+ */
+ static CloseableScpClient singleSessionInstance(ScpClient client) {
+ return NioChannelDelegateInvocationHandler.wrapDelegateChannel(
+ client, CloseableScpClient.class, client.getClientSession());
+ }
}
diff --git
a/sshd-scp/src/main/java/org/apache/sshd/scp/client/SimpleScpClientImpl.java
b/sshd-scp/src/main/java/org/apache/sshd/scp/client/SimpleScpClientImpl.java
index afb1990..7b8e474 100644
--- a/sshd-scp/src/main/java/org/apache/sshd/scp/client/SimpleScpClientImpl.java
+++ b/sshd-scp/src/main/java/org/apache/sshd/scp/client/SimpleScpClientImpl.java
@@ -20,7 +20,6 @@
package org.apache.sshd.scp.client;
import java.io.IOException;
-import java.lang.reflect.Proxy;
import java.net.SocketAddress;
import java.security.KeyPair;
import java.util.Objects;
@@ -98,7 +97,7 @@ public class SimpleScpClientImpl extends AbstractLoggingBean
implements SimpleSc
try {
ScpClientCreator creator = getScpClientCreator();
ScpClient client =
creator.createScpClient(Objects.requireNonNull(session, "No client session"));
- return createScpClient(session, client);
+ return CloseableScpClient.singleSessionInstance(client);
} catch (Exception e) {
log.warn("createScpClient({}) failed ({}) to create proxy: {}",
session, e.getClass().getSimpleName(), e.getMessage());
@@ -114,28 +113,6 @@ public class SimpleScpClientImpl extends
AbstractLoggingBean implements SimpleSc
}
}
- protected CloseableScpClient createScpClient(ClientSession session,
ScpClient client) throws IOException {
- ClassLoader loader = CloseableScpClient.class.getClassLoader();
- Class<?>[] interfaces = { CloseableScpClient.class };
- return (CloseableScpClient) Proxy.newProxyInstance(loader, interfaces,
(proxy, method, args) -> {
- String name = method.getName();
- try {
- // The Channel implementation is provided by the session
- if (("close".equals(name) || "isOpen".equals(name)) &&
GenericUtils.isEmpty(args)) {
- return method.invoke(session, args);
- } else {
- return method.invoke(client, args);
- }
- } catch (Throwable t) {
- if (log.isTraceEnabled()) {
- log.trace("invoke(CloseableScpClient#{}) failed ({}) to
execute: {}",
- name, t.getClass().getSimpleName(),
t.getMessage());
- }
- throw t;
- }
- });
- }
-
@Override
public boolean isOpen() {
return true;
diff --git
a/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
b/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
index abb0021..b5f6c87 100644
---
a/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
+++
b/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
@@ -174,6 +174,24 @@ public abstract class AbstractScpTestSupport extends
BaseTestSupport {
return OUTPUT_DEBUG_MESSAGES ? DEBUG_LISTENER :
ScpTransferEventListener.EMPTY;
}
+ protected CloseableScpClient createCloseableScpClient() throws IOException
{
+ return createCloseableScpClient(getCurrentTestName());
+ }
+
+ protected CloseableScpClient createCloseableScpClient(String username)
throws IOException {
+ ClientSession session = createAuthenticatedClientSession(username);
+ try {
+ ScpClient client = createScpClient(session);
+ CloseableScpClient closer =
CloseableScpClient.singleSessionInstance(client);
+ session = null; // avoid auto-close at finally clause
+ return closer;
+ } finally {
+ if (session != null) {
+ session.close();
+ }
+ }
+ }
+
protected static ScpClient createScpClient(ClientSession session) {
ScpClientCreator creator = ScpClientCreator.instance();
ScpTransferEventListener listener =
getScpTransferEventListener(session);
diff --git a/sshd-scp/src/test/java/org/apache/sshd/scp/client/ScpTest.java
b/sshd-scp/src/test/java/org/apache/sshd/scp/client/ScpTest.java
index a07c097..214fe0a 100644
--- a/sshd-scp/src/test/java/org/apache/sshd/scp/client/ScpTest.java
+++ b/sshd-scp/src/test/java/org/apache/sshd/scp/client/ScpTest.java
@@ -120,8 +120,7 @@ public class ScpTest extends AbstractScpTestSupport {
String[] remoteComps = GenericUtils.split(remotePath, '/');
Factory<? extends Random> factory = client.getRandomFactory();
Random rnd = factory.create();
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
StringBuilder sb = new StringBuilder(remotePath.length() +
Long.SIZE);
for (int i = 0; i < Math.max(Long.SIZE, remoteComps.length); i++) {
if (sb.length() > 0) {
@@ -175,8 +174,7 @@ public class ScpTest extends AbstractScpTestSupport {
Path remoteFile =
remoteDir.resolve(localFile.getFileName().toString());
String localPath = localFile.toString();
String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, remoteFile);
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
scp.upload(localPath, remotePath);
assertFileLength(remoteFile, data.length, DEFAULT_TIMEOUT);
@@ -194,28 +192,28 @@ public class ScpTest extends AbstractScpTestSupport {
@Test
public void testScpUploadOverwrite() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
- String data = getClass().getName() + "#" + getCurrentTestName() +
IoUtils.EOL;
+ String data = getClass().getName() + "#" + getCurrentTestName() +
IoUtils.EOL;
- Path targetPath = detectTargetFolder();
- Path parentPath = targetPath.getParent();
- Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
- ScpHelper.SCP_COMMAND_PREFIX, getClass().getSimpleName(),
getCurrentTestName());
- CommonTestSupportUtils.deleteRecursive(scpRoot);
+ Path targetPath = detectTargetFolder();
+ Path parentPath = targetPath.getParent();
+ Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
+ ScpHelper.SCP_COMMAND_PREFIX, getClass().getSimpleName(),
getCurrentTestName());
+ CommonTestSupportUtils.deleteRecursive(scpRoot);
- Path localDir =
assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
- Path localFile = localDir.resolve("file.txt");
- CommonTestSupportUtils.writeFile(localFile, data);
+ Path localDir =
assertHierarchyTargetFolderExists(scpRoot.resolve("local"));
+ Path localFile = localDir.resolve("file.txt");
+ CommonTestSupportUtils.writeFile(localFile, data);
- Path remoteDir =
assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
- Path remoteFile = remoteDir.resolve(localFile.getFileName());
- CommonTestSupportUtils.writeFile(remoteFile, data + data);
+ Path remoteDir =
assertHierarchyTargetFolderExists(scpRoot.resolve("remote"));
+ Path remoteFile = remoteDir.resolve(localFile.getFileName());
+ CommonTestSupportUtils.writeFile(remoteFile, data + data);
- String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, remoteFile);
+ String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, remoteFile);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
scp.upload(localFile.toString(), remotePath);
- assertFileLength(remoteFile, data.length(), DEFAULT_TIMEOUT);
}
+
+ assertFileLength(remoteFile, data.length(), DEFAULT_TIMEOUT);
}
@Test
@@ -240,12 +238,11 @@ public class ScpTest extends AbstractScpTestSupport {
Files.delete(zeroRemote);
}
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
- String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(targetPath.getParent(),
zeroRemote);
+ String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(targetPath.getParent(),
zeroRemote);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
scp.upload(zeroLocal.toString(), remotePath);
- assertFileLength(zeroRemote, 0L, DEFAULT_TIMEOUT);
}
+ assertFileLength(zeroRemote, 0L, DEFAULT_TIMEOUT);
}
@Test
@@ -269,12 +266,11 @@ public class ScpTest extends AbstractScpTestSupport {
}
assertEquals("Non-zero size for remote file=" + zeroRemote, 0L,
Files.size(zeroRemote));
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
- String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(targetPath.getParent(),
zeroRemote);
+ String remotePath =
CommonTestSupportUtils.resolveRelativeRemotePath(targetPath.getParent(),
zeroRemote);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
scp.download(remotePath, zeroLocal.toString());
- assertFileLength(zeroLocal, 0L, DEFAULT_TIMEOUT);
}
+ assertFileLength(zeroLocal, 0L, DEFAULT_TIMEOUT);
}
@Test
@@ -295,8 +291,7 @@ public class ScpTest extends AbstractScpTestSupport {
Path remoteDir = scpRoot.resolve("remote");
Path remoteOutFile = remoteDir.resolve(localOutFile.getFileName());
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
CommonTestSupportUtils.writeFile(localOutFile, data);
assertFalse("Remote folder already exists: " + remoteDir,
Files.exists(remoteDir));
@@ -335,8 +330,7 @@ public class ScpTest extends AbstractScpTestSupport {
// see SSHD-822
assumeNotIoServiceProvider(EnumSet.of(BuiltinIoServiceFactoryFactories.MINA,
BuiltinIoServiceFactoryFactories.NETTY));
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
@@ -409,8 +403,7 @@ public class ScpTest extends AbstractScpTestSupport {
@Test
public void testScpNativeOnRecursiveDirs() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
@@ -444,8 +437,7 @@ public class ScpTest extends AbstractScpTestSupport {
@Test // see SSHD-893
public void testScpNativeOnDirWithPattern() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
@@ -481,8 +473,7 @@ public class ScpTest extends AbstractScpTestSupport {
Files.createDirectories(remoteDir);
sshd.setFileSystemFactory(new VirtualFileSystemFactory(remoteDir));
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
ScpHelper.SCP_COMMAND_PREFIX, getClass().getSimpleName(),
getCurrentTestName());
@@ -519,8 +510,7 @@ public class ScpTest extends AbstractScpTestSupport {
@Test
public void testScpNativeOnMixedDirAndFiles() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
@@ -559,8 +549,7 @@ public class ScpTest extends AbstractScpTestSupport {
@Test
public void testScpNativePreserveAttributes() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
@@ -617,8 +606,7 @@ public class ScpTest extends AbstractScpTestSupport {
@Test
public void testStreamsUploadAndDownload() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClient scp = createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
@@ -770,9 +758,7 @@ public class ScpTest extends AbstractScpTestSupport {
}
});
- try (ClientSession session = createAuthenticatedClientSession()) {
- ScpClientCreator creator = ScpClientCreator.instance();
- ScpClient scp = creator.createScpClient(session);
+ try (CloseableScpClient scp = createCloseableScpClient()) {
Path targetPath = detectTargetFolder();
Path parentPath = targetPath.getParent();
Path scpRoot = CommonTestSupportUtils.resolve(targetPath,
diff --git
a/sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/FullAccessSftpClient.java
similarity index 55%
copy from
sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
copy to
sshd-sftp/src/main/java/org/apache/sshd/sftp/client/FullAccessSftpClient.java
index 0171a88..eec17c5 100644
--- a/sshd-scp/src/main/java/org/apache/sshd/scp/client/CloseableScpClient.java
+++
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/FullAccessSftpClient.java
@@ -17,15 +17,23 @@
* under the License.
*/
-package org.apache.sshd.scp.client;
+package org.apache.sshd.sftp.client;
-import java.nio.channels.Channel;
+import
org.apache.sshd.common.util.closeable.AutoCloseableDelegateInvocationHandler;
/**
- * An {@link ScpClient} wrapper that also closes the underlying session when
closed
- *
+ * Provides both structured and raw SFTP access
+ *
* @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
*/
-public interface CloseableScpClient extends ScpClient, Channel {
- // Marker interface
+public interface FullAccessSftpClient extends SftpClient, RawSftpClient {
+ static SftpClient singleSessionInstance(SftpClient client) {
+ if (client instanceof FullAccessSftpClient) {
+ return
AutoCloseableDelegateInvocationHandler.wrapDelegateCloseable(
+ client, FullAccessSftpClient.class,
client.getClientSession());
+ } else {
+ return
AutoCloseableDelegateInvocationHandler.wrapDelegateCloseable(
+ client, SftpClient.class, client.getClientSession());
+ }
+ }
}
diff --git
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpClient.java
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpClient.java
index d20c03f..28ebef2 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpClient.java
@@ -978,4 +978,14 @@ public interface SftpClient extends SubsystemClient {
* @see #getServerExtensions()
*/
SftpClientExtension getExtension(String extensionName);
+
+ /**
+ * Creates an {@link SftpClient} instance that also closes the underlying
{@link #getClientSession() client session}
+ * when the client instance is closed.
+ *
+ * @return The wrapper instance
+ */
+ default SftpClient singleSessionInstance() {
+ return FullAccessSftpClient.singleSessionInstance(this);
+ }
}
diff --git
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
index 7e48fb3..c36049e 100644
---
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
+++
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/AbstractSftpClient.java
@@ -44,8 +44,7 @@ import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.sftp.SftpModuleProperties;
-import org.apache.sshd.sftp.client.RawSftpClient;
-import org.apache.sshd.sftp.client.SftpClient;
+import org.apache.sshd.sftp.client.FullAccessSftpClient;
import org.apache.sshd.sftp.client.extensions.BuiltinSftpClientExtensions;
import org.apache.sshd.sftp.client.extensions.SftpClientExtension;
import org.apache.sshd.sftp.client.extensions.SftpClientExtensionFactory;
@@ -57,7 +56,7 @@ import org.apache.sshd.sftp.common.extensions.ParserUtils;
/**
* @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
*/
-public abstract class AbstractSftpClient extends AbstractSubsystemClient
implements SftpClient, RawSftpClient {
+public abstract class AbstractSftpClient extends AbstractSubsystemClient
implements FullAccessSftpClient {
public static final int INIT_COMMAND_SIZE = Byte.BYTES /* command */ +
Integer.BYTES /* version */;
private final Attributes fileOpenAttributes = new Attributes();
diff --git
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/SimpleSftpClientImpl.java
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/SimpleSftpClientImpl.java
index 71198b2..8cf82b0 100644
---
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/SimpleSftpClientImpl.java
+++
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/impl/SimpleSftpClientImpl.java
@@ -20,7 +20,6 @@
package org.apache.sshd.sftp.client.impl;
import java.io.IOException;
-import java.lang.reflect.Proxy;
import java.net.SocketAddress;
import java.security.KeyPair;
@@ -33,8 +32,10 @@ import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClientFactory;
import org.apache.sshd.sftp.client.SimpleSftpClient;
+/**
+ * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
+ */
public class SimpleSftpClientImpl extends AbstractLoggingBean implements
SimpleSftpClient {
-
private SimpleClient clientInstance;
private SftpClientFactory sftpClientFactory;
@@ -97,15 +98,20 @@ public class SimpleSftpClientImpl extends
AbstractLoggingBean implements SimpleS
try {
SftpClient client = sftpClientFactory.createSftpClient(session);
try {
- return createSftpClient(session, client);
+ SftpClient closer = client.singleSessionInstance();
+ client = null; // disable auto-close at finally block
+ return closer;
} catch (Exception e) {
err = GenericUtils.accumulateException(err, e);
- try {
- client.close();
- } catch (Exception t) {
- debug("createSftpClient({}) failed ({}) to close client:
{}",
- session, t.getClass().getSimpleName(),
t.getMessage(), t);
- err = GenericUtils.accumulateException(err, t);
+ } finally {
+ if (client != null) {
+ try {
+ client.close();
+ } catch (Exception t) {
+ debug("createSftpClient({}) failed ({}) to close
client: {}",
+ session, t.getClass().getSimpleName(),
t.getMessage(), t);
+ err = GenericUtils.accumulateException(err, t);
+ }
}
}
} catch (Exception e) {
@@ -113,7 +119,7 @@ public class SimpleSftpClientImpl extends
AbstractLoggingBean implements SimpleS
}
// This point is reached if error occurred
- log.warn("createSftpClient({}) failed ({}) to create session: {}",
+ log.warn("createSftpClient({}) failed ({}) to create client: {}",
session, err.getClass().getSimpleName(), err.getMessage());
try {
@@ -131,40 +137,6 @@ public class SimpleSftpClientImpl extends
AbstractLoggingBean implements SimpleS
}
}
- protected SftpClient createSftpClient(ClientSession session, SftpClient
client) throws IOException {
- ClassLoader loader = SftpClient.class.getClassLoader();
- Class<?>[] interfaces = { SftpClient.class };
- return (SftpClient) Proxy.newProxyInstance(loader, interfaces, (proxy,
method, args) -> {
- Throwable err = null;
- Object result = null;
- String name = method.getName();
- try {
- result = method.invoke(client, args);
- } catch (Throwable t) {
- debug("invoke(SftpClient#{}) failed ({}) to execute: {}",
- name, t.getClass().getSimpleName(), t.getMessage(), t);
- err = GenericUtils.accumulateException(err, t);
- }
-
- // propagate the "close" call to the session as well
- if ("close".equals(name) && GenericUtils.isEmpty(args)) {
- try {
- session.close();
- } catch (Throwable t) {
- debug("invoke(ClientSession#{}) failed ({}) to execute:
{}",
- name, t.getClass().getSimpleName(),
t.getMessage(), t);
- err = GenericUtils.accumulateException(err, t);
- }
- }
-
- if (err != null) {
- throw err;
- }
-
- return result;
- });
- }
-
@Override
public boolean isOpen() {
return true;
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/AbstractSftpClientTestSupport.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/AbstractSftpClientTestSupport.java
index 9ffd69d..4d7b14e 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/AbstractSftpClientTestSupport.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/AbstractSftpClientTestSupport.java
@@ -109,6 +109,28 @@ public abstract class AbstractSftpClientTestSupport
extends BaseTestSupport {
}
}
+ protected SftpClient createSingleSessionClient() throws IOException {
+ ClientSession session = createAuthenticatedClientSession();
+ try {
+ SftpClient client = createSftpClient(session);
+ try {
+ SftpClient closer = client.singleSessionInstance();
+ // avoid auto-close at finally clause
+ client = null;
+ session = null;
+ return closer;
+ } finally {
+ if (client != null) {
+ client.close();
+ }
+ }
+ } finally {
+ if (session != null) {
+ session.close();
+ }
+ }
+ }
+
protected SftpClient createSftpClient(ClientSession session) throws
IOException {
return SftpClientFactory.instance().createSftpClient(session);
}
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
index 415b3c5..c920cf5 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
@@ -169,24 +169,21 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
rnd.fill(expectedRandom);
byte[] expectedText = (getClass().getName() + "#" +
getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
- String file =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile);
-
- try (CloseableHandle handle = sftp.open(
- file, OpenMode.Create, OpenMode.Write, OpenMode.Read,
OpenMode.Append)) {
- sftp.write(handle, 7365L, expectedRandom);
- byte[] actualRandom = new byte[expectedRandom.length];
- int readLen = sftp.read(handle, 0L, actualRandom);
- assertEquals("Incomplete random data read",
expectedRandom.length, readLen);
- assertArrayEquals("Mismatched read random data",
expectedRandom, actualRandom);
-
- sftp.write(handle, 3777347L, expectedText);
- byte[] actualText = new byte[expectedText.length];
- readLen = sftp.read(handle, actualRandom.length, actualText);
- assertEquals("Incomplete text data read", actualText.length,
readLen);
- assertArrayEquals("Mismatched read text data", expectedText,
actualText);
- }
+ String file =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile);
+ try (SftpClient sftp = createSingleSessionClient();
+ CloseableHandle handle = sftp.open(
+ file, OpenMode.Create, OpenMode.Write, OpenMode.Read,
OpenMode.Append)) {
+ sftp.write(handle, 7365L, expectedRandom);
+ byte[] actualRandom = new byte[expectedRandom.length];
+ int readLen = sftp.read(handle, 0L, actualRandom);
+ assertEquals("Incomplete random data read", expectedRandom.length,
readLen);
+ assertArrayEquals("Mismatched read random data", expectedRandom,
actualRandom);
+
+ sftp.write(handle, 3777347L, expectedText);
+ byte[] actualText = new byte[expectedText.length];
+ readLen = sftp.read(handle, actualRandom.length, actualText);
+ assertEquals("Incomplete text data read", actualText.length,
readLen);
+ assertArrayEquals("Mismatched read text data", expectedText,
actualText);
}
byte[] actualBytes = Files.readAllBytes(testFile);
@@ -214,29 +211,27 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
rnd.fill(expected);
Files.write(testFile, expected);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
- String file =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile);
- byte[] actual = new byte[expected.length];
- int maxAllowed = actual.length / 4;
- // allow less than actual
- SftpModuleProperties.MAX_READDATA_PACKET_LENGTH.set(sshd,
maxAllowed);
- try (CloseableHandle handle = sftp.open(file, OpenMode.Read)) {
- int readLen = sftp.read(handle, 0L, actual);
- assertEquals("Mismatched read len", maxAllowed, readLen);
-
- for (int index = 0; index < readLen; index++) {
- byte expByte = expected[index];
- byte actByte = actual[index];
- if (expByte != actByte) {
- fail("Mismatched values at index=" + index
- + ": expected=0x" + Integer.toHexString(expByte &
0xFF)
- + ", actual=0x" + Integer.toHexString(actByte &
0xFF));
- }
+ String file =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile);
+ byte[] actual = new byte[expected.length];
+ int maxAllowed = actual.length / 4;
+ // allow less than actual
+ SftpModuleProperties.MAX_READDATA_PACKET_LENGTH.set(sshd, maxAllowed);
+ try (SftpClient sftp = createSingleSessionClient();
+ CloseableHandle handle = sftp.open(file, OpenMode.Read)) {
+ int readLen = sftp.read(handle, 0L, actual);
+ assertEquals("Mismatched read len", maxAllowed, readLen);
+
+ for (int index = 0; index < readLen; index++) {
+ byte expByte = expected[index];
+ byte actByte = actual[index];
+ if (expByte != actByte) {
+ fail("Mismatched values at index=" + index
+ + ": expected=0x" + Integer.toHexString(expByte &
0xFF)
+ + ", actual=0x" + Integer.toHexString(actByte &
0xFF));
}
- } finally {
- SftpModuleProperties.MAX_READDATA_PACKET_LENGTH.remove(sshd);
}
+ } finally {
+ SftpModuleProperties.MAX_READDATA_PACKET_LENGTH.remove(sshd);
}
}
@@ -256,8 +251,7 @@ public class SftpTest extends AbstractSftpClientTestSupport
{
}
});
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
String rootDir = sftp.canonicalPath("/");
String upDir = sftp.canonicalPath(rootDir + "/..");
assertEquals("Mismatched root dir parent", rootDir, upDir);
@@ -281,39 +275,36 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
lclSftp = assertHierarchyTargetFolderExists(lclSftp);
sshd.setFileSystemFactory(new VirtualFileSystemFactory(lclSftp));
- try (ClientSession session = createAuthenticatedClientSession()) {
- String escapePath;
- if (useAbsolutePath) {
- escapePath = targetPath.toString();
- if (OsUtils.isWin32()) {
- escapePath = "/" + escapePath.replace(File.separatorChar,
'/');
- }
- } else {
- Path parent = lclSftp.getParent();
- Path forbidden =
Files.createDirectories(parent.resolve("forbidden"));
- escapePath = "../" + forbidden.getFileName();
+ String escapePath;
+ if (useAbsolutePath) {
+ escapePath = targetPath.toString();
+ if (OsUtils.isWin32()) {
+ escapePath = "/" + escapePath.replace(File.separatorChar, '/');
}
+ } else {
+ Path parent = lclSftp.getParent();
+ Path forbidden =
Files.createDirectories(parent.resolve("forbidden"));
+ escapePath = "../" + forbidden.getFileName();
+ }
- try (SftpClient sftp = createSftpClient(session)) {
- SftpClient.Attributes attrs = sftp.stat(escapePath);
- fail("Unexpected escape success for path=" + escapePath + ": "
+ attrs);
- } catch (SftpException e) {
- int expected = OsUtils.isWin32() || (!useAbsolutePath)
- ? SftpConstants.SSH_FX_INVALID_FILENAME
- : SftpConstants.SSH_FX_NO_SUCH_FILE;
- assertEquals("Mismatched status for " + escapePath,
- SftpConstants.getStatusName(expected),
- SftpConstants.getStatusName(e.getStatus()));
- }
+ try (SftpClient sftp = createSingleSessionClient()) {
+ SftpClient.Attributes attrs = sftp.stat(escapePath);
+ fail("Unexpected escape success for path=" + escapePath + ": " +
attrs);
+ } catch (SftpException e) {
+ int expected = OsUtils.isWin32() || (!useAbsolutePath)
+ ? SftpConstants.SSH_FX_INVALID_FILENAME
+ : SftpConstants.SSH_FX_NO_SUCH_FILE;
+ assertEquals("Mismatched status for " + escapePath,
+ SftpConstants.getStatusName(expected),
+ SftpConstants.getStatusName(e.getStatus()));
}
}
@Test
public void testNormalizeRemoteRootValues() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
- StringBuilder sb = new StringBuilder(Long.SIZE + 1);
+ try (SftpClient sftp = createSingleSessionClient()) {
String expected = sftp.canonicalPath("/");
+ StringBuilder sb = new StringBuilder(Long.SIZE + 1);
for (int i = 0; i < Long.SIZE; i++) {
if (sb.length() > 0) {
sb.setLength(0);
@@ -342,8 +333,7 @@ public class SftpTest extends AbstractSftpClientTestSupport
{
Factory<? extends Random> factory = client.getRandomFactory();
Random rnd = factory.create();
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
StringBuilder sb = new StringBuilder(file.length() + comps.length);
String expected = sftp.canonicalPath(file);
for (int i = 0; i < file.length(); i++) {
@@ -392,86 +382,83 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
File javaFile = testFile.toFile();
assertHierarchyTargetFolderExists(javaFile.getParentFile());
- try (ClientSession session = createAuthenticatedClientSession()) {
- javaFile.createNewFile();
- javaFile.setWritable(false, false);
- javaFile.setReadable(false, false);
+ javaFile.createNewFile();
+ javaFile.setWritable(false, false);
+ javaFile.setReadable(false, false);
+ try (SftpClient sftp = createSingleSessionClient()) {
+ boolean isWindows = OsUtils.isWin32();
- try (SftpClient sftp = createSftpClient(session)) {
- boolean isWindows = OsUtils.isWin32();
-
- try (SftpClient.CloseableHandle h = sftp.open(file /* no mode
== read */)) {
- // NOTE: on Windows files are always readable
- // see
https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/
- //
luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
- assertTrue("Empty read should have failed on " + file,
isWindows);
- } catch (IOException e) {
- if (isWindows) {
- throw e;
- }
- }
-
- try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
- fail("Empty write should have failed on " + file);
- } catch (IOException e) {
- // ok
+ try (SftpClient.CloseableHandle h = sftp.open(file /* no mode ==
read */)) {
+ // NOTE: on Windows files are always readable
+ // see
https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/
+ //
luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
+ assertTrue("Empty read should have failed on " + file,
isWindows);
+ } catch (IOException e) {
+ if (isWindows) {
+ throw e;
}
+ }
- try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Truncate))) {
- // NOTE: on Windows files are always readable
- assertTrue("Empty truncate should have failed on " + file,
isWindows);
- } catch (IOException e) {
- // ok
- }
+ try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
+ fail("Empty write should have failed on " + file);
+ } catch (IOException e) {
+ // ok
+ }
+ try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Truncate))) {
// NOTE: on Windows files are always readable
- int perms = sftp.stat(file).getPermissions();
- int readMask = isWindows ? 0 : SftpConstants.S_IRUSR;
- int permsMask = SftpConstants.S_IWUSR | readMask;
- assertEquals("Mismatched permissions for " + file + ": 0x" +
Integer.toHexString(perms), 0, perms & permsMask);
+ assertTrue("Empty truncate should have failed on " + file,
isWindows);
+ } catch (IOException e) {
+ // ok
+ }
- javaFile.setWritable(true, false);
+ // NOTE: on Windows files are always readable
+ int perms = sftp.stat(file).getPermissions();
+ int readMask = isWindows ? 0 : SftpConstants.S_IRUSR;
+ int permsMask = SftpConstants.S_IWUSR | readMask;
+ assertEquals("Mismatched permissions for " + file + ": 0x" +
Integer.toHexString(perms), 0, perms & permsMask);
- try (SftpClient.CloseableHandle h = sftp.open(
- file, EnumSet.of(SftpClient.OpenMode.Truncate,
SftpClient.OpenMode.Write))) {
- // OK should succeed
- assertTrue("Handle not marked as open for file=" + file,
h.isOpen());
- }
+ javaFile.setWritable(true, false);
- byte[] d = "0123456789\n".getBytes(StandardCharsets.UTF_8);
- try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
- sftp.write(h, 0, d, 0, d.length);
- sftp.write(h, d.length, d, 0, d.length);
- }
+ try (SftpClient.CloseableHandle h = sftp.open(
+ file, EnumSet.of(SftpClient.OpenMode.Truncate,
SftpClient.OpenMode.Write))) {
+ // OK should succeed
+ assertTrue("Handle not marked as open for file=" + file,
h.isOpen());
+ }
- try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
- sftp.write(h, d.length * 2, d, 0, d.length);
- }
+ byte[] d = "0123456789\n".getBytes(StandardCharsets.UTF_8);
+ try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
+ sftp.write(h, 0, d, 0, d.length);
+ sftp.write(h, d.length, d, 0, d.length);
+ }
- try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
- byte[] overwrite = "-".getBytes(StandardCharsets.UTF_8);
- sftp.write(h, 3L, overwrite, 0, 1);
- d[3] = overwrite[0];
- }
+ try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
+ sftp.write(h, d.length * 2, d, 0, d.length);
+ }
- try (SftpClient.CloseableHandle h = sftp.open(file /* no mode
== read */)) {
- // NOTE: on Windows files are always readable
- assertTrue("Data read should have failed on " + file,
isWindows);
- } catch (IOException e) {
- if (isWindows) {
- throw e;
- }
+ try (SftpClient.CloseableHandle h = sftp.open(file,
EnumSet.of(SftpClient.OpenMode.Write))) {
+ byte[] overwrite = "-".getBytes(StandardCharsets.UTF_8);
+ sftp.write(h, 3L, overwrite, 0, 1);
+ d[3] = overwrite[0];
+ }
+
+ try (SftpClient.CloseableHandle h = sftp.open(file /* no mode ==
read */)) {
+ // NOTE: on Windows files are always readable
+ assertTrue("Data read should have failed on " + file,
isWindows);
+ } catch (IOException e) {
+ if (isWindows) {
+ throw e;
}
+ }
- javaFile.setReadable(true, false);
+ javaFile.setReadable(true, false);
- byte[] buf = new byte[3];
- try (SftpClient.CloseableHandle h = sftp.open(file /* no mode
== read */)) {
- int l = sftp.read(h, 2L, buf, 0, buf.length);
- String expected = new String(d, 2, l,
StandardCharsets.UTF_8);
- String actual = new String(buf, 0, l,
StandardCharsets.UTF_8);
- assertEquals("Mismatched read data", expected, actual);
- }
+ byte[] buf = new byte[3];
+ try (SftpClient.CloseableHandle h = sftp.open(file /* no mode ==
read */)) {
+ int l = sftp.read(h, 2L, buf, 0, buf.length);
+ String expected = new String(d, 2, l, StandardCharsets.UTF_8);
+ String actual = new String(buf, 0, l, StandardCharsets.UTF_8);
+ assertEquals("Mismatched read data", expected, actual);
}
}
}
@@ -487,28 +474,26 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
String file =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile);
assertHierarchyTargetFolderExists(testFile.getParent());
- try (ClientSession session = createAuthenticatedClientSession()) {
- Files.deleteIfExists(testFile); // make sure starting fresh
- Files.createFile(testFile, IoUtils.EMPTY_FILE_ATTRIBUTES);
+ Files.deleteIfExists(testFile); // make sure starting fresh
+ Files.createFile(testFile, IoUtils.EMPTY_FILE_ATTRIBUTES);
- try (SftpClient sftp = createSftpClient(session)) {
- Collection<PosixFilePermission> initialPermissions =
IoUtils.getPermissions(testFile);
- assertTrue("File does not have enough initial permissions: " +
initialPermissions,
- initialPermissions.containsAll(
- EnumSet.of(PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE)));
+ try (SftpClient sftp = createSingleSessionClient()) {
+ Collection<PosixFilePermission> initialPermissions =
IoUtils.getPermissions(testFile);
+ assertTrue("File does not have enough initial permissions: " +
initialPermissions,
+ initialPermissions.containsAll(
+ EnumSet.of(PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE)));
- try (CloseableHandle handle = sendRawAttributeImpactOpen(file,
sftp)) {
- outputDebugMessage("%s - handle=%s", getCurrentTestName(),
handle);
- }
-
- Collection<PosixFilePermission> updatedPermissions =
IoUtils.getPermissions(testFile);
- assertEquals("Mismatched updated permissions count",
initialPermissions.size(), updatedPermissions.size());
- assertTrue("File does not preserve initial permissions:
expected=" + initialPermissions + ", actual="
- + updatedPermissions,
- updatedPermissions.containsAll(initialPermissions));
- } finally {
- Files.delete(testFile);
+ try (CloseableHandle handle = sendRawAttributeImpactOpen(file,
sftp)) {
+ outputDebugMessage("%s - handle=%s", getCurrentTestName(),
handle);
}
+
+ Collection<PosixFilePermission> updatedPermissions =
IoUtils.getPermissions(testFile);
+ assertEquals("Mismatched updated permissions count",
initialPermissions.size(), updatedPermissions.size());
+ assertTrue("File does not preserve initial permissions: expected="
+ initialPermissions + ", actual="
+ + updatedPermissions,
+ updatedPermissions.containsAll(initialPermissions));
+ } finally {
+ Files.delete(testFile);
}
}
@@ -552,8 +537,7 @@ public class SftpTest extends AbstractSftpClientTestSupport
{
byte[] data
= (getClass().getName() + "#" + getCurrentTestName() + "[" +
localFile + "]").getBytes(StandardCharsets.UTF_8);
Files.write(localFile, data, StandardOpenOption.CREATE);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session);
+ try (SftpClient sftp = createSingleSessionClient();
InputStream stream = sftp.read(
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, localFile),
OpenMode.Read)) {
byte[] expected = new byte[data.length / 4];
@@ -626,8 +610,7 @@ public class SftpTest extends AbstractSftpClientTestSupport
{
byte[] expected = (getClass().getName() + "#" +
getCurrentTestName() + "[" + localFile + "]")
.getBytes(StandardCharsets.UTF_8);
Files.write(localFile, expected, StandardOpenOption.CREATE);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
byte[] actual = new byte[expected.length];
try (InputStream stream = sftp.read(
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, localFile),
OpenMode.Read)) {
@@ -865,8 +848,7 @@ public class SftpTest extends AbstractSftpClientTestSupport
{
};
factory.addSftpEventListener(listener);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
assertEquals("Mismatched negotiated version", sftp.getVersion(),
versionHolder.get());
testClient(client, sftp);
@@ -895,51 +877,49 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
*/
@Test
public void testWriteChunking() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession()) {
- Path targetPath = detectTargetFolder();
- Path lclSftp = CommonTestSupportUtils.resolve(
- targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME,
getClass().getSimpleName(), getCurrentTestName());
- CommonTestSupportUtils.deleteRecursive(lclSftp);
+ Path targetPath = detectTargetFolder();
+ Path lclSftp = CommonTestSupportUtils.resolve(
+ targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME,
getClass().getSimpleName(), getCurrentTestName());
+ CommonTestSupportUtils.deleteRecursive(lclSftp);
- Path parentPath = targetPath.getParent();
- Path clientFolder =
assertHierarchyTargetFolderExists(lclSftp).resolve("client");
- String dir =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder);
+ Path parentPath = targetPath.getParent();
+ Path clientFolder =
assertHierarchyTargetFolderExists(lclSftp).resolve("client");
+ String dir =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder);
- try (SftpClient sftp = createSftpClient(session)) {
- sftp.mkdir(dir);
-
- uploadAndVerifyFile(sftp, clientFolder, dir, 0,
"emptyFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir, 1000,
"smallFile.txt");
-
- // Make sure sizes should invoke our internal chunking
mechanism
- ClientChannel clientChannel = sftp.getClientChannel();
- SftpModuleProperties.WRITE_CHUNK_SIZE.set(clientChannel,
- Math.min(SftpClient.IO_BUFFER_SIZE,
SftpModuleProperties.WRITE_CHUNK_SIZE.getRequiredDefault())
- -
Byte.MAX_VALUE);
-
- uploadAndVerifyFile(sftp, clientFolder, dir,
- SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT
- 1, "bufferMaxLenMinusOneFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir,
- SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT,
"bufferMaxLenFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir,
- SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT
+ 1, "bufferMaxLenPlusOneFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir,
- (int) (1.5 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT),
"1point5BufferMaxLenFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir,
- (2 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) - 1,
"2TimesBufferMaxLenMinusOneFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir,
- 2 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT,
"2TimesBufferMaxLenFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir,
- (2 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) + 1,
"2TimesBufferMaxLenPlusOneFile.txt");
- uploadAndVerifyFile(sftp, clientFolder, dir, 200000,
"largerFile.txt");
-
- // test erroneous calls that check for negative values
- Path invalidPath = clientFolder.resolve(getCurrentTestName() +
"-invalid");
- testInvalidParams(sftp, invalidPath,
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, invalidPath));
-
- // cleanup
- sftp.rmdir(dir);
- }
+ try (SftpClient sftp = createSingleSessionClient()) {
+ sftp.mkdir(dir);
+
+ uploadAndVerifyFile(sftp, clientFolder, dir, 0, "emptyFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir, 1000,
"smallFile.txt");
+
+ // Make sure sizes should invoke our internal chunking mechanism
+ ClientChannel clientChannel = sftp.getClientChannel();
+ SftpModuleProperties.WRITE_CHUNK_SIZE.set(clientChannel,
+ Math.min(SftpClient.IO_BUFFER_SIZE,
SftpModuleProperties.WRITE_CHUNK_SIZE.getRequiredDefault())
+ -
Byte.MAX_VALUE);
+
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT - 1,
"bufferMaxLenMinusOneFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT,
"bufferMaxLenFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT + 1,
"bufferMaxLenPlusOneFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ (int) (1.5 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT),
"1point5BufferMaxLenFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ (2 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) - 1,
"2TimesBufferMaxLenMinusOneFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ 2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT,
"2TimesBufferMaxLenFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir,
+ (2 *
SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) + 1,
"2TimesBufferMaxLenPlusOneFile.txt");
+ uploadAndVerifyFile(sftp, clientFolder, dir, 200000,
"largerFile.txt");
+
+ // test erroneous calls that check for negative values
+ Path invalidPath = clientFolder.resolve(getCurrentTestName() +
"-invalid");
+ testInvalidParams(sftp, invalidPath,
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, invalidPath));
+
+ // cleanup
+ sftp.rmdir(dir);
}
}
@@ -1125,8 +1105,7 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
Path parentPath = targetPath.getParent();
Path clientFolder =
assertHierarchyTargetFolderExists(lclSftp.resolve("client"));
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
Path file1 = clientFolder.resolve("file-1.txt");
String file1Path =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, file1);
try (OutputStream os = sftp.write(file1Path,
SftpClient.MIN_WRITE_BUFFER_SIZE)) {
@@ -1163,8 +1142,7 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
@Test
public void testServerExtensionsDeclarations() throws Exception {
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
Map<String, byte[]> extensions = sftp.getServerExtensions();
for (String name : new String[] {
SftpConstants.EXT_NEWLINE, SftpConstants.EXT_VERSIONS,
@@ -1497,8 +1475,7 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
@Test // see SSHD-903
public void testForcedVersionNegotiation() throws Exception {
SftpModuleProperties.SFTP_VERSION.set(sshd, SftpConstants.SFTP_V3);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
assertEquals("Mismatched negotiated version",
SftpConstants.SFTP_V3, sftp.getVersion());
}
}
@@ -1547,8 +1524,7 @@ public class SftpTest extends
AbstractSftpClientTestSupport {
Path parentPath = targetPath.getParent();
Path clientFolder =
assertHierarchyTargetFolderExists(lclSftp.resolve("client"));
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
Path file = clientFolder.resolve("file.txt");
String filePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, file);
try (OutputStream os = sftp.write(filePath,
SftpClient.MIN_WRITE_BUFFER_SIZE)) {
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java
index 3aaae5b..cea742a 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java
@@ -21,7 +21,6 @@ package org.apache.sshd.sftp.client.extensions;
import java.io.IOException;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -41,14 +40,13 @@ public class UnsupportedExtensionTest extends
AbstractSftpClientTestSupport {
@Test // see SSHD-890
public void testUnsupportedExtension() throws IOException {
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftpClient = createSftpClient(session)) {
+ try (SftpClient sftpClient = createSingleSessionClient()) {
+ RawSftpClient sftp = assertObjectInstanceOf("Not a raw SFTP
client", RawSftpClient.class, sftpClient);
+
String opcode = getCurrentTestName();
Buffer buffer = new ByteArrayBuffer(Integer.BYTES +
GenericUtils.length(opcode) + Byte.SIZE, false);
buffer.putString(opcode);
- assertObjectInstanceOf("Not a raw SFTP client",
RawSftpClient.class, sftpClient);
- RawSftpClient sftp = (RawSftpClient) sftpClient;
int cmd = sftp.send(SftpConstants.SSH_FXP_EXTENDED, buffer);
Buffer responseBuffer = sftp.receive(cmd);
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractCheckFileExtensionTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractCheckFileExtensionTest.java
index af7b3ec..b192122 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractCheckFileExtensionTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractCheckFileExtensionTest.java
@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.digest.BuiltinDigests;
@@ -175,8 +174,7 @@ public class AbstractCheckFileExtensionTest extends
AbstractSftpClientTestSuppor
Path parentPath = targetPath.getParent();
String srcPath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, srcFile);
String srcFolder =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath,
srcFile.getParent());
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
CheckFileNameExtension file = assertExtensionCreated(sftp,
CheckFileNameExtension.class);
try {
Map.Entry<String, ?> result = file.checkFileName(srcFolder,
algorithms, 0L, 0L, hashBlockSize);
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractMD5HashExtensionTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractMD5HashExtensionTest.java
index aa70070..460fc20 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractMD5HashExtensionTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/AbstractMD5HashExtensionTest.java
@@ -29,7 +29,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.digest.BuiltinDigests;
import org.apache.sshd.common.digest.Digest;
import org.apache.sshd.common.util.GenericUtils;
@@ -133,8 +132,7 @@ public class AbstractMD5HashExtensionTest extends
AbstractSftpClientTestSupport
Path parentPath = targetPath.getParent();
String srcPath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, srcFile);
String srcFolder =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath,
srcFile.getParent());
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
MD5FileExtension file = assertExtensionCreated(sftp,
MD5FileExtension.class);
try {
byte[] actual = file.getHash(srcFolder, 0L, 0L, quickHash);
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyDataExtensionImplTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyDataExtensionImplTest.java
index 8301d3c..e24458d 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyDataExtensionImplTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyDataExtensionImplTest.java
@@ -33,7 +33,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.Factory;
import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.util.io.IoUtils;
@@ -159,8 +158,7 @@ public class CopyDataExtensionImplTest extends
AbstractSftpClientTestSupport {
}
}
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
CopyDataExtension ext = assertExtensionCreated(sftp,
CopyDataExtension.class);
try (CloseableHandle readHandle = sftp.open(srcPath,
SftpClient.OpenMode.Read);
CloseableHandle writeHandle = sftp.open(dstPath,
SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyFileExtensionImplTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyFileExtensionImplTest.java
index 08dbe67..f2e5dd3 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyFileExtensionImplTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/CopyFileExtensionImplTest.java
@@ -25,7 +25,6 @@ import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
import org.apache.sshd.sftp.client.SftpClient;
@@ -71,8 +70,7 @@ public class CopyFileExtensionImplTest extends
AbstractSftpClientTestSupport {
LinkOption[] options = IoUtils.getLinkOptions(true);
assertFalse("Destination file unexpectedly exists",
Files.exists(dstFile, options));
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
CopyFileExtension ext = assertExtensionCreated(sftp,
CopyFileExtension.class);
ext.copyFile(srcPath, dstPath, false);
assertTrue("Source file not preserved", Files.exists(srcFile,
options));
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/SpaceAvailableExtensionImplTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/SpaceAvailableExtensionImplTest.java
index 1158c09..a18f17e 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/SpaceAvailableExtensionImplTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/helpers/SpaceAvailableExtensionImplTest.java
@@ -27,7 +27,6 @@ import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.subsystem.SubsystemFactory;
@@ -88,8 +87,7 @@ public class SpaceAvailableExtensionImplTest extends
AbstractSftpClientTestSuppo
}
}));
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
SpaceAvailableExtension ext = assertExtensionCreated(sftp,
SpaceAvailableExtension.class);
SpaceAvailableExtensionInfo actual = ext.available(queryPath);
assertEquals("Mismatched information", expected, actual);
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/openssh/helpers/OpenSSHExtensionsTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/openssh/helpers/OpenSSHExtensionsTest.java
index 639ff89..d0ba605 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/openssh/helpers/OpenSSHExtensionsTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/openssh/helpers/OpenSSHExtensionsTest.java
@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.io.IoUtils;
@@ -81,8 +80,7 @@ public class OpenSSHExtensionsTest extends
AbstractSftpClientTestSupport {
Path parentPath = targetPath.getParent();
String srcPath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, srcFile);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
OpenSSHFsyncExtension fsync = assertExtensionCreated(sftp,
OpenSSHFsyncExtension.class);
try (CloseableHandle fileHandle = sftp.open(srcPath,
SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
sftp.write(fileHandle, 0L, expected);
@@ -164,8 +162,7 @@ public class OpenSSHExtensionsTest extends
AbstractSftpClientTestSupport {
}
}));
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
OpenSSHStatPathExtension pathStat = assertExtensionCreated(sftp,
OpenSSHStatPathExtension.class);
OpenSSHStatExtensionInfo actual = pathStat.stat(srcPath);
String invokedExtension = extensionHolder.getAndSet(null);
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
index d238ddc..12ee16b 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.io.DirectoryScanner;
import org.apache.sshd.common.util.io.PathUtils;
import org.apache.sshd.sftp.client.SftpClient;
@@ -96,8 +95,7 @@ public class SftpDirectoryScannersTest extends
AbstractSftpFilesSystemSupport {
List<Path> expected = setup.getExpected();
String remRoot = setup.getRemoteFilePath();
List<ScanDirEntry> actual;
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
+ try (SftpClient sftp = createSingleSessionClient()) {
SftpClientDirectoryScanner ds = new
SftpClientDirectoryScanner(remRoot, pattern);
actual = ds.scan(sftp, () -> new ArrayList<>(expected.size()));
}
diff --git
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
index a2d52ec..f1aa19e 100644
---
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
+++
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
@@ -30,7 +30,6 @@ import java.nio.file.StandardOpenOption;
import java.util.Date;
import java.util.EnumSet;
-import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.sftp.SftpModuleProperties;
import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
import org.apache.sshd.sftp.client.SftpClient;
@@ -66,25 +65,23 @@ public class SftpRemotePathChannelTest extends
AbstractSftpClientTestSupport {
byte[] expected
= (getClass().getName() + "#" + getCurrentTestName() + "(" +
new Date() + ")").getBytes(StandardCharsets.UTF_8);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session)) {
- Path parentPath = targetPath.getParent();
- String remFilePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, lclFile);
-
- try (FileChannel fc = sftp.openRemotePathChannel(
- remFilePath, EnumSet.of(
- StandardOpenOption.CREATE,
StandardOpenOption.READ, StandardOpenOption.WRITE))) {
- int writeLen = fc.write(ByteBuffer.wrap(expected));
- assertEquals("Mismatched written length", expected.length,
writeLen);
-
- FileChannel fcPos = fc.position(0L);
- assertSame("Mismatched positioned file channel", fc, fcPos);
-
- byte[] actual = new byte[expected.length];
- int readLen = fc.read(ByteBuffer.wrap(actual));
- assertEquals("Mismatched read len", writeLen, readLen);
- assertArrayEquals("Mismatched read data", expected, actual);
- }
+ Path parentPath = targetPath.getParent();
+ String remFilePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, lclFile);
+
+ try (SftpClient sftp = createSingleSessionClient();
+ FileChannel fc = sftp.openRemotePathChannel(
+ remFilePath, EnumSet.of(
+ StandardOpenOption.CREATE,
StandardOpenOption.READ, StandardOpenOption.WRITE))) {
+ int writeLen = fc.write(ByteBuffer.wrap(expected));
+ assertEquals("Mismatched written length", expected.length,
writeLen);
+
+ FileChannel fcPos = fc.position(0L);
+ assertSame("Mismatched positioned file channel", fc, fcPos);
+
+ byte[] actual = new byte[expected.length];
+ int readLen = fc.read(ByteBuffer.wrap(actual));
+ assertEquals("Mismatched read len", writeLen, readLen);
+ assertArrayEquals("Mismatched read data", expected, actual);
}
byte[] actual = Files.readAllBytes(lclFile);
@@ -114,8 +111,7 @@ public class SftpRemotePathChannelTest extends
AbstractSftpClientTestSupport {
Files.deleteIfExists(dstFile);
String remFilePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, srcFile);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session);
+ try (SftpClient sftp = createSingleSessionClient();
FileChannel srcChannel = sftp.openRemotePathChannel(
remFilePath, EnumSet.of(StandardOpenOption.READ));
FileChannel dstChannel = FileChannel.open(dstFile,
@@ -148,8 +144,7 @@ public class SftpRemotePathChannelTest extends
AbstractSftpClientTestSupport {
Files.deleteIfExists(dstFile);
String remFilePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, srcFile);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session);
+ try (SftpClient sftp = createSingleSessionClient();
FileChannel srcChannel = sftp.openRemotePathChannel(
remFilePath, EnumSet.of(StandardOpenOption.READ));
FileChannel dstChannel = FileChannel.open(dstFile,
@@ -188,8 +183,7 @@ public class SftpRemotePathChannelTest extends
AbstractSftpClientTestSupport {
Files.deleteIfExists(dstFile);
String remFilePath =
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, dstFile);
- try (ClientSession session = createAuthenticatedClientSession();
- SftpClient sftp = createSftpClient(session);
+ try (SftpClient sftp = createSingleSessionClient();
FileChannel dstChannel = sftp.openRemotePathChannel(
remFilePath, EnumSet.of(StandardOpenOption.CREATE,
StandardOpenOption.WRITE));
FileChannel srcChannel = FileChannel.open(srcFile,
StandardOpenOption.READ)) {