e853cf861b
This patch adds an 'Event' class which may be used to issue various notifications to other MuranoPl classes in an Event-driven manner. Any object which is going to emit the notifications should declare the instances of this new class as its public Runtime properties. The objects going to subscribe for the notifications should pass themselves into the 'subscribe' method of the Event along with the names of their methods which will be used to handle the notification. The specified handler methods must be present in the subscriber class (if the method name is missing it will be defaulted to the 'handle%Eventname%') and has at least one standard (i.e. non-vararg or kwarg) argument. The class going to emit the notification should call the 'notify' method of the event and pass itself as the first argument. All the optional parameters of the event may be passed as varargs/kwargs of the 'notify' call and will be passed all the way to the handler methods. Since this approach relies on the reflection this patch also fixes a bug #1596647 since its fix is required for the argument reflection to work properly. It also documents new reflection capabilities which were added as part of the bugfix. Targets-blueprint: application-development-framework Closes-Bug: #1596647 Change-Id: Ifa7053e4c7b8456030e8df743f57ed812104b064
105 lines
3.1 KiB
YAML
105 lines
3.1 KiB
YAML
|
|
Namespaces:
|
|
=: io.murano.applications
|
|
std: io.murano
|
|
py: # empty, for python-originating exceptions
|
|
|
|
|
|
--- # ------------------------------------------------------------------ # ---
|
|
|
|
Name: Event
|
|
|
|
Properties:
|
|
name:
|
|
Contract: $.string().notNull()
|
|
|
|
Methods:
|
|
|
|
.init:
|
|
Body:
|
|
- $this._handlers: {}
|
|
|
|
subscribe:
|
|
Arguments:
|
|
- subscriber:
|
|
Contract: $.class(std:Object).notNull()
|
|
- methodName:
|
|
Contract: $.string()
|
|
Body:
|
|
- If: not $methodName
|
|
Then:
|
|
- $methodName: format('handle{0}', $this.name.substring(0,1).toUpper()+
|
|
$this.name.substring(1))
|
|
|
|
- Try:
|
|
- $method: typeinfo($subscriber).methods.where($.name = $methodName).single()
|
|
Catch:
|
|
With: py:StopIteration
|
|
Do:
|
|
- Throw: NoHandlerMethodException
|
|
Message: format('Unknown method {0} for
|
|
receiver {1} to handle event {2}',
|
|
$methodName, $subscriber, $this.name)
|
|
|
|
# This check ensures that the method passed as a handler has at least one
|
|
# standard (i.e. non vararg or kwarg) argument which is supposed to be
|
|
# "sender" object of the event.
|
|
# Although having the sender in the handler is not always nessesary it's
|
|
# still better to enforce its presence since it helps to prevent many
|
|
# hard-to-debug errors
|
|
- If: not $method.arguments.where($.usage=Standard).any()
|
|
Then:
|
|
- Throw: WrongHandlerMethodException
|
|
Message: format("Method {0} of handler {1} should accept at least
|
|
a 'sender' argument to handle event {2}",
|
|
$methodName, $subscriber, $this.name)
|
|
- $key: list($subscriber, $methodName)
|
|
- $this._handlers[$key]: $this._handlers.get($key, 0) + 1
|
|
|
|
unsubscribe:
|
|
Arguments:
|
|
- subscriber:
|
|
Contract: $.class(std:Object).notNull()
|
|
- methodName:
|
|
Contract: $.string()
|
|
Body:
|
|
- If: not $methodName
|
|
Then:
|
|
- $methodName: format('handle{0}', $this.name.substring(0,1).toUpper()+
|
|
$this.name.substring(1))
|
|
- $key: list($subscriber, $methodName)
|
|
- If: $key in $this._handlers.keys()
|
|
Then:
|
|
- $this._handlers[$key]: $this._handlers[$key] - 1
|
|
- If: $this._handlers[$key] = 0
|
|
Then:
|
|
- $this._handlers: $this._handlers.delete($key)
|
|
|
|
notify:
|
|
Arguments:
|
|
- sender:
|
|
Contract: $.notNull()
|
|
- args:
|
|
Contract: $
|
|
Usage: VarArgs
|
|
- kwargs:
|
|
Contract: $
|
|
Usage: KwArgs
|
|
Body:
|
|
- $combinedArgs: list($sender) + $args
|
|
- $this._handlers.keys().select(call($[1], $combinedArgs, $kwargs, $[0]))
|
|
|
|
notifyInParallel:
|
|
Arguments:
|
|
- sender:
|
|
Contract: $.notNull()
|
|
- args:
|
|
Contract: $
|
|
Usage: VarArgs
|
|
- kwargs:
|
|
Contract: $
|
|
Usage: KwArgs
|
|
Body:
|
|
- $combinedArgs: list($sender) + $args
|
|
- $this._handlers.keys().pselect(call($[1], $combinedArgs, $kwargs, $[0]))
|