Difference between revisions of "Eventing in Services"
(New page: Category:EiffelStudio Services Category:Extending EiffelStudio {{UnderConstruction}} Event specification is a little different from using action sequences in EiffelVision2 or in ...) |
(→Interface Designs) |
||
Line 12: | Line 12: | ||
When designing interfaces or a service interface the event type to use is the base event type interface <e>EVENT_TYPE_I</e>. <e>EVENT_TYPE</e> is actually the default implementation class for <e>EVENT_TYPE_I</e>. The difference between <e>EVENT_TYPE_I</e> and its implementation <e>EVENT_TYPE</e> is <e>EVENT_TYPE</e> also implements <e>EVENT_TYPE_PUBLISHER_I</e>. With respects to correct encapsulation design, an interfaces should always use <e>EVENT_TYPE_I</e> because no interface should allow a client to publish an event. Events should only be raised in context. | When designing interfaces or a service interface the event type to use is the base event type interface <e>EVENT_TYPE_I</e>. <e>EVENT_TYPE</e> is actually the default implementation class for <e>EVENT_TYPE_I</e>. The difference between <e>EVENT_TYPE_I</e> and its implementation <e>EVENT_TYPE</e> is <e>EVENT_TYPE</e> also implements <e>EVENT_TYPE_PUBLISHER_I</e>. With respects to correct encapsulation design, an interfaces should always use <e>EVENT_TYPE_I</e> because no interface should allow a client to publish an event. Events should only be raised in context. | ||
+ | === Interface Event Declarations === | ||
+ | Take the following rudimentary interface definition with a single event <e>changed_event</e>: | ||
<e> | <e> | ||
deferred class | deferred class | ||
Line 21: | Line 23: | ||
feature -- Events | feature -- Events | ||
− | changed_event: ! | + | changed_event: !EVENT_TYPE_I [TUPLE [flags: INTEGER]] |
-- Events call when a change occurs | -- Events call when a change occurs | ||
require | require | ||
Line 33: | Line 35: | ||
end | end | ||
</e> | </e> | ||
+ | The first point to recognize is the name of the event feature is singular and not plural. It is, after all, an event and not a collection of events. An event will have multiple actions subscribed to it, all called when published, but it is still a single event. | ||
+ | The design opts to define a deferred feature for specification of the event. As with all interface definitions should be free from all specific implementation and bindings to a particular declaration style, unless necessary of course. The implementation is now free to implement the event as a once, once-per-object, self-attribute or using a lazy-instantiation model (the latter being commonly used for efficient memory management and clean-up.) | ||
+ | |||
+ | Finally, the <e>Result</e> type of the event feature is <e>EVENT_TYPE_I</e> and not the more specific <e>EVENT_TYPE</e>. As previously mentioned, the latter effective type contains means to publish the events, which should not be accessed by any client. | ||
+ | |||
+ | === Supporting Events === | ||
<e> | <e> | ||
class | class | ||
Line 51: | Line 59: | ||
<e> | <e> | ||
+ | deferred class | ||
+ | INTERFACE_I | ||
+ | |||
+ | inherit | ||
+ | USABLE_I | ||
+ | |||
+ | feature -- Access | ||
+ | |||
+ | interface_connection: EVENT_CONNECTION_I [INTERFACE_OBSERVER, INTERFACE_I] | ||
+ | -- Connection point for {INTERFACE_I} events. | ||
+ | require | ||
+ | is_interface_usable: is_interface_usable | ||
+ | local | ||
+ | l_target: INTERFACE_OBSERVER | ||
+ | attribute | ||
+ | create l_target | ||
+ | create {EVENT_CONNECTION [INTERFACE_OBSERVER, INTERFACE_I]} | ||
+ | Result.make_from_array (<< | ||
+ | -- Event-Action map | ||
+ | [changed_event, agent l_target.on_changed] | ||
+ | >>) | ||
+ | end | ||
+ | |||
+ | feature -- Events | ||
+ | |||
+ | changed_event: !EVENT_TYPE_I [TUPLE [flags: INTEGER]] | ||
+ | -- Events call when a change occurs | ||
+ | require | ||
+ | is_interface_usable: is_interface_usable | ||
+ | deferred | ||
+ | ensure | ||
+ | result_consistent: Result ~ changed_event | ||
+ | result_is_interface_usable: Result.is_interface_usable | ||
+ | end | ||
+ | |||
+ | end | ||
</e> | </e> | ||
+ | |||
== Event Connections and Observers == | == Event Connections and Observers == | ||
To Su | To Su |
Revision as of 13:05, 16 December 2008
Event specification is a little different from using action sequences in EiffelVision2 or in other action-based eventing systems. ESS should not use ACTION_SEQUENCE like in these other systems but a specialized type called EVENT_TYPE. There is a support framework for ESS wrapped around EVENT_TYPE and a observer design pattern to simplify use.
Contents
Event vs Action
A new eventing model was used in ESS as not to conflict of alter the existing mechanisms in EiffelBase. In addition, services act on or raises an "event". With respects to EiffelVision2 an action is event that is performed in response to some action.
Interface Designs
When designing interfaces or a service interface the event type to use is the base event type interface EVENT_TYPE_I
. EVENT_TYPE
is actually the default implementation class for EVENT_TYPE_I
. The difference between EVENT_TYPE_I
and its implementation EVENT_TYPE
is EVENT_TYPE
also implements EVENT_TYPE_PUBLISHER_I
. With respects to correct encapsulation design, an interfaces should always use EVENT_TYPE_I
because no interface should allow a client to publish an event. Events should only be raised in context.
Interface Event Declarations
Take the following rudimentary interface definition with a single event changed_event
:
deferred class INTERFACE_I inherit USABLE_I feature -- Events changed_event: !EVENT_TYPE_I [TUPLE [flags: INTEGER]] -- Events call when a change occurs require is_interface_usable: is_interface_usable deferred ensure result_consistent: Result ~ changed_event result_is_interface_usable: Result.is_interface_usable end end
The first point to recognize is the name of the event feature is singular and not plural. It is, after all, an event and not a collection of events. An event will have multiple actions subscribed to it, all called when published, but it is still a single event.
The design opts to define a deferred feature for specification of the event. As with all interface definitions should be free from all specific implementation and bindings to a particular declaration style, unless necessary of course. The implementation is now free to implement the event as a once, once-per-object, self-attribute or using a lazy-instantiation model (the latter being commonly used for efficient memory management and clean-up.)
Finally, the Result
type of the event feature is EVENT_TYPE_I
and not the more specific EVENT_TYPE
. As previously mentioned, the latter effective type contains means to publish the events, which should not be accessed by any client.
Supporting Events
class INTERFACE_OBSERVER feature -- Event Handler on_changed (a_flags: INTEGER) -- require is_interface_usable: {l_usable: USABLE_I} Current implies l_usable.is_interface_usable do end end
deferred class INTERFACE_I inherit USABLE_I feature -- Access interface_connection: EVENT_CONNECTION_I [INTERFACE_OBSERVER, INTERFACE_I] -- Connection point for {INTERFACE_I} events. require is_interface_usable: is_interface_usable local l_target: INTERFACE_OBSERVER attribute create l_target create {EVENT_CONNECTION [INTERFACE_OBSERVER, INTERFACE_I]} Result.make_from_array (<< -- Event-Action map [changed_event, agent l_target.on_changed] >>) end feature -- Events changed_event: !EVENT_TYPE_I [TUPLE [flags: INTEGER]] -- Events call when a change occurs require is_interface_usable: is_interface_usable deferred ensure result_consistent: Result ~ changed_event result_is_interface_usable: Result.is_interface_usable end end
Event Connections and Observers
To Su