Skip to content
Tim Buckley edited this page May 2, 2014 · 3 revisions

Java 8 support

Will likely be developed as a separate branch to keep Java 7 support.

Functional interfaces

Functional interfaces as event receivers:

producer.bus().register(SomeEvent.class, someEvent -> /* do things */)

The register() method will likely also return a reference to the handler object to allow it to be removed again.

Deadlines

Deadlines could be implemented in a number of (not necessarily exclusive) ways. "Destructive" deadlines would ensure that EventBus.push() or a flush of the event queue (see Executors below) would occur within a certain amount of time, possibly dropping low-priority event handlers (priority < 0).

Executors

Currently event dispatching takes place on the calling thread, which introduces a number of problems. Executors will provide a pluggable method of dispatching events and will allow events to be dispatched in various ways. Some examples:

  • SimpleExecutor: current behavior; events are dispatched on the thread that called EventBus.push().
  • ThreadedExecutor: events are queued and dispatched in a dedicated thread
  • EmbeddedExecutor: events are dispatched within another thread, some EmbeddedExecutor.process() must be called
    • Useful for integrating into existing event threads (e.g. UIs, etc)
    • AndroidExecutor: execute within the Android UI thread
    • SwingExecutor: execute within the Swing UI thread
  • PooledExecutor: events are dispatched to a thread pool and processed concurrently
    • Potentially faster, but somewhat situation-specific

Threading does introduce some complexity and will require planning on the client side, so SimpleExecutor may remain the default.

A preliminary implementation of the above executors may be found in the executors branch.

Multiple Executors

Complex systems may require that different event handlers be invoked in different ways. That is, certain handlers may want to be executed in their own thread, while other handlers may need to execute in the background...

Consider a platform like Android (particularly with strict mode enabled): UI interactions must take place in the UI thread, while network and other IO must be performed in some background thread. This shouldn't be too difficult to accomodate:

@EventHandler(executor = "eventThread")
public void backgroundEvent(SomeEvent event) {
    // handle it
}

@EventHandler(executor = "uiThread")
public void uiEvent(SomeEvent event) {
    // handle
}

/* ... bus creation ... */
bus = new EventBus();
bus.addExecutor("eventThread", new ThreadedExecutor());
bus.addExecutor("uiThread", new AndroidExecutor());

Events can then be dispatched to the appropriate Executor implementation when EventBus.push() is called, using a specified default for handlers that indicate no preference.

Filters

Filters will allow only a certain subset of event handlers to be notified of events. Some (as yet undecided) functionality will allow event handlers to communicate some parameters to the event bus, which can then be filtered against when pushing a new event.

A few tentative requirements exist:

  • Must be dynamic, i.e. it should allow runtime properties (for example, position of an entity in a game, etc)
  • Should remain simple and not define any class-level requirements. One of the main strengths is that there's very little work needed to define, emit, or receive a new event.

Some extra goals:

  • Create the smallest possible performance impact. This feature is intended to decrease overhead, after all.
Example Use-Case

A (hypothetical) game world is a large 2d plane, and a large number of entities are distributed throughout it. AI updates only need to take events occurring within 20 units into account, but events can occur rapidly. Pushing an event to the entire game world and having each entity do a distance check is very inefficient - can this overhead be removed?

We can efficiently get a list of entities in range (via a quadtree or some such) - how do we communicate this to our event dispatcher?

Possible solutions:

  • Matching on the parent object of a handler, or handlers define some @EventHandler(filterOn = 'field') attribute
  • Pros: simple to implement
  • Cons: creates unintuitive dependencies on other classes or class data
  • Event producer passes some Filter implementation to push() that performs filtering
  • Pros: even simpler, filtering logic is left to the event producer
  • Cons: fairly large amount of work on client-side needed to make a filter, adds class-specific requirements to handlers

Neither of these solutions seem ideal, but would at least provide basic functionality. They aren't mutually exclusive, either: both could be implemented without too much trouble.

Clone this wiki locally