From eb9624846e1bac79b1719fa8d557f89282991319 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 27 Dec 2022 16:09:32 +0100 Subject: [PATCH 1/2] [MRESOLVER-302] Introduce onSessionClose hooks That integrators must integrate, to provide onSessionClosed hooks functionality to any component requiring it. --- https://issues.apache.org/jira/browse/MRESOLVER-302 --- .../org/eclipse/aether/RepositorySystem.java | 35 ++++++++ .../impl/RepositorySystemLifecycle.java | 31 +++++++ .../impl/DefaultRepositorySystem.java | 21 +++++ .../DefaultRepositorySystemLifecycle.java | 85 +++++++++++++++++++ 4 files changed, 172 insertions(+) diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java index be186e875..6b028c7af 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java @@ -302,4 +302,39 @@ List newResolutionRepositories( RepositorySystemSession sessio * @since 1.9.0 */ void shutdown(); + + /** + * Registers the session for lifecycle tracking: it marks that the passed in session instance is about to start. + * After this call it is possible to register "on close" handlers using + * {@link #addOnSessionEndedHandle(RepositorySystemSession, Runnable)} method that will execute once + * {@link #sessionEnded(RepositorySystemSession)} method was invoked. + *

+ * Same session instance can be started only once. + * + * @param session the session that is about to start, never {@code null}. + * @since TBD + */ + void sessionStarted( RepositorySystemSession session ); + + /** + * Registers a handler to execute when this session ends. This method throws, if the passed in session instance + * was not passed to method {@link #sessionStarted(RepositorySystemSession)} beforehand. + * + * @param session the session for which the handler needs to be registered, never {@code null}. + * @param handler the handler, never {@code null}. + * @since TBD + */ + void addOnSessionEndedHandle( RepositorySystemSession session, Runnable handler ); + + /** + * Signals to repository system that passed in session ended, it will not be used anymore. Repository system + * will invoke the registered handlers for this session, if any. This method throws if the passed in session + * instance was not passed to method {@link #sessionStarted(RepositorySystemSession)} beforehand. + *

+ * Same session instance can be ended only once. + * + * @param session the session that just ended, never {@code null}. + * @since TBD + */ + void sessionEnded( RepositorySystemSession session ); } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java index 68fcf8147..57e8190a8 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java @@ -19,6 +19,8 @@ * under the License. */ +import org.eclipse.aether.RepositorySystemSession; + /** * Lifecycle managing component for repository system. * @@ -41,4 +43,33 @@ public interface RepositorySystemLifecycle * Throws if repository system is already shut down. */ void addOnSystemEndedHandler( Runnable handler ); + + /** + * Registers the session for lifecycle tracking: it marks that the passed in session instance is about to start. + *

+ * Same session instance can be started only once. + * + * @since TBD + */ + void sessionStarted( RepositorySystemSession session ); + + /** + * Signals that passed in session was ended, it will not be used anymore. Repository system + * will invoke the registered handlers for this session, if any. This method throws if the passed in session + * instance was not passed to method {@link #sessionStarted(RepositorySystemSession)} beforehand. + *

+ * Same session instance can be ended only once. + * + * @since TBD + */ + void sessionEnded( RepositorySystemSession session ); + + /** + * Registers an "on session end" handler. + *

+ * Throws if session was not passed to {@link #sessionStarted(RepositorySystemSession)} beforehand. + * + * @since TBD + */ + void addOnSessionEndedHandle( RepositorySystemSession session, Runnable handler ); } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java index 7a383bf59..f5160f151 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java @@ -503,6 +503,27 @@ public void shutdown() } } + @Override + public void sessionStarted( RepositorySystemSession session ) + { + validateSession( session ); + repositorySystemLifecycle.sessionStarted( session ); + } + + @Override + public void sessionEnded( RepositorySystemSession session ) + { + validateSession( session ); + repositorySystemLifecycle.sessionEnded( session ); + } + + @Override + public void addOnSessionEndedHandle( RepositorySystemSession session, Runnable handler ) + { + validateSession( session ); + repositorySystemLifecycle.addOnSessionEndedHandle( session, handler ); + } + private void validateSession( RepositorySystemSession session ) { requireNonNull( session, "repository system session cannot be null" ); diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java index 6aef7c0bc..4e8fa4641 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java @@ -24,10 +24,13 @@ import javax.inject.Singleton; import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.aether.MultiRuntimeException; +import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.RepositorySystemLifecycle; import static java.util.Objects.requireNonNull; @@ -40,15 +43,23 @@ public class DefaultRepositorySystemLifecycle implements RepositorySystemLifecycle { + private static final String LIFECYCLE_ID_KEY = DefaultRepositorySystemLifecycle.class + ".key"; + private final AtomicBoolean shutdown; private final CopyOnWriteArrayList onSystemEndedHandlers; + private final ConcurrentHashMap> onSessionEndedHandlers; + + private final AtomicInteger sessionIdCounter; + @Inject public DefaultRepositorySystemLifecycle() { this.shutdown = new AtomicBoolean( false ); this.onSystemEndedHandlers = new CopyOnWriteArrayList<>(); + this.onSessionEndedHandlers = new ConcurrentHashMap<>(); + this.sessionIdCounter = new AtomicInteger( 0 ); } @Override @@ -80,6 +91,72 @@ public void addOnSystemEndedHandler( Runnable handler ) onSystemEndedHandlers.add( 0, handler ); } + @Override + public void sessionStarted( RepositorySystemSession session ) + { + requireNonNull( session, "session cannot be null" ); + requireNotShutdown(); + String sessionId = sessionId( session ); + onSessionEndedHandlers.compute( sessionId, ( k, v ) -> + { + if ( v != null ) + { + throw new IllegalStateException( "session instance already registered" ); + } + return new CopyOnWriteArrayList<>(); + } ); + } + + @Override + public void sessionEnded( RepositorySystemSession session ) + { + requireNonNull( session, "session cannot be null" ); + requireNotShutdown(); + String sessionId = sessionId( session ); + ArrayList handlers = new ArrayList<>(); + onSessionEndedHandlers.compute( sessionId, ( k, v ) -> + { + if ( v == null ) + { + throw new IllegalStateException( "session instance not registered" ); + } + handlers.addAll( v ); + return null; + } ); + + ArrayList exceptions = new ArrayList<>(); + for ( Runnable handler : handlers ) + { + try + { + handler.run(); + } + catch ( Exception e ) + { + exceptions.add( e ); + } + } + MultiRuntimeException.mayThrow( "sessionEnded handler issue(s)", exceptions ); + } + + @Override + public void addOnSessionEndedHandle( RepositorySystemSession session, Runnable handler ) + { + requireNonNull( session, "session cannot be null" ); + requireNonNull( handler, "handler cannot be null" ); + requireNotShutdown(); + String sessionId = sessionId( session ); + onSessionEndedHandlers.compute( sessionId, ( k, v ) -> + { + if ( v == null ) + { + throw new IllegalStateException( "session instance not registered" ); + } + v.add( handler ); + return v; + } ); + } + private void requireNotShutdown() { if ( shutdown.get() ) @@ -87,4 +164,12 @@ private void requireNotShutdown() throw new IllegalStateException( "repository system is already shut down" ); } } + + private String sessionId( RepositorySystemSession session ) + { + String id = (String) session.getData() + .computeIfAbsent( LIFECYCLE_ID_KEY, () -> String.valueOf( sessionIdCounter.incrementAndGet() ) ); + id += "-" + System.identityHashCode( session ); + return id; + } } From 5f94c6ea0ff64634fd6301f813d7a04e69b6ed9a Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 28 Dec 2022 12:43:33 +0100 Subject: [PATCH 2/2] Typo in HTML tag --- .../src/main/java/org/eclipse/aether/RepositorySystem.java | 4 ++-- .../org/eclipse/aether/impl/RepositorySystemLifecycle.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java index 6b028c7af..4a46f1371 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java @@ -309,7 +309,7 @@ List newResolutionRepositories( RepositorySystemSession sessio * {@link #addOnSessionEndedHandle(RepositorySystemSession, Runnable)} method that will execute once * {@link #sessionEnded(RepositorySystemSession)} method was invoked. *

- * Same session instance can be started only once. + * Same session instance can be started only once. * * @param session the session that is about to start, never {@code null}. * @since TBD @@ -331,7 +331,7 @@ List newResolutionRepositories( RepositorySystemSession sessio * will invoke the registered handlers for this session, if any. This method throws if the passed in session * instance was not passed to method {@link #sessionStarted(RepositorySystemSession)} beforehand. *

- * Same session instance can be ended only once. + * Same session instance can be ended only once. * * @param session the session that just ended, never {@code null}. * @since TBD diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java index 57e8190a8..367bd8c74 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java @@ -47,7 +47,7 @@ public interface RepositorySystemLifecycle /** * Registers the session for lifecycle tracking: it marks that the passed in session instance is about to start. *

- * Same session instance can be started only once. + * Same session instance can be started only once. * * @since TBD */ @@ -58,7 +58,7 @@ public interface RepositorySystemLifecycle * will invoke the registered handlers for this session, if any. This method throws if the passed in session * instance was not passed to method {@link #sessionStarted(RepositorySystemSession)} beforehand. *

- * Same session instance can be ended only once. + * Same session instance can be ended only once. * * @since TBD */