A JGrapes application consists of a tree of components that interact using events.
Components can be defined in two ways. Classes can implement the interface
ComponentType and provide a special attribute
that allows them to access their component manager
(see the description of the interface
for details). Alternatively, classes
can inherit from
Component. This base class
ComponentType and also provides the
component manager for the component.
Manager interface enables the components
to access the functions of the framework. This includes methods
for manipulating the tree structure
Manager.detach() etc.) and methods
for sending and handling events
Manager.addHandler(Method, HandlerScope, int)).
Events are objects that trigger activities of the components that
handle them. Because components are usually only interested in certain
kinds of triggers, events implement the
interface that enables the user to obtain an event’s kind (as criterion)
and to filter events according to their kind.
As implemented in the base class
kind of an event is represented by its Java class. E.g. a
Started event is an instance
org.jgrapes.core.events.Started and its kind
Especially when building small sample applications, some programmers
prefer to use a name for representing the kind of an event. The core
package supports this by providing the
This class overrides
Event.isEligibleFor(Object) so that a
simple string is used to represent and match the event’s kind.
Event handlers are methods that are invoked by the framework.
These methods have return type
void and can have zero to
two parameters. If specified, the first parameter must be of type
Event (or, as usual, a subtype of
Event). The purpose of the second (optional) parameter will be
explained in the next section.
Event handlers are usually registered with the framework using
an annotation. The standard annotation for registering event handlers
Handler. See its definition
for usage examples. If special needs arise,
other annotations for registering handlers may be defined using the
If the information required for using the handler annotation is not
(completely) available at compile time, handler methods can also be added
at runtime using
Manager.addHandler(Method, HandlerScope, int).
Because events are usually only relevant for a subset of the application’s components, events are fired on so called channels. Event handlers are attached to one ore more of those channels.
In order for objects to be usable as channels, they must implement the
Channel interface, which implies implementing
Eligible interface. The core package
provides two predefined types of channels: the
ClassChannel, that uses a Java class for
identification and the
NamedChannel, that uses
a name (String) for identification.
A third group of channels is implicitly provided by the
Components, which implement the
Channel interface as well. This means that
every component can be used as a channel, with the eligibility defined
in such a way that the component’s handlers are always invoked
for events that are explicitly “targeted” at the component.
From a conceptional point of view, components fire events on one or
more channels, and the channels forward the events to all (0 to many)
interested event handlers (in reality, channels are only used as
identifiers in event management).
Manager.fire(Event, Channel...) for
a description of how to choose channels when fireing an event.
A handler is considered to be interested in an event if it has registered with one of the channels that the event is fired on and the event is of a type that the handler (annotation) has specified as being processed by the handler (see above)1.
The channels that an event has been fired on are made available
when the event is passed to an event handler by
Event.channels(). In some use cases, an
event handler has to perform an action for each of the channels. To
simplify this, an event handler may specify a second parameter
Channel. In this case, the handler
is invoked by the framework once for each channel that the event
was fired on. If the type of the second parameter is a subtype
Channel, it is invoked only if the
parameter is assignable from the actual channel.
The package supports some specific (java.util) logging settings.
- If set to FINE, causes events and their handlers to be logged before the handler is invoked. If set to FINER additionally causes events without any handler to be logged and if set to FINEST also logs the result of invoking a handler (the additional logging is done with log level FINE, just as the logging of the invocations). Enabling the invocation logging involves some performance penalty because additional information (not required for normal operation) has to be maintained.
- If set to FINE, the
event generators added and removed are tracked (usually, they are
only counted). Differences between the counted and the tracked
generators are reported as errors when
Components.awaitExhaustion()is invoked. In addition, the generators blocking the exhaustion are reported. If set to FINEST, addition and removal of generators is reported as well.
- If set to FINER, class names are converted to fully qualified names in toString() methods.
The mapping from a tuple “(event, channels)” to the handlers is evaluated once for a new tuple and then cached. So once the cache has been filled, event processing imposes only a relatively small constant overhead over invoking methods directly. The cache is cleared if the handlers are removed or added. Therefore, frequent changes of the applications structure whie running it should be avoided.↩
ClassDescriptionImplemented by classes that allow arbitrary objects to be associated with instances.Instances of this interface can be used as a communication bus for sending events between components.This interface’s class can be used to specify the component’s channel (see
Component.channel()) as criterion in handler annotations.This class is the root base class for channels that use their class (type) as value for matching (see
Eligible).A base class for events that signal the completion of some other (monitored) event and provide this other event as their result.Represents a lock that prevents sending completion events.This class can be used as base class for implementing a component.Deprecated.This class has been moved to
ComponentCollector.A general purpose factory interface for components.This class provides some utility functions.Implemented by classes that want a special class (scope) to be used for looking up their id or want to map to another object for getting the id (see
Components.objectId(Object)).An index of pooled items.Instances are added to the scheduler in order to be invoked at a given time.Represents a timer as created by
Components.schedule(TimeoutHandler, Instant).This interface marks a class as a component.This interface provides a mechanism for matching objects, using a filter on the object’s “kind” as criterion.Event<T>This class is the base class for all events.An interface that describes a queue of events that are sent to the components of the associated tree.This interface allows to verify whether a given event fired on one of the given channels is handled by a handler.The interface that provides the methods for manipulating the component and the component’s hierarchy and for firing events.This class provides channels that are identified by a name (
string).NamedEvent<T>A class for events using a simple name as the event’s kind.This interface type can be used to specify the object itself as channel in handler annotations.Represents a subchannel.A simple implementation of