gnodet commented on PR #13011:
URL: https://github.com/apache/maven/pull/13011#issuecomment-5561988438

   ## API Design Suggestion: Event/Listener Hierarchy
   
   The current PR introduces `RepositoryListener` / `RepositoryEvent` as 
standalone types with separate registration methods on `Session`. This works, 
but it creates an inconsistency with the existing `Listener` / `Event` API 
(build lifecycle events) — two parallel, unrelated listener systems on the same 
`Session` with different design patterns:
   
   - `Listener` uses `@FunctionalInterface` single-dispatch (`onEvent(Event)`) 
— consumers must switch on `EventType`
   - `RepositoryListener` uses typed `default` callbacks 
(`artifactDownloading()`, etc.) — much better ergonomics
   
   **Proposed hierarchy** for 4.1.0: introduce `Event` and `Listener` as base 
marker types, with `ExecutionEvent`/`ExecutionListener` (build lifecycle) and 
`RepositoryEvent`/`RepositoryListener` (repository operations) as typed 
specializations.
   
   ### Event hierarchy
   
   ```java
   @Experimental @Immutable
   public interface Event {
       @Nonnull Session session();
   }
   
   @Experimental @Immutable
   public interface ExecutionEvent extends Event {
       @Nonnull ExecutionEventType type();
       @Nonnull Optional<Project> project();
       @Nonnull Optional<MojoExecution> mojoExecution();
       @Nonnull Optional<Exception> exception();
   }
   
   @Experimental @Immutable
   public interface RepositoryEvent extends Event {
       @Nonnull RepositoryEventType type();
       @Nonnull Optional<Artifact> artifact();
       @Nonnull Optional<RepositoryMetadata> metadata();
       @Nonnull Optional<Path> path();
       @Nonnull Optional<Repository> repository();
       @Nonnull Optional<Exception> exception();
       @Nonnull List<Exception> exceptions();
       @Nonnull Optional<RequestTrace> trace();
   }
   ```
   
   ### Listener hierarchy
   
   ```java
   @Experimental @Consumer
   public interface Listener {
       /** @deprecated Implement ExecutionListener or RepositoryListener 
instead. */
       @Deprecated
       default void onEvent(@Nonnull Event event) {}
   }
   
   @Experimental @Consumer
   public interface ExecutionListener extends Listener {
       default void sessionStarted(@Nonnull ExecutionEvent event) {}
       default void sessionEnded(@Nonnull ExecutionEvent event) {}
       default void projectDiscoveryStarted(@Nonnull ExecutionEvent event) {}
       default void projectStarted(@Nonnull ExecutionEvent event) {}
       default void projectSucceeded(@Nonnull ExecutionEvent event) {}
       default void projectFailed(@Nonnull ExecutionEvent event) {}
       default void projectSkipped(@Nonnull ExecutionEvent event) {}
       default void mojoStarted(@Nonnull ExecutionEvent event) {}
       default void mojoSucceeded(@Nonnull ExecutionEvent event) {}
       default void mojoFailed(@Nonnull ExecutionEvent event) {}
       default void mojoSkipped(@Nonnull ExecutionEvent event) {}
       default void forkStarted(@Nonnull ExecutionEvent event) {}
       default void forkSucceeded(@Nonnull ExecutionEvent event) {}
       default void forkFailed(@Nonnull ExecutionEvent event) {}
       default void forkedProjectStarted(@Nonnull ExecutionEvent event) {}
       default void forkedProjectSucceeded(@Nonnull ExecutionEvent event) {}
       default void forkedProjectFailed(@Nonnull ExecutionEvent event) {}
   }
   
   @Experimental @Consumer
   public interface RepositoryListener extends Listener {
       default void artifactDescriptorInvalid(@Nonnull RepositoryEvent event) {}
       default void artifactDescriptorMissing(@Nonnull RepositoryEvent event) {}
       default void metadataInvalid(@Nonnull RepositoryEvent event) {}
       default void artifactResolving(@Nonnull RepositoryEvent event) {}
       default void artifactResolved(@Nonnull RepositoryEvent event) {}
       // ... etc (19 typed callbacks, as in this PR)
   }
   ```
   
   ### Session impact
   
   Single registration point — no overloaded methods needed:
   
   ```java
   // Session keeps ONE set of listener methods for both types:
   void registerListener(@Nonnull Listener listener);
   void unregisterListener(@Nonnull Listener listener);
   Collection<Listener> getListeners();
   ```
   
   The dispatcher routes via `instanceof ExecutionListener` / `instanceof 
RepositoryListener`. A listener can even implement both.
   
   ### Benefits
   
   - **Uniform design** — both event families use typed `default` callbacks, no 
more `@FunctionalInterface` single-dispatch
   - **Single registration** — no separate 
`registerListener(RepositoryListener)` / `getRepositoryListeners()` on `Session`
   - **Extensible** — future event categories (transfer, toolchain) just add 
`XxxEvent extends Event` + `XxxListener extends Listener`, no `Session` changes
   - **Backward compatible** — old `Listener.onEvent()` stays as a `@Deprecated 
default`, existing consumers keep compiling
   - **Noun-style accessors** on new types (consistent with #13036), 
`@Immutable` events
   - `EventType` → `ExecutionEventType` for symmetry with `RepositoryEventType`


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to