Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ Behavior rules for the coding agent
- If changing code that touches Testcontainers or integration tests, ensure Docker is available when validating; otherwise skip integration tests locally and make this explicit in PR.
- If any command from these instructions fails, only then search the repository for more details or updated config. Trust this document first.
- When tests fail locally, reproduce failing tests selectively with `--tests` before making fixes.
- Do not report exact test counts unless verified from test result files (`build/test-results/**/TEST-*.xml`); Gradle console summaries may be misleading with caching or filtered runs.
- When adding or updating documentation examples, verify API names and signatures against current source code (especially after recent renames).
- If the user says changes are already committed, avoid unsolicited commit-oriented follow-ups and focus on the requested review/documentation/diff task.

Reference (root file list, quick)
- README.md
Expand Down
29 changes: 29 additions & 0 deletions .github/skills/generate-branch-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ Group modifications by their nature:
Create a section in `summary.md` with this format:

```markdown
## Overview

Short 2-4 sentence summary of what the branch introduces and why it matters.

## Changes Summary

### <Category 1> (e.g., "New Array API")
Expand All @@ -53,6 +57,12 @@ Create a section in `summary.md` with this format:
- What documentation was added
- Why it matters (e.g., for future contributors)

### <Category N> Event flow diagram (when relevant)
- Add a Mermaid `flowchart` for runtime flow when the branch introduces/changes flow-heavy APIs

### <Category N+1> Usage samples (when relevant)
- Add copy-pasteable API usage examples for new public APIs

## Testing & Validation
- `./gradlew :module-name:build` ✅
- `./gradlew clean build` (recommended before merge)
Expand Down Expand Up @@ -81,9 +91,16 @@ Create a section in `summary.md` with this format:
- Use bullet points for lists
- Use bold (`**`) for emphasis on key terms
- Use inline code (`` ` ` ``) for class/method names
- Always include `## Overview` before `## Changes Summary`
- Do not add a `Branch:` section or heading in the summary
- Do not add `Status`, `Commits`, or `Version` metadata lines in the summary

#### Mermaid Diagram Safety (when diagrams are included)
- Prefer quoted node labels, e.g. `A["Create bus"]`
- Avoid method-signature punctuation inside node text (`(`, `)`, `,`, generics); use plain words instead
- Use edge labels like `|send|` instead of `|send(event)|`
- Keep node text short and parser-safe; move details to bullets under the diagram

### 6. Output Location
Always write to `summary.md` in the repository root, replacing or updating the previous summary section.

Expand All @@ -93,6 +110,11 @@ If `summary.md` already contains unrelated sections (e.g., documentation of othe
## Example Output

```markdown
## Overview

This branch extends the collections API with safe internal resizing and dictionary optimizations.
It reduces overhead on empty collections and adds documentation to clarify the new contract.

## Changes Summary

### 1. New Array API: `tryTrimTo(int)`
Expand Down Expand Up @@ -151,3 +173,10 @@ Mention:
4. **Be concise** — summaries should be readable in 2-3 minutes
5. **Link to code** — mention file paths and method names so reviewers can navigate easily
6. **Quantify changes** — "7 methods optimized" is more informative than "several optimizations"

## Final Checklist (before saving `summary.md`)
- `## Overview` exists and is concise
- `## Changes Summary` exists with clear categories
- If a diagram is included, Mermaid renders with parser-safe labels
- If a new public API is introduced, usage samples are included
- `## Testing & Validation` includes executed commands and recommended full build
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ A modular Java utility library providing common utilities for classpath scanning
| `rlib-collections` | Extended collection implementations |
| `rlib-compiler` | Runtime Java source compilation API |
| `rlib-concurrent` | Concurrency utilities and helpers |
| `rlib-eventbus` | Typed low-overhead event bus API |
| `rlib-classpath` | Classpath scanning and class discovery |
| `rlib-functions` | Functional interfaces and utilities |
| `rlib-geometry` | Geometry utilities |
Expand Down Expand Up @@ -45,20 +46,22 @@ repositories {
}

ext {
rlibVersion = "10.0.alpha16"
rlibVersion = "10.0.alpha17"
}

dependencies {
implementation "javasabr.rlib:rlib-common:$rlibVersion"
implementation "javasabr.rlib:rlib-collections:$rlibVersion"
implementation "javasabr.rlib:rlib-compiler:$rlibVersion"
implementation "javasabr.rlib:rlib-concurrent:$rlibVersion"
implementation "javasabr.rlib:rlib-eventbus:$rlibVersion"
implementation "javasabr.rlib:rlib-geometry:$rlibVersion"
implementation "javasabr.rlib:rlib-logger-api:$rlibVersion"
implementation "javasabr.rlib:rlib-logger-slf4j:$rlibVersion"
implementation "javasabr.rlib:rlib-plugin-system:$rlibVersion"
implementation "javasabr.rlib:rlib-reference:$rlibVersion"
implementation "javasabr.rlib:rlib-reusable:$rlibVersion"
implementation "javasabr.rlib:rlib-eventbus:$rlibVersion"
implementation "javasabr.rlib:rlib-fx:$rlibVersion"
implementation "javasabr.rlib:rlib-network:$rlibVersion"
implementation "javasabr.rlib:rlib-mail:$rlibVersion"
Expand Down Expand Up @@ -120,6 +123,29 @@ LoggerLevel.DEBUG.setEnabled(false);
logger.setEnabled(LoggerLevel.DEBUG, true);
```

### EventBus API

Type-safe event publishing and subscription with low dispatch overhead:

```java
interface AppEvents extends EventBus.TypeIdSet {}

record UserCreatedEvent(
String userId,
EventBus.TypeId<AppEvents, UserCreatedEvent> typeId
) implements EventBus.Event<AppEvents> {}

var typeIdFactory = EventBusFactory.createTypeIdFactory(AppEvents.class);
var eventBus = EventBusFactory.createEventBus(typeIdFactory);
var userCreatedTypeId = typeIdFactory.typeIdOf(UserCreatedEvent.class);

eventBus.subscribe(userCreatedTypeId, event ->
System.out.println("User created: " + event.userId()));

eventBus.send(new UserCreatedEvent("user-42", userCreatedTypeId));
eventBus.sendInBackground(new UserCreatedEvent("user-43", userCreatedTypeId));
```

### Mail Sender

Send emails synchronously or asynchronously:
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
rootProject.version = "10.0.alpha16"
rootProject.version = "10.0.alpha17"
group = 'javasabr.rlib'

allprojects {
Expand Down
8 changes: 8 additions & 0 deletions rlib-eventbus/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
plugins {
id("configure-java")
id("configure-publishing")
}

dependencies {
api projects.rlibCollections
}
124 changes: 124 additions & 0 deletions rlib-eventbus/src/main/java/javasabr/rlib/eventbus/EventBus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package javasabr.rlib.eventbus;

import java.util.function.Consumer;

/**
* Provides a typed event bus for subscribing and publishing events by {@link TypeId}.
* Implementations are expected to support concurrent subscribe, unsubscribe, and send operations.
*
* @param <S> the type of type-id set
* @since 10.0.0
*/
public interface EventBus<S extends EventBus.TypeIdSet> {

/**
* Subscribes a consumer to events identified by the provided type id.
*
* @param typeId the event type id
* @param consumer the consumer of events
* @param <E> the type of event
* @since 10.0.0
*/
<E extends Event<S>> void subscribe(TypeId<S, E> typeId, Consumer<E> consumer);

/**
* Unsubscribes a consumer from events identified by the provided type id.
*
* @param typeId the event type id
* @param consumer the consumer of events
* @param <E> the type of event
* @since 10.0.0
*/
<E extends Event<S>> void unsubscribe(TypeId<S, E> typeId, Consumer<E> consumer);

/**
* Sends an event to all subscribed consumers in the current thread.
* This method does not enqueue work and returns only after dispatch is finished.
* Consumer exceptions are propagated to the caller.
*
* @param event the event to send
* @since 10.0.0
*/
void send(Event<S> event);

/**
* Schedules sending an event on the background executor.
* This method returns immediately after scheduling.
* Delivery order between different background sends is not guaranteed and depends on the executor policy.
* Consumer exceptions are handled on the background thread.
*
* @param event the event to send
* @since 10.0.0
*/
void sendInBackground(Event<S> event);

/**
* Marks a type-id namespace used to isolate event buses by event family.
*
* @since 10.0.0
*/
interface TypeIdSet {
}

/**
* Creates stable {@link TypeId} instances for event types within one type-id namespace.
*
* @param <S> the type of type-id set
* @since 10.0.0
*/
interface TypeIdFactory<S extends TypeIdSet> {

/**
* Returns a type id for the specified event type.
*
* @param eventType the event class
* @param <E> the type of event
* @return the type id of the event class
* @since 10.0.0
*/
<E extends Event<S>> TypeId<S, E> typeIdOf(Class<E> eventType);
}

/**
* Represents an identity of one event type within a {@link TypeIdSet}.
*
* @param <S> the type of type-id set
* @param <E> the type of event
* @since 10.0.0
*/
interface TypeId<S extends TypeIdSet, E extends Event<S>> {

/**
* Returns the event class associated with this type id.
*
* @return the event class
* @since 10.0.0
*/
Class<E> eventType();

/**
* Returns the numeric id used for fast lookup in event bus internals.
*
* @return the numeric event type id
* @since 10.0.0
*/
int id();
}

/**
* Represents an event published to an {@link EventBus}.
*
* @param <S> the type of type-id set
* @since 10.0.0
*/
interface Event<S extends TypeIdSet> {

/**
* Returns the type id of this event.
*
* @return the type id of this event
* @since 10.0.0
*/
TypeId<S, ? extends Event<S>> typeId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package javasabr.rlib.eventbus;

import javasabr.rlib.eventbus.EventBus.TypeIdFactory;
import javasabr.rlib.eventbus.EventBus.TypeIdSet;
import javasabr.rlib.eventbus.impl.DefaultEventBus;
import javasabr.rlib.eventbus.impl.DefaultTypeIdFactory;
import lombok.experimental.UtilityClass;

/**
* Provides factory methods for creating event bus API components.
*
* @since 10.0.0
*/
@UtilityClass
public class EventBusFactory {
Comment thread
JavaSaBr marked this conversation as resolved.

/**
* Creates a type-id factory for the provided type-id namespace.
*
* @param typeIdSetType the type-id namespace class
* @param <S> the type of type-id set
* @return a type-id factory for the namespace
* @since 10.0.0
*/
public static <S extends TypeIdSet> TypeIdFactory<S> createTypeIdFactory(Class<S> typeIdSetType) {
return DefaultTypeIdFactory.INSTANCE.typedTypeIdFactory(typeIdSetType);
}

/**
* Creates an event bus instance.
* The default implementation uses a shared background executor for {@link EventBus#sendInBackground(EventBus.Event)}.
*
* @param typeIdFactory the type-id factory associated with this bus API
* @param <S> the type of type-id set
* @return a new event bus
* @since 10.0.0
*/
public static <S extends TypeIdSet> EventBus<S> createEventBus(@SuppressWarnings("unused") TypeIdFactory<S> typeIdFactory) {
return new DefaultEventBus<>();
}
}
Loading
Loading