From 1374aac7b794343ad21af7ed83cce2fdbd8636ee Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 9 Jan 2025 11:52:58 +0100 Subject: [PATCH] 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