<commit_before># EventSockets

## A Lightweight Object Event Framework

The purpose of this framework is to provide a simple approach to implementing direct
Publish / Subscribe, similar to that used by GUI frameworks, without requiring a lot
of repeated boilerplate code.  This is not an Event Bus or Grand Central Dispatch
eventing framework.

I developed this framework as an attempt to overcome what I perceive as a design
oversight in the Java programming language: the lack of native Events.  While
some other such frameworks have existed for a long time, including the `EventListenerList`
in Swing, I have found that they still require a significant amount of boilerplate
code to utilize, enough so that I have sometimes opted to do without Events in my past
object designs, even when they were warranted.


## Concepts and Usage

### Events

Events in this framework are identified by their type.  All events must implement
`IEvent`, which is a simple tagging interface.  While this interface wasn't
strictly necessary, it helps ensure that event objects are appropriately declared.
It also serves as the base for two specialty variants.

Event types implementing `ICancelableEvent` will abort event processing if
the fired event object returns `true` from `ICancelableEvent.canceled()`.
Generally, you will want to extend the `AbstractCancellableEvent` class,
rather than directly implementing this interface.

Event objects of types implementing `IClonableEvent` will be cloned prior to
each listener call, whereas ordinary event objects are simply passed to each registered
listener in turn.  Generally, you will want to extend the `AbstractClonableEvent`
class, rather than directly implementing this interface.


### Listeners

Listeners can be created either as instances of `IListener`, or as methods
of the listening object, using the `@Listener` annotation.  The `IListener`
interface is lambda-compatible, so in Java 8 (or beyond) listeners may be
provided simply as lambda expressions.

Listeners are characterized by the type of event object which they listen for,
which is provided as the generic type for `IListener`.


### Event Sockets

Event Sockets are the glue which binds listeners to objects.

Rather than requiring objects which expose (or fire) events to implement a plethora of
add*Listener and remove*Listener methods, the class exposes one Event Socket method
for each event type.  The value returned by the Event Socket method has the appropriate
bind and unbind methods.  The term Event Socket reflects the notions that event listeners
are plugged into the event they listen for.

By convention, all Event Socket methods are named `on*EventType*`.


### Event Services

A class which wishes to expose events should have a private member of an appropriate
Event Service type.  The Event Service provides methods to get Event Sockets and to
fire events.  While the Event Sockets are expected to be part of the public interface
of the class, the firing of events is generally part of the private (or protected)
implementation.

There are two base types of Event Services, which both implement `IEventService`.
The `SimpleEventService` is for classes which only need to expose a single event
type.  Such classes will typically expose a single Event Socket, named either `onEvent`
or `on*EventType*`.  The socket is obtained by calling `SimpleEventService.getSocket()`.

The `MultiEventService` is for classes which need to expose multiple events (i.e.
multiple event types).  In addition to supporting the socket for the root event type,
the MultiEventService has the `MultiEventService.getSocket( Class eventClass )`
method, which allows event listeners to be bound to a specific event type.  It also
supports binding all annotated listeners on an object at once, using
`MultiEventService.getBinder()`.
See the `@Listener` annotation's documentation for more details.


#### Event Propagation

The provided `IEventService` implementations provide support for propagating
events to handlers registered on other objects, such as propagating a UI event
up the component hierarchy.  This propagation can be easily implemented by
overriding the Event Service's `preFire` or `postFire` methods, empty implementations
of which are defined in the `AbstractEventService` class.


## Example
<commit_msg>Minor changes to README.md<commit_after># EventSockets

## A Lightweight Object Event Framework

The purpose of this framework is to provide a simple approach to implementing direct
Publish / Subscribe, similar to that used by GUI frameworks, without requiring a lot
of repeated boilerplate code.  This is not an Event Bus or Grand Central Dispatch
eventing framework.


## Concepts and Usage

### Events

Events in this framework are identified by their type.  All events must implement
`IEvent`, which is a simple tagging interface.  While this interface wasn't
strictly necessary, it helps ensure that event objects are appropriately declared.
It also serves as the base for two specialty variants.

Event types implementing `ICancelableEvent` will abort event processing if
the fired event object returns `true` from `ICancelableEvent.canceled()`.
Generally, you will want to extend the `AbstractCancellableEvent` class,
rather than directly implementing this interface.

Event objects of types implementing `IClonableEvent` will be cloned prior to
each listener call, whereas ordinary event objects are simply passed to each registered
listener in turn.  Generally, you will want to extend the `AbstractClonableEvent`
class, rather than directly implementing this interface.


### Listeners

Listeners can be created either as instances of `IListener`, or as methods
of the listening object, using the `@Listener` annotation.  The `IListener`
interface is lambda-compatible, so in Java 8 (or beyond) listeners may be
provided simply as lambda expressions.

Listeners are characterized by the type of event object which they listen for,
which is provided as the generic type for `IListener`.


### Event Sockets

Event Sockets are the glue which binds listeners to objects.

Rather than requiring objects which expose (or fire) events to implement a plethora of
add*Listener and remove*Listener methods, the class exposes one Event Socket method
for each event type.  The value returned by the Event Socket method has the appropriate
bind and unbind methods.  The term Event Socket reflects the notions that event listeners
are plugged into the event they listen for.

By convention, all Event Socket methods are named on*EventType*.


### Event Services

A class which wishes to expose events should have a private member of an appropriate
Event Service type.  The Event Service provides methods to get Event Sockets and to
fire events.  While the Event Sockets are expected to be part of the public interface
of the class, the firing of events is generally part of the private (or protected)
implementation.

There are two base types of Event Services, which both implement `IEventService`.
The `SimpleEventService` is for classes which only need to expose a single event
type.  Such classes will typically expose a single Event Socket, named either `onEvent`
or on*EventType*.  The socket is obtained by calling `SimpleEventService.getSocket()`.

The `MultiEventService` is for classes which need to expose multiple events (i.e.
multiple event types).  In addition to supporting the socket for the root event type,
the MultiEventService has the `MultiEventService.getSocket( Class eventClass )`
method, which allows event listeners to be bound to a specific event type.  It also
supports binding all annotated listeners on an object at once, using
`MultiEventService.getBinder()`.
See the `@Listener` annotation's documentation for more details.


#### Event Propagation

The provided `IEventService` implementations provide support for propagating
events to handlers registered on other objects, such as propagating a UI event
up the component hierarchy.  This propagation can be easily implemented by
overriding the Event Service's `preFire` or `postFire` methods, empty implementations
of which are defined in the `AbstractEventService` class.


## Example

{'fraction_non_alphanumeric': 0.04101061882094471, 'fraction_numerical': 0.00024411082631514708, 'mean_word_length': 5.011738811445341, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '844962', 'n_tokens_mistral': 1940, 'n_tokens_neox': 1848, 'n_words': 1177}