From f5c26d11191eb7609505673d220c643069b30f01 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 9 Jan 2025 09:42:52 +0100 Subject: [PATCH 1/2] Make sure required feature is available regardless of connection state. --- .../ch/cyberduck/core/ftp/FTPReadFeature.java | 12 +++++----- .../ch/cyberduck/core/ftp/FTPSession.java | 23 +++++++------------ .../core/ftp/list/FTPListService.java | 22 ++++++++++++------ .../core/cryptomator/FTPListServiceTest.java | 7 ++---- .../core/cryptomator/FTPWriteFeatureTest.java | 3 +-- .../core/cryptomator/MoveWorkerTest.java | 5 ++-- .../core/ftp/FTPMFMTTimestampFeatureTest.java | 3 +-- .../ch/cyberduck/core/ftp/FTPSessionTest.java | 3 +-- .../ftp/FTPUnixPermissionFeatureTest.java | 3 +-- .../core/ftp/FTPWriteFeatureTest.java | 3 +-- .../core/ftp/list/FTPListServiceTest.java | 11 ++++----- 11 files changed, 43 insertions(+), 52 deletions(-) diff --git a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPReadFeature.java b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPReadFeature.java index 3cfa134ed28..a6cdc36fbf3 100644 --- a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPReadFeature.java +++ b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPReadFeature.java @@ -41,15 +41,15 @@ public class FTPReadFeature implements Read { /** * Server process supports RESTart in STREAM mode */ - private final boolean rest; + private final EnumSet flags = EnumSet.noneOf(Flags.class); public FTPReadFeature(final FTPSession session) { - this(session, true); + this.session = session; } - public FTPReadFeature(final FTPSession session, final boolean rest) { - this.session = session; - this.rest = rest; + public void configure(final EnumSet flags) { + this.flags.clear(); + this.flags.addAll(flags); } @Override @@ -81,7 +81,7 @@ public InputStream execute() throws BackgroundException { @Override public EnumSet features(final Path file) { - return rest ? EnumSet.of(Flags.offset) : EnumSet.noneOf(Flags.class); + return flags; } private final class ReadReplyInputStream extends ProxyInputStream { diff --git a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java index daf3b058d48..fc8ba25b6c0 100644 --- a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java +++ b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java @@ -35,7 +35,6 @@ import ch.cyberduck.core.ftp.list.FTPListService; import ch.cyberduck.core.idna.PunycodeConverter; import ch.cyberduck.core.preferences.HostPreferences; -import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.preferences.PreferencesReader; import ch.cyberduck.core.proxy.ProxyFinder; import ch.cyberduck.core.proxy.ProxySocketFactory; @@ -62,8 +61,8 @@ import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.time.Duration; +import java.util.EnumSet; import java.util.Locale; -import java.util.TimeZone; public class FTPSession extends SSLSession { private static final Logger log = LogManager.getLogger(FTPSession.class); @@ -71,11 +70,12 @@ public class FTPSession extends SSLSession { private final PreferencesReader preferences = new HostPreferences(host); - private Read read; + private final FTPListService list = new FTPListService(this); + private final FTPReadFeature read = new FTPReadFeature(this); + private Timestamp timestamp; private UnixPermission permission; private Symlink symlink; - private FTPListService listService; private Protocol.Case casesensitivity = Protocol.Case.sensitive; public FTPSession(final Host h) { @@ -246,14 +246,6 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } } } - final TimeZone zone; - if(null == host.getTimezone()) { - zone = TimeZone.getTimeZone(PreferencesFactory.get().getProperty("ftp.timezone.default")); - } - else { - zone = host.getTimezone(); - } - log.info("Reset parser to timezone {}", zone); String system = StringUtils.EMPTY; //Unknown try { system = client.getSystemType(); @@ -264,8 +256,9 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw catch(IOException e) { log.warn("SYST command failed {}", e.getMessage()); } - read = new FTPReadFeature(this, client.hasFeature("REST", "STREAM")); - listService = new FTPListService(this, system, zone); + read.configure(client.hasFeature("REST", "STREAM") ? + EnumSet.of(Read.Flags.offset) : EnumSet.noneOf(Read.Flags.class)); + list.configure(system); if(client.hasFeature(FTPCmd.MFMT.getCommand())) { timestamp = new FTPMFMTTimestampFeature(this); } @@ -295,7 +288,7 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw @SuppressWarnings("unchecked") public T _getFeature(final Class type) { if(type == ListService.class) { - return (T) listService; + return (T) list; } if(type == Directory.class) { return (T) new FTPDirectoryFeature(this); diff --git a/ftp/src/main/java/ch/cyberduck/core/ftp/list/FTPListService.java b/ftp/src/main/java/ch/cyberduck/core/ftp/list/FTPListService.java index 55f96ee231d..53f48e5dce1 100644 --- a/ftp/src/main/java/ch/cyberduck/core/ftp/list/FTPListService.java +++ b/ftp/src/main/java/ch/cyberduck/core/ftp/list/FTPListService.java @@ -28,6 +28,7 @@ import ch.cyberduck.core.ftp.FTPSession; import ch.cyberduck.core.ftp.parser.CompositeFileEntryParser; import ch.cyberduck.core.preferences.HostPreferences; +import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.preferences.PreferencesReader; import org.apache.commons.lang3.StringUtils; @@ -91,28 +92,35 @@ public String toString() { } } - public FTPListService(final FTPSession session, final String system, final TimeZone zone) { + public FTPListService(final FTPSession session) { this.session = session; + this.configure(StringUtils.EMPTY); + } + + public void configure(final String system) { + implementations.clear(); // Directory listing parser depending on response for SYST command - final CompositeFileEntryParser parser = new FTPParserSelector().getParser(system, zone); - this.implementations.put(Command.list, new FTPDefaultListService(session, parser, Command.list)); + final TimeZone tz = null == session.getHost().getTimezone() ? TimeZone.getTimeZone(PreferencesFactory.get().getProperty("ftp.timezone.default")) : session.getHost().getTimezone(); + log.info("Reset parser to timezone {}", tz); + final CompositeFileEntryParser parser = new FTPParserSelector().getParser(system, tz); + implementations.put(Command.list, new FTPDefaultListService(session, parser, Command.list)); final PreferencesReader preferences = new HostPreferences(session.getHost()); if(preferences.getBoolean("ftp.command.stat")) { if(StringUtils.isNotBlank(system)) { if(!system.toUpperCase(Locale.ROOT).contains(FTPClientConfig.SYST_NT)) { // Workaround for #5572. - this.implementations.put(Command.stat, new FTPStatListService(session, parser)); + implementations.put(Command.stat, new FTPStatListService(session, parser)); } } else { - this.implementations.put(Command.stat, new FTPStatListService(session, parser)); + implementations.put(Command.stat, new FTPStatListService(session, parser)); } } if(preferences.getBoolean("ftp.command.mlsd")) { - this.implementations.put(Command.mlsd, new FTPMlsdListService(session)); + implementations.put(Command.mlsd, new FTPMlsdListService(session)); } if(preferences.getBoolean("ftp.command.lista")) { - this.implementations.put(Command.lista, new FTPDefaultListService(session, parser, Command.lista)); + implementations.put(Command.lista, new FTPDefaultListService(session, parser, Command.lista)); } } diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java index 31c98147755..73dbe912cf5 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java @@ -42,7 +42,6 @@ import java.util.Arrays; import java.util.EnumSet; -import java.util.TimeZone; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -59,12 +58,10 @@ public void testListCryptomator() throws Exception { final CryptoVault cryptomator = new CryptoVault(vault); cryptomator.create(session, new VaultCredentials("test"), vaultVersion); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordStore(), new DisabledPasswordCallback(), cryptomator)); - assertTrue(new CryptoListService(session, new FTPListService(session, null, - TimeZone.getDefault()), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); + assertTrue(new CryptoListService(session, new FTPListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); new CryptoTouchFeature<>(session, new DefaultTouchFeature<>(new FTPWriteFeature(session) ), new FTPWriteFeature(session), cryptomator).touch(test, new TransferStatus()); - assertEquals(test, new CryptoListService(session, new FTPListService(session, null, - TimeZone.getDefault()), cryptomator).list(vault, new DisabledListProgressListener()).get(0)); + assertEquals(test, new CryptoListService(session, new FTPListService(session), cryptomator).list(vault, new DisabledListProgressListener()).get(0)); cryptomator.getFeature(session, Delete.class, new FTPDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } } diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java index 4fd57c694b4..bd735f28bc6 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java @@ -57,7 +57,6 @@ import java.io.OutputStream; import java.util.Arrays; import java.util.EnumSet; -import java.util.TimeZone; import static org.junit.Assert.*; @@ -90,7 +89,7 @@ public void testWrite() throws Exception { assertEquals(TransferStatus.UNKNOWN_LENGTH, status.getResponse().getSize()); assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(test)); final PathAttributes attr = cryptomator.getFeature(session, AttributesFinder.class, new FTPAttributesFinderFeature(session)).find(test); - assertEquals(content.length, new CryptoListService(session, new FTPListService(session, null, TimeZone.getDefault()), cryptomator).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes().getSize()); + assertEquals(content.length, new CryptoListService(session, new FTPListService(session), cryptomator).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes().getSize()); final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); final InputStream in = new CryptoReadFeature(session, new FTPReadFeature(session), cryptomator).read(test, new TransferStatus(), new DisabledConnectionCallback()); new StreamCopier(status, status).transfer(in, buffer); diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 323be8fc40c..354c55e7064 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -58,7 +58,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; -import java.util.TimeZone; import java.util.UUID; import static org.junit.Assert.*; @@ -160,12 +159,12 @@ public void testMoveFolder() throws Exception { assertFalse(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(folder)); assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(folderRenamed)); try { - assertTrue(new CryptoListService(session, new FTPListService(session, null, TimeZone.getDefault()), cryptomator).list(folder, new DisabledListProgressListener()).isEmpty()); + assertTrue(new CryptoListService(session, new FTPListService(session), cryptomator).list(folder, new DisabledListProgressListener()).isEmpty()); } catch(NotfoundException e) { // } - assertEquals(1, new CryptoListService(session, new FTPListService(session, null, TimeZone.getDefault()), cryptomator).list(folderRenamed, new DisabledListProgressListener()).size()); + assertEquals(1, new CryptoListService(session, new FTPListService(session), cryptomator).list(folderRenamed, new DisabledListProgressListener()).size()); cryptomator.getFeature(session, Delete.class, new FTPDeleteFeature(session)).delete(Arrays.asList( new Path(folderRenamed, "f1", EnumSet.of(Path.Type.file)), folderRenamed), new DisabledLoginCallback(), new Delete.DisabledCallback()); } diff --git a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPMFMTTimestampFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPMFMTTimestampFeatureTest.java index 5f53bf7f279..f6d06da784d 100644 --- a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPMFMTTimestampFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPMFMTTimestampFeatureTest.java @@ -30,7 +30,6 @@ import java.util.Collections; import java.util.EnumSet; -import java.util.TimeZone; import java.util.UUID; import static org.junit.Assert.assertEquals; @@ -45,7 +44,7 @@ public void testSetTimestamp() throws Exception { final Path test = new Path(new FTPWorkdirService(session).find(), UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); new FTPTouchFeature(session).touch(test, new TransferStatus()); new FTPMFMTTimestampFeature(session).setTimestamp(test, modified); - assertEquals(modified / 1000 * 1000, new FTPListService(session, null, TimeZone.getDefault()).list(home, new DisabledListProgressListener()).get(test).attributes().getModificationDate()); + assertEquals(modified / 1000 * 1000, new FTPListService(session).list(home, new DisabledListProgressListener()).get(test).attributes().getModificationDate()); new FTPDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback()); } } diff --git a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPSessionTest.java b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPSessionTest.java index 429ab7765e2..12115522113 100644 --- a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPSessionTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPSessionTest.java @@ -30,7 +30,6 @@ import java.security.cert.X509Certificate; import java.util.Collections; import java.util.EnumSet; -import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -96,7 +95,7 @@ public void testTouch() throws Exception { @Test(expected = NotfoundException.class) public void testNotfound() throws Exception { - new FTPListService(session, null, TimeZone.getDefault()).list(new Path(UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)), new DisabledListProgressListener()); + new FTPListService(session).list(new Path(UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)), new DisabledListProgressListener()); } @Test diff --git a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPUnixPermissionFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPUnixPermissionFeatureTest.java index 3e6f44a9105..767ed3ffba5 100644 --- a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPUnixPermissionFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPUnixPermissionFeatureTest.java @@ -15,7 +15,6 @@ import java.util.Collections; import java.util.EnumSet; -import java.util.TimeZone; import java.util.UUID; import static org.junit.Assert.assertEquals; @@ -30,7 +29,7 @@ public void testSetUnixPermission() throws Exception { final Path test = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); new FTPTouchFeature(session).touch(test, new TransferStatus()); new FTPUnixPermissionFeature(session).setUnixPermission(test, new Permission(666)); - assertEquals("666", new FTPListService(session, null, TimeZone.getDefault()).list(home, new DisabledListProgressListener()).get(test).attributes().getPermission().getMode()); + assertEquals("666", new FTPListService(session).list(home, new DisabledListProgressListener()).get(test).attributes().getPermission().getMode()); new FTPDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback()); } } diff --git a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPWriteFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPWriteFeatureTest.java index d897f882ff9..bfc66afaddc 100644 --- a/ftp/src/test/java/ch/cyberduck/core/ftp/FTPWriteFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/ftp/FTPWriteFeatureTest.java @@ -29,7 +29,6 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.EnumSet; -import java.util.TimeZone; import java.util.UUID; import static org.junit.Assert.*; @@ -48,7 +47,7 @@ public void testReadWrite() throws Exception { new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), out); out.close(); assertTrue(session.getFeature(Find.class).find(test)); - final PathAttributes attributes = new FTPListService(session, null, TimeZone.getDefault()).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes(); + final PathAttributes attributes = new FTPListService(session).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes(); assertEquals(content.length, attributes.getSize()); { final InputStream in = new FTPReadFeature(session).read(test, new TransferStatus().withLength(content.length), new DisabledConnectionCallback()); diff --git a/ftp/src/test/java/ch/cyberduck/core/ftp/list/FTPListServiceTest.java b/ftp/src/test/java/ch/cyberduck/core/ftp/list/FTPListServiceTest.java index 8938ef4f97d..a07ae840951 100644 --- a/ftp/src/test/java/ch/cyberduck/core/ftp/list/FTPListServiceTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/ftp/list/FTPListServiceTest.java @@ -40,7 +40,6 @@ import java.net.SocketTimeoutException; import java.util.Collections; import java.util.EnumSet; -import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -51,7 +50,7 @@ public class FTPListServiceTest extends AbstractFTPTest { @Test public void testList() throws Exception { - final ListService service = new FTPListService(session, null, TimeZone.getDefault()); + final ListService service = new FTPListService(session); final Path directory = new FTPWorkdirService(session).find(); final Path file = new Path(directory, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); new FTPTouchFeature(session).touch(file, new TransferStatus()); @@ -67,7 +66,7 @@ public void chunk(final Path parent, AttributedList list) { @Test public void testListExtended() throws Exception { - final FTPListService service = new FTPListService(session, null, TimeZone.getDefault()); + final FTPListService service = new FTPListService(session); service.remove(FTPListService.Command.list); service.remove(FTPListService.Command.stat); service.remove(FTPListService.Command.mlsd); @@ -86,7 +85,7 @@ public void chunk(final Path parent, AttributedList list) { @Test public void testListEmptyDirectoryList() throws Exception { - final FTPListService list = new FTPListService(session, null, TimeZone.getDefault()); + final FTPListService list = new FTPListService(session); list.remove(FTPListService.Command.stat); list.remove(FTPListService.Command.lista); list.remove(FTPListService.Command.mlsd); @@ -107,7 +106,7 @@ public void chunk(final Path parent, final AttributedList list) { @Test(expected = ConnectionTimeoutException.class) public void testListIOFailureStat() throws Exception { - final FTPListService service = new FTPListService(session, null, TimeZone.getDefault()); + final FTPListService service = new FTPListService(session); service.remove(FTPListService.Command.lista); service.remove(FTPListService.Command.mlsd); final AtomicBoolean set = new AtomicBoolean(); @@ -128,7 +127,7 @@ public AttributedList list(final Path directory, final ListProgressListene @Test(expected = NotfoundException.class) public void testListNotfound() throws Exception { final Path f = new Path(UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); - final FTPListService service = new FTPListService(session, null, TimeZone.getDefault()); + final FTPListService service = new FTPListService(session); service.list(f, new DisabledListProgressListener()); } } From 1374aac7b794343ad21af7ed83cce2fdbd8636ee Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 9 Jan 2025 11:52:58 +0100 Subject: [PATCH 2/2] Obtain session from pool to return feature. --- .../ch/cyberduck/core/FeatureFactory.java | 28 +++++++++++ .../main/java/ch/cyberduck/core/Protocol.java | 3 +- .../main/java/ch/cyberduck/core/Session.java | 5 +- .../core/pool/DefaultSessionPool.java | 49 +++++++++---------- .../ch/cyberduck/core/pool/SessionPool.java | 6 ++- 5 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 core/src/main/java/ch/cyberduck/core/FeatureFactory.java diff --git a/core/src/main/java/ch/cyberduck/core/FeatureFactory.java b/core/src/main/java/ch/cyberduck/core/FeatureFactory.java new file mode 100644 index 00000000000..3c5fcd4c6c7 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/FeatureFactory.java @@ -0,0 +1,28 @@ +package ch.cyberduck.core; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +public interface FeatureFactory { + @SuppressWarnings("unchecked") + T getFeature(Class type); + + FeatureFactory disabled = new FeatureFactory() { + @Override + public T getFeature(final Class type) { + return null; + } + }; +} diff --git a/core/src/main/java/ch/cyberduck/core/Protocol.java b/core/src/main/java/ch/cyberduck/core/Protocol.java index 4d736dbb86a..5d3564b42f1 100644 --- a/core/src/main/java/ch/cyberduck/core/Protocol.java +++ b/core/src/main/java/ch/cyberduck/core/Protocol.java @@ -25,7 +25,7 @@ import java.util.Map; import java.util.Set; -public interface Protocol extends Comparable, Serializable { +public interface Protocol extends FeatureFactory, Comparable, Serializable { /** * Check login credentials for validity for this protocol. @@ -365,5 +365,6 @@ enum VersioningMode { } @SuppressWarnings("unchecked") + @Override T getFeature(final Class type); } diff --git a/core/src/main/java/ch/cyberduck/core/Session.java b/core/src/main/java/ch/cyberduck/core/Session.java index f784db5466f..86c82db4234 100644 --- a/core/src/main/java/ch/cyberduck/core/Session.java +++ b/core/src/main/java/ch/cyberduck/core/Session.java @@ -47,7 +47,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -public abstract class Session implements TranscriptListener { +public abstract class Session implements FeatureFactory, TranscriptListener { private static final Logger log = LogManager.getLogger(Session.class); /** @@ -255,8 +255,8 @@ public void log(final Type request, final String message) { * @return Feature implementation or null when not supported */ @SuppressWarnings("unchecked") + @Override public T getFeature(final Class type) { - metrics.increment(type); return this.getFeature(type, this._getFeature(type)); } @@ -269,6 +269,7 @@ public T getFeature(final Class type) { */ @SuppressWarnings("unchecked") public T getFeature(final Class type, final T feature) { + metrics.increment(type); return registry.getFeature(this, type, feature); } diff --git a/core/src/main/java/ch/cyberduck/core/pool/DefaultSessionPool.java b/core/src/main/java/ch/cyberduck/core/pool/DefaultSessionPool.java index 219980d5b8f..417b5f0e190 100644 --- a/core/src/main/java/ch/cyberduck/core/pool/DefaultSessionPool.java +++ b/core/src/main/java/ch/cyberduck/core/pool/DefaultSessionPool.java @@ -18,12 +18,9 @@ import ch.cyberduck.core.ConnectionService; import ch.cyberduck.core.Host; import ch.cyberduck.core.Session; -import ch.cyberduck.core.SessionFactory; import ch.cyberduck.core.TranscriptListener; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.ConnectionCanceledException; -import ch.cyberduck.core.ssl.DefaultX509KeyManager; -import ch.cyberduck.core.ssl.DisabledX509TrustManager; import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; import ch.cyberduck.core.threading.BackgroundActionState; @@ -53,7 +50,6 @@ public class DefaultSessionPool implements SessionPool { private final FailureDiagnostics diagnostics = new DefaultFailureDiagnostics(); - private final ConnectionService connect; private final TranscriptListener transcript; private final Host bookmark; @@ -61,29 +57,29 @@ public class DefaultSessionPool implements SessionPool { private final GenericObjectPool pool; - private SessionPool features = SessionPool.DISCONNECTED; + private static final GenericObjectPoolConfig configuration = new GenericObjectPoolConfig<>(); - public DefaultSessionPool(final ConnectionService connect, final X509TrustManager trust, final X509KeyManager key, - final VaultRegistry registry, final TranscriptListener transcript, - final Host bookmark) { - this.connect = connect; - this.registry = registry; - this.bookmark = bookmark; - this.transcript = transcript; - final GenericObjectPoolConfig configuration = new GenericObjectPoolConfig<>(); + static { configuration.setJmxEnabled(false); configuration.setEvictionPolicyClassName(CustomPoolEvictionPolicy.class.getName()); configuration.setBlockWhenExhausted(true); configuration.setMaxWait(Duration.ofMillis(BORROW_MAX_WAIT_INTERVAL)); - this.pool = new GenericObjectPool<>(new PooledSessionFactory(connect, trust, key, bookmark, registry), configuration); - final AbandonedConfig abandon = new AbandonedConfig(); + } + + private static final AbandonedConfig abandon = new AbandonedConfig(); + + { abandon.setUseUsageTracking(true); - this.pool.setAbandonedConfig(abandon); } - public DefaultSessionPool(final ConnectionService connect, final VaultRegistry registry, - final TranscriptListener transcript, final Host bookmark, final GenericObjectPool pool) { - this.connect = connect; + public DefaultSessionPool(final ConnectionService connect, final X509TrustManager trust, final X509KeyManager key, + final VaultRegistry registry, final TranscriptListener transcript, final Host bookmark) { + this(connect, registry, transcript, bookmark, + new GenericObjectPool<>(new PooledSessionFactory(connect, trust, key, bookmark, registry), configuration, abandon)); + } + + public DefaultSessionPool(final ConnectionService connect, final VaultRegistry registry, final TranscriptListener transcript, + final Host bookmark, final GenericObjectPool pool) { this.transcript = transcript; this.bookmark = bookmark; this.registry = registry; @@ -132,9 +128,6 @@ public Session borrow(final BackgroundActionState callback) throws Background log.info("Borrow session from pool {}", this); final Session session = pool.borrowObject(); log.info("Borrowed session {} from pool {}", session, this); - if(DISCONNECTED == features) { - features = new StatelessSessionPool(connect, session, transcript, registry); - } return session.withListener(transcript); } catch(IllegalStateException e) { @@ -259,10 +252,16 @@ public Session.State getState() { @Override public T getFeature(final Class type) { - if(DISCONNECTED == features) { - return SessionFactory.create(bookmark, new DisabledX509TrustManager(), new DefaultX509KeyManager()).getFeature(type); + try { + final Session session = this.borrow(BackgroundActionState.running); + final T feature = session.getFeature(type); + this.release(session, null); + return feature; + } + catch(BackgroundException e) { + log.warn("Failure {} obtaining feature from {}", e.toString(), this); + return null; } - return features.getFeature(type); } @Override diff --git a/core/src/main/java/ch/cyberduck/core/pool/SessionPool.java b/core/src/main/java/ch/cyberduck/core/pool/SessionPool.java index f1d27e0b46b..ed3cc1ec250 100644 --- a/core/src/main/java/ch/cyberduck/core/pool/SessionPool.java +++ b/core/src/main/java/ch/cyberduck/core/pool/SessionPool.java @@ -18,6 +18,7 @@ */ import ch.cyberduck.core.AbstractProtocol; +import ch.cyberduck.core.FeatureFactory; import ch.cyberduck.core.Host; import ch.cyberduck.core.Scheme; import ch.cyberduck.core.Session; @@ -27,7 +28,7 @@ import org.apache.commons.lang3.StringUtils; -public interface SessionPool { +public interface SessionPool extends FeatureFactory { SessionPool DISCONNECTED = new DisconnectedSessionPool(); /** @@ -70,6 +71,7 @@ public interface SessionPool { /** * Obtain feature from connection type */ + @Override T getFeature(final Class type); /** @@ -116,7 +118,7 @@ public Session.State getState() { @Override public T getFeature(final Class type) { - return null; + return FeatureFactory.disabled.getFeature(type); } @Override