Using YANCEES - Project Documentation |
Writing Simple Clients | | Starting YANCEES Server |
Sample Configurations |
Understanding The Design Dimensions | | Examples | |
YANCEES is a versatile publish/subscribe infrastructure. The current implementation provides an extensible and configurable event-based framework. Extension points are layd over the main design dimensions of a publish/subscribe system. These dimensions are the subscription, notification, publicatoin, event and protocol models. Additionally, YANCEES provides support for static plub-ins (a.k.a. services). The architecture is flexible enough to allow the distribution of components through client and server sides, providing flexibility to the resource model.
Subscription and notificatoin models are defined in terms of extensible languages, that syntactically describe the primitives, commands and messages of each model; Associated to each sets of elements in these languages are plug-ins. The dynamic binding of plug-ins with syntactical constructs in the language provides the desired functionality in each dimension. Internally, this dynamic plug-in allocation is performed by dynamic parsers associated to the subscription, notification and protocol models.
In short, YANCEES provides:
import edu.uci.isr.yancees.YanceesEvent; |
|
<subscription> |
notify(EventInterface myEvent) and
notify(EventInterface[] myEventList) which receive a single event or a pattern matching of events.
The subscriber then registers itself as a listener for
notifications in the method subscribe(). After that, it starts
receiving notifications whenever the subscriptioin is match, in
response to an event publication.
import edu.uci.isr.yancees.YanceesEvent; |
In this section, we briefly explain the main extensibility dimensions, their models and how to extend them. At the end of this section, full examples are provided. All design dimensions are represented by a language, defined in XMLSchema, and plug-ins, implemented to provide the functionality.
The
event model deals with the way events are
represented.
The basic event model supported by current YANCEES implementation is
tuple-based. In this
model, an
event is a set of attribute/value pairs. This model is very flexible
and allows
the implementation of more restrictive models such as record-based
(fixed set of
attributes/types) and subject-based (having a special attribute to
distinguish
events from different types) models. The enforcement of these rules can
be
achieved by the use of input and output filters as will de discussed
later.
Note:
Event models are usually bound to the event router used in the
framework. Currently, we support Elvin, Siena, and a proprietary fast
switch router. Other event representations can be defined provided that
a router, that understands that representation, is installed in the
framework. Different routers can be simultaneously used.
Events are represented as sets of attributes which have name, type and value. Events in YANCEES can be represented as YanceesEvent objects or in XML format as the example below.
|
This format was chosen to provide the ability to represent large attribute values, such as binary files, text files, and long strings in between <value> tags (as opposed to use attribute and value as attributes of the tag, instead of elements as it is represented now). The types supported in current YANCEES implementation are the same as provided by the XML schema: boolean, double, float, long, int, string, hexBinary which, for the sake of limiting the possible attribute types, facilitating the parsing of the events, and coping with extensibility, are represented as: yanceesBoolean, yanceesDouble, yanceesFloat, yanceesLong, yanceesInt, yanceesString and yanceesBinary types.
In order to extend the event
model, developers extend the GenericMessage interface and optionally change the event schema with the new features,
using the inheritance and extensibilty feautres of the XMLSchema
definition. Alternatively, one can define a new event representation
(or schemas).
Once the extension is defined, it must be implemented by plug-ins or by the adapter installed in the YANCEES framework. For example, if events are represented as generic HTML pages, it is the responsibility of the notification server adapter to receive this events and transform them, back and forth, from this representation to the native representation of the installed event dispatcher. In our current YANCEES prototype implementation, this is performed by the SienaAdapter or ElvinAdapter, with the help of the SienaEvent and ElvinEvent classes. These last classes convert the internal event representation to the native representation of Siena and Elvin, respectively, and vice-versa. The adapters are responsible for reading publish and subscribe commands and converting them to the native Siena and Elvin formats respectively.
The subscription language allows an interested party (or subscriber) to specify its interest in a sub-set of events. The subscription language allows the specification of constraints in both the content and the order the events to be queried (including their type or subject in other event models). This is usually performed through the use logical expressions (or queries), based on special commands. For example, a <sequence> command can be defined to detect sequences of events; a <filter> command inquires about the content of the events and so on. These commands can be combined in subscription expressions that are interpreted by the Yancees SubscriptionParser.
In the point of view of the YANCEES framework, simple subscriptions are represented as combinations of operators over events and their attributes. These operators are combined in logical expressions that, when matched, result in the delivery of the events to the end user. Operators are combined in a reverse polish notation as shown in the example below (in other words, it uses a LISP-like function composition syntax where operators comes before operands).
Complex subscriptions can be defined to generate new events, combine and abstract them. The classical example are rules. Rules are composed of a simple subscription part and an action part. The action can produce new events, and usually operate on the results of the subscription (condition).
|
Example of a rule specification...
|
The subscription model is extended by two combined steps: (1) the extension of the subscription language, which is defined in XMLSchema, by the definition of new tags (operators); (2) the implementation of plug-ins to handle those new tags, according to their syntax rules, defined in the XMLSchema extension. The plug-ins and their tags are then installed in the system using the configuration file, which associates their binaries with the appropriate XML tags in the plug-in manager.
The notification language specifies policies and procedures that deal with the delivery of events after their matching by a subscription expression. It allows, for example, the specification that events must be delivered as soon as they are produced, using <push> policy, or over subscriber request, using <pull>. Examples of extensions, or additional options, of such policies may include validity (the time an event should be kept in the server waiting for a deliver request); or a time interval (period) that all events matched in a subscription and stored for delivery, up to a certain point of time, must be delivered.
The notification policies are usually included at the end of a subscription message to the server, in the <notification> section, as presented in the following example.
|
The notification model is extended in the same way as the subscription model. Extensions in the notification language need to be implemented by the plug-ins that will handle that commands expressed in the subscription message. Whenever the subscription is matched, the result is sent to the specified notification plug-in. Extensions such as pull may store the events in a temporary repository. These events are then collected by the subscriber with the help of protocol plug-ins.
The protocol model allows the specification of more complex interaction modes with the service (apart from the common publish/subscription of events). The idea is to allow the addition of new services to the common publish/subscribe model. Examples of protocols may include the identification and browsing of event source hierarchies (with primitives similar to CASSIUS); support for mobile clients (with move-in/move-out primitives); authentication protocols and so on.
Protocols are implemented by plug-ins that externalize the protocol API using Remote interfaces in Java RMI. These plug-ins are dynamically loaded, being created and accessed through factory methods in YANCEES API. This way, a protocol can implement an arbitrary complex interface, representing protocol messages, which adds flexibiltiy to the model. Protocol plug-ins can interact with other YANCEES plug-ins. In order to locate installed plug-ins YANCEES internal plug-in registry stores a reference to all active plug-ins (static or dynamic) at any given time.
The current implementation of YANCEES uses RMI. A plug-in must implement a remote interface and responds to the remote method invocations. A session is created between the client and the plug-in, through the plug-in manager, based on the service requested through YANCEES API.
The resource model allows the definition of the components of the system, and their location. In the current implementation, the resource model is provided by a configuration language. This language allows the configuration of plug-ins, services and filters that are installed in the server, as well as the dispatcher components to be used.
The configuration file allows the specification of the files that implement the plug-ins, services, filters and adapters of the whole system. It is subdivided in 5 sections, the dispatcher section, which configures the adapter(s) and the notification server(s) used in a configuration, the subscription section which defined subscription plug-ins; the notification and protocol sections with the same syntax as the subscription, defining their plug-ins. Finally services and input and output filters can also be defined. A configuration file looks like the one presented below.
<architecture> |
DESIGN DIMENSION | HOW TO EXTEND | EXAMPLE EXTENSIONS |
Subscription Model | Extensible subscription language together with subscription plug-ins. Services and filters can also be used by the plug-ins | Event
aggregation Abstraction Rules (Event-condition/action Sequence detection and rules |
Event Model | Extensible
event
representation language or GenericMessage interface. Decoupling provided by the event adapter. Plug-in to handle adapter-specific features and language. |
Tuple-bassed
(attribute/value
pairs) Record-based Object-based Typed and un-typed events |
Publication Model | Extensible FilterInterface. Filters are insterded in a chain of responsibility fasion that intercepts the publicatoin of events in YANCEES | PublishToPeers plug-in that diverges events to peers in a P2P Yancees model. Type Checking, Event Persistency |
Notification Model | Extensible notification language together with notification plug-ins that implement event delivery policies | Push Pull (with persistency) |
Resource Model | Server
configuration language
which is interpreted by the configuration manager. It allows the distribution of components through the client side or server side. |
Centralized Partially-centralized Client-side components |
Protocol Model | Extensible
protocol language
together with Protocol plug-ins. |
Security
protocols Mobility Protocols Configuration protocols |
Once the languages are extended to include new primitives, commands and representations, plug-ins must be defined to actually implement and handle this new functionality. Dynamic (notification, subscription and protocol) parsers perform this dynamic instantiation and composition of plug-ins for each new subscription request. Plug-ins, however, are allocated on demand, usually one set for each subscription posted in the server.
The plug-in life cycle ends when the subscription is not necessary anymore. This model is stateless and usually requires some external persistency that spans different plug-in activations. Another need is access to external resources such as database systems, data models, applications and so on. In order to cope with these extra requirements, services are provided. Services are objects that remain active in the system during the whole execution of the server and can be accessed by plug-ins whenever required. They enhance plug-ins with persistency and other services.
Filters provide extension points in both the input and output buffers of the server, allowing the implementation of pre and post processing tasks, data collection and policy enforcements, for example. They usually apply to all input and output events. For example, plug-ins can collect performance information for further analysis, they can enforce event types, security policies and so on.
This section describes in more detail how to implement the system's plug-ins, services and filters, presenting their interfaces.
interface PluginInterface |
public interface ServiceInterface { |
public interface FilterInterface { |
The configuration manager installs and configures the main components of the system. Configurations are expressed using the YANCEES configuration language, which is provided to the YANCEES runtime during its bootstrap. An example of configuration file was previously presented in the extensibility dimensions section.
To illustrate the use of the architecture extensibility and configurability, this section presents some examples on how to define and adapt the components of the system to implement different services. It also shows how YANCEES can be customized to provide the functionality required by different application domains.
For example, suppose that YANCEES needs to be adapted to support awareness applications. Notification servers such as Khronika and CASSIUS provide us with a list of the basic services needed. Hence, in order to be functionality-compatible with this domain, YANCEES needs to provide: event persistency and typing, event sequence detection, and the pull notification delivery mechanism. Moreover, a special feature provided by CASSIUS is the ability to browse and later subscribe to the event types that are published by each event source. This service, called event source browsing, provides information about the publishers and the events they publish.
Sequence detection requires the extension of the subscription model with the addition of a new keyword <sequence>. It will operate over a set of content-based filters, which are natively provided by the event dispatcher component.
The first step is to extend the YANCESS subscription language with the new <sequence> tag. This is illustrated in the code fragment of Table 1 as follows.
<complexType name="SequenceSubscriptionType"> <complexType name="FilterSequenceType"> |
The next step is to implement the sequence detection plug-in, extending the AbstractPlugin, a convenience class that provides default implementations to the plug-in interface presented in Table 2 as follows.
interface PluginInterface |
Note that the PluginInterface is a listener to events produced in other plug-ins. It implements the interface in Table 3 as follows.
interface PluginListenerInterface { |
A simple sequence detection implementation will collect, in the right order, events coming from each one of the filters it observes. When a successful sequence is detected, the sequence plug-in returns the set of events collected, publishing it to higher-level plug-ins (listeners). Note that we are assuming that the event dispatcher guarantees the in-order delivery of events. If this is not the case, more complex algorithms must be used.
A plug-in factory, implementing the interface in Table 4 must also be defined.
interface PluginFactoryInterface { |
A simple factory implementation will return a new instance of the plug-in only each time the createNewInstance() method is invoked in its interface. The plug-in factory must then be registered under the “sequence” tag name in the YANCEES configuration file described in Table 5, followed by the restart or reconfiguration of the YANCEES service.
<subscription> |
The plug-in is then ready to be used. It will be activated each time a subscription is provided that uses the <sequence> tag as its part. An example of a subscription using this new extension is presented in Table 6. The Java DOM parser automatically checks the subscription for syntax errors by using the XML schema defined in Table 1.
<subscription> |
Pull delivery allows subscribers to periodically poll (or check) the server for new events matching their subscriptions. This mechanism copes with the requirements of some mobile applications, where subscribers usually get temporarily disconnected.
This mechanism is provided by a pull notification plug-in. In order to temporarily store the events that are not being delivered, the pull mechanism needs an event persistency service. As a consequence, together with the pull notification plug-in, an event persistency service must also be defined.
Users need to control when to collect and when to store the events being routed to them as a result of a subscription. This usually requires a polling interaction protocol. This interaction is not part of the regular publish() and subscribe() commands of a notification server, so a protocol plug-in must be defined. In short, the implementation of a pull delivery mechanism requires:
The pull plug-in implementation is very simple; it directs the events to the persistency service component and registers them under their target subscriber interface.
The poll plug-in responds to commands such as <poll-interval>, <stop-polling> and <poll>, which define different polling mechanisms. It collects the events stored in the persistency service, and delivers them periodically to the subscriber (poll-interval command); it then collects the notifications whenever requested (using the poll command) or deactivates the periodic delivery (using the stop-polling command) in case of a temporary disconnection.
These sets of plug-ins define a configuration, a set of components that need to be present in order for a service to operate. The dependencies between these are checked by YANCEES with the help of the <depends> clause in the configuration file.
In addition to the features described in the previous sessions, CASSIUS provides event typing and the ability to browse through hierarchies of event sources.
The browsing of event sources in CASSIUS allows publishers to register events in a hierarchy based on accounts and objects. This model and the API required to operate the server are described elsewhere.
In the YANCEES framework, the CASSIUS functionality is implemented by the use of protocol plug-ins and a CassiusService component. The CASSIUS protocol plug-in interacts with the CassiusService, which allows the creation and management of objects, accounts, and their events. These operations include registering/un-registering accounts, objects, and events, as well as polling commands.
CASSIUS uses events with a fixed set of attributes. These events can be easily identified and checked for correctness by an input filter. This filter checks all incoming events for the proper CASSIUS template format. Once a CASSIUS event is identified and validated, it is copied to the CassiusService, which stores it in a database in its proper account/object record.
Polling of events, in this case, is handled by the CASSIUS protocol plug-in, which allows the collection of events by account, object, or sub-hierarchies. Note that this approach does not prevent the simultaneous installation of both services, the simple pull and the CASSIUS pull protocol.
The poll mechanism is not the only
way to collect CASSIUS events. At any time, subscriptions can also be
performed on regular CASSIUS events.
This section describes the functionality of the components currently available to the YANCEES framework. It is subdivided according to the extensibilty dimensions: event model, subscription model, notification mode and protocol.
In the current YANCESS version, the events are represented as sets of attribute/value pairs.
Supports conent-based and topic-based subscrtiptins. The content-based language is a XML porting of the Siena Subscription language. The topic-based language, is implemented by the <require> tag with behaves similarly to the Elvin require() command.
Supports <push> and <pull>
supports polling, to access the event stored on the server side, if the <pull> notification policy is used.
P.S. I will expand these last topics later on...