!act,doc #2922 Doc event bus and fix Java API

This commit is contained in:
Patrik Nordwall 2014-02-06 15:08:51 +01:00
parent f1edf78979
commit a247365b57
13 changed files with 803 additions and 168 deletions

View file

@ -1,26 +1,15 @@
.. _event-bus-scala:
#################
Event Bus
#################
###########
Event Bus
###########
Originally conceived as a way to send messages to groups of actors, the
:class:`EventBus` has been generalized into a set of composable traits
implementing a simple interface:
- :meth:`subscribe(subscriber: Subscriber, classifier: Classifier): Boolean`
subscribes the given subscriber to events with the given classifier
- :meth:`unsubscribe(subscriber: Subscriber, classifier: Classifier): Boolean`
undoes a specific subscription
- :meth:`unsubscribe(subscriber: Subscriber)` undoes all subscriptions for the
given subscriber
- :meth:`publish(event: Event)` publishes an event, which first is classified
according to the specific bus (see `Classifiers`_) and then published to all
subscribers for the obtained classifier
.. includecode:: ../../../akka-actor/src/main/scala/akka/event/EventBus.scala#event-bus-api
.. note::
@ -28,9 +17,8 @@ implementing a simple interface:
published messages. If you need a reference to the original sender
you have to provide it inside the message.
This mechanism is used in different places within Akka, e.g. the
:ref:`DeathWatch <deathwatch-scala>` and the `Event Stream`_. Implementations
can make use of the specific building blocks presented below.
This mechanism is used in different places within Akka, e.g. the `Event Stream`_.
Implementations can make use of the specific building blocks presented below.
An event bus must define the following three abstract types:
@ -50,9 +38,7 @@ Classifiers
The classifiers presented here are part of the Akka distribution, but rolling
your own in case you do not find a perfect match is not difficult, check the
implementation of the existing ones on `github`_.
.. _github: https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/event/EventBus.scala
implementation of the existing ones on `github <@github@/akka-actor/src/main/scala/akka/event/EventBus.scala>`_
Lookup Classification
---------------------
@ -61,22 +47,15 @@ The simplest classification is just to extract an arbitrary classifier from
each event and maintaining a set of subscribers for each possible classifier.
This can be compared to tuning in on a radio station. The trait
:class:`LookupClassification` is still generic in that it abstracts over how to
compare subscribers and how exactly to classify. The necessary methods to be
implemented are the following:
compare subscribers and how exactly to classify.
- :meth:`classify(event: Event): Classifier` is used for extracting the
classifier from the incoming events.
The necessary methods to be implemented are illustrated with the following example:
- :meth:`compareSubscribers(a: Subscriber, b: Subscriber): Int` must define a
partial order over the subscribers, expressed as expected from
:meth:`java.lang.Comparable.compare`.
.. includecode:: code/docs/event/EventBusDocSpec.scala#lookup-bus
- :meth:`publish(event: Event, subscriber: Subscriber)` will be invoked for
each event for all subscribers which registered themselves for the events
classifier.
A test for this implementation may look like this:
- :meth:`mapSize: Int` determines the initial size of the index data structure
used internally (i.e. the expected number of different classifiers).
.. includecode:: code/docs/event/EventBusDocSpec.scala#lookup-bus-test
This classifier is efficient in case no subscribers exist for a particular event.
@ -89,19 +68,15 @@ can be compared to tuning in on (possibly multiple) radio channels by genre.
This classification has been developed for the case where the classifier is
just the JVM class of the event and subscribers may be interested in
subscribing to all subclasses of a certain class, but it may be used with any
classifier hierarchy. The abstract members needed by this classifier are
classifier hierarchy.
- :obj:`subclassification: Subclassification[Classifier]` is an object
providing :meth:`isEqual(a: Classifier, b: Classifier)` and
:meth:`isSubclass(a: Classifier, b: Classifier)` to be consumed by the other
methods of this classifier.
The necessary methods to be implemented are illustrated with the following example:
- :meth:`classify(event: Event): Classifier` is used for extracting the
classifier from the incoming events.
.. includecode:: code/docs/event/EventBusDocSpec.scala#subchannel-bus
- :meth:`publish(event: Event, subscriber: Subscriber)` will be invoked for
each event for all subscribers which registered themselves for the events
classifier.
A test for this implementation may look like this:
.. includecode:: code/docs/event/EventBusDocSpec.scala#subchannel-bus-test
This classifier is also efficient in case no subscribers are found for an
event, but it uses conventional locking to synchronize an internal classifier
@ -117,21 +92,14 @@ strictly hierarchical, this classifier is useful if there are overlapping
classifiers which cover various parts of the event space without forming a
hierarchy. It can be compared to tuning in on (possibly multiple) radio
stations by geographical reachability (for old-school radio-wave transmission).
The abstract members for this classifier are:
- :meth:`compareClassifiers(a: Classifier, b: Classifier): Int` is needed for
determining matching classifiers and storing them in an ordered collection.
The necessary methods to be implemented are illustrated with the following example:
- :meth:`compareSubscribers(a: Subscriber, b: Subscriber): Int` is needed for
storing subscribers in an ordered collection.
.. includecode:: code/docs/event/EventBusDocSpec.scala#scanning-bus
- :meth:`matches(classifier: Classifier, event: Event): Boolean` determines
whether a given classifier shall match a given event; it is invoked for each
subscription for all received events, hence the name of the classifier.
A test for this implementation may look like this:
- :meth:`publish(event: Event, subscriber: Subscriber)` will be invoked for
each event for all subscribers which registered themselves for a classifier
matching this event.
.. includecode:: code/docs/event/EventBusDocSpec.scala#scanning-bus-test
This classifier takes always a time which is proportional to the number of
subscriptions, independent of how many actually match.
@ -139,15 +107,17 @@ subscriptions, independent of how many actually match.
Actor Classification
--------------------
This classification has been developed specifically for implementing
This classification was originally developed specifically for implementing
:ref:`DeathWatch <deathwatch-scala>`: subscribers as well as classifiers are of
type :class:`ActorRef`. The abstract members are
type :class:`ActorRef`.
- :meth:`classify(event: Event): ActorRef` is used for extracting the
classifier from the incoming events.
The necessary methods to be implemented are illustrated with the following example:
- :meth:`mapSize: Int` determines the initial size of the index data structure
used internally (i.e. the expected number of different classifiers).
.. includecode:: code/docs/event/EventBusDocSpec.scala#actor-bus
A test for this implementation may look like this:
.. includecode:: code/docs/event/EventBusDocSpec.scala#actor-bus-test
This classifier is still is generic in the event type, and it is efficient for
all use cases.
@ -161,7 +131,7 @@ The event stream is the main event bus of each actor system: it is used for
carrying :ref:`log messages <logging-scala>` and `Dead Letters`_ and may be
used by the user code for other purposes as well. It uses `Subchannel
Classification`_ which enables registering to related sets of channels (as is
used for :class:`RemoteLifeCycleMessage`). The following example demonstrates
used for :class:`RemotingLifecycleEvent`). The following example demonstrates
how a simple subscription works:
.. includecode:: code/docs/event/LoggingDocSpec.scala#deadletters