Michael Elhadad
Software Engineering - Fall 1999
Lecture 10: Event Models
Motivation
- Generic notions and patterns around event, notification, listener, adapter.
- CORBA Event Services: Event Channels, push, pull and hybrid modes
- Introduction to Java's Event Model
- Events, Listeners and Adapters
- Types of adapters: demultiplexing, wrappers, distributed, queuing,
filtering.
References
Read The
Java Event Model from the Sun Java Tutorial.
More
on Java events in SWING.
Read Schmidt's
columns on Corba's event system (the examples are translated in Java in
the previous lecture notes):
- Distributed
Callbacks and Decoupled Communication in CORBA, SIGS, Vol 8. No
9. October 1996.
This column examines distributed callbacks
in CORBA and illustrates why they are useful for decoupling relationships
between consumers and suppliers in object-oriented communication
applications. The source code examples are based on the HP ORB Plus CORBA
implementation.
- OMG
Event Object Service, SIGS, Vol. 9, No 2. February, 1997.
This column outlines the roles of the key components in the OMG Events
Service, examines the IDL interfaces of the Events Service
components in detail, shows how to use it to build a flexible
implementation of the distributed stock quoter system, and evaluates
the strengths and weaknesses of the OMG Event Services model and its
specification.
- Overcoming
Drawbacks with the OMG Events Service,, SIGS, Vol. 9, No 6. June,
1997. (updated April 7th, 1997)
This column describes techniques for overcoming drawbacks with the OMG Events Service. These techniques range from changing
the COS Events Service specification, to changing implementations of the
COS Events Service specification, as well as changing applications that use
a COS Events Service implementation.
Events
Events are objects or messages used when a software components wants
to notify a state change to other components.
An Event model is a software architecture (a set of classes and
interfaces) that determine how components can:
- On the event source side:
- create and describe events
- trigger (or fire) events
- distribute events to interested components
- On the event listener side:
- subscribe to event sources
- react to events when received
- remove the subscription to event sources when desired
Terminology often used refers to:
- Event Source or Provider: the sender of events
- Event: the object sent
- Event Listener or Event Sink or Consumer: the
receiver of events.
Properties of Event Services
The most important properties:
- Synchronous vs. asynchronous events: does the consumer react
immediately to the event? does the producer wait for the consumer to finish
reacting?
- Connection topology: can producers and consumers be connected in
complex topologies (fan-in, fan-out)? does the service require a
centralized event registration mechanism or can it be distributed?
- Push vs. Pull: do producers inform consumers (push) or reversely
do consumers ask producers for events (pull)? Can hybrid models be
supported?
- Distributed vs. single process events
- Quality of Service (QoS): does the service insure that the
channel between producer and consumer can reserve bandwidth to allow
time-critical events to reach consumers whenever needed?
- Directed vs. undirected events: it is desirable that the
producer can trigger events without knowing the identity of the consumers
and vice-versa, that consumers can subscribe to event sources without
knowing the identity of the potential producers.
- Typed vs. untyped events: with untyped events, consumers can
listen to any type of events. This adds to flexibility but costs in
security (no compile-time check).
- Persistent: what happens if the event channel process exits? It
should keep the event queues in a persistent store and restore them upon
restart. Also, if an event channel or a source is used, whenever it is
shut down, it should keep the list of registered listeners to restore it
upon restart.
- Security: does anyone check if consumers are authorized to
subscribe to an event notification service?
- Filtering: who is in charge of filtering events, consumer or
producer? How difficult is it to define filtering constraints?
The conclusion is that the definition of an event model can be difficult,
and must be adapted by analyzing the trade-offs of each application.
The Java Event Model: Part 1
Java defines the following basis to help define new event types:
class EventObject
: is serializable and remembers the
Source object.
interface EventListener
: is used only to tag interfaces
that extend it so that run-time type information can recognize them.
When defining a new event, the following conventions are followed:
- A new class extending EventObject is defined. It is named using the
pattern
xxxEvent
.
- A new interface extending EventListener is defined. It is named using
the pattern
xxxListener
- The interface xxxListener defines functions to react to the xxxEvent
family. They are named using the pattern
onxxx(xxxEvent)
.
- The producer of the xxxEvent implements 3 methods:
void addxxxListener(xxxListener l)
:
adds l to the list of interested listeners.
void removexxxListener(xxxListener l)
:
removes l from the list.
void notifyxxx()
:
creates an xxxEvent and sends it to all interested listeners.
- The consumers of the event define an instance of a class that
implements the xxxListener interface and register this class with
an xxxEvent producer using the addxxxListener() method.
- The producer fires events by calling notifyxxx().
This is the simplest application of the model. It is:
- synchronous
- simple direct topology (direct link producer/consumer)
- push
- non distributed (except if the onxxx() method is a remote invocation,
but this is not desirable because this is a synchronous model and
the remote invocation would block the event notification loop).
- No handling of quality of service: there is no priority among listeners
- they are simply added to the list of listeners, which could
grow. The time it takes to notify a listener is therefore
unbounded.
- Directed (consumers and producers know about each other)
- Typed (the xxxEvent type is used)
- The addxxxListener is in charge of checking security
- Filtering is performed by the producer in the notifyxxx() method or by
the consumer in the onxxx() method. There is no "declarative"
setting of event filtering.
The Java Event Model: Example 1
The following code illustrates how to implement the simplest application of
the Java event model:
// Define a new event
public class StockPriceChangeEvent extends EventObject {
private long newPrice;
public StockPriceChangeEvent(Object source, long np) {
super(source);
newPrice = np;
}
public long getNewPrice() {
return newPrice;
}
// Type-safe access to source
public Stock getStock() {
return (Stock)getSource();
}
}
// Define new listener interface
public interface StockListener extends EventListener {
public abstract void onStockPriceChange(StockPriceChangeEvent e);
}
// Define a source for the event
public class Stock {
private long currentPrice;
private Vector stockListeners = new Vector();
private String name;
public Stock(String n) {name = n;}
public setPrice(long np) {
currentprice = np;
notifyStockPriceChange();
}
public synchronized void addStockListener(StockListener l) {
stockListeners.addElement(l);
}
public synchronized void removeStockListener(StockListener l) {
stockListeners.removeElement(l);
}
protected void notifyStockPriceChange() {
StockPriceChangeEvent e = new StockPriceChangeEvent(this, currentPrice);
for (int i = 0; i < stockListeners.size(); i++ ) {
StockListener l = (StockListener)stockListeners.elementAt(i);
l.onStockPriceChange(e);
}
}
}
// Define a listener for the event
public class Trader implements StockListener {
public Trader() {
ibm = new Stock("ibm");
ibm.addStockListener(this);
}
...
public onStockPriceChange(StockPriceChangeEvent e) {
if (e.getNewPrice() > 103) {
Buy(e.getStock());
}
}
}
As shown in the code, event sources must deal with the issue of
registration of listeners and distribution of events when they work in push
mode. Java provides classes to support this aspect of the problem.
Event Adapters
Adapters are intermediary objects -- objects that come between event
sources and their targets. Adapters allow the decoupling of sources
and targets. This is desirable in several scenarios:
- Demultiplexing adapters: the same adapter can receive events
from several sources and trigger a single event on the targets.
- Generic adapters:
are useful to allow wiring of sources and targets that are not
type compatible. The adapter maintains a map to make events of
different types correspond to each other.
- Distributed adapters:
take care of the remote interfaces to send events to remote
targets. For example, a CORBA event-adapter allows an event
source to connect to targets on any machine related through the ORB.
- Queuing adapters:
When using a synchronous event-model, a queuing adapter is
important to decouple the posting of an event with the execution of
the callback on the targets. The queuing adapter just records the
event and the source can keep working. The targets can handle the
event when they have time.
- Filtering adapters:
apply rules to determine which targets should be informed, and
which should not be informed of each type of event.
The following Swing
example illustrates a good usage of event adapters and the technique of
using inner classes as event adapters.
Last modified June 13th, 1999
Michael Elhadad