5.5 Application Events - Reference Documentation
Authors: Andres Almiray
Version: 1.2.0
Table of Contents
5.5 Application Events
Applications have the ability to publish events from time to time to communicate that something of interest has happened at runtime. Events will be triggered by the application during each of its life cycle phases, also when MVC groups are created and destroyed.All application event handlers are guaranteed to be called in the same thread that originated the event.Any artifact or class can trigger an application event, by routing it through the reference to the current running application instance. All artifacts posses an instance variable that points to that reference. All other classes can use ApplicationHolder to gain access to the current application's instance.Publishing an event can be done synchronously on the current thread or asynchronously relative to the UI thread. For example, the following snippet will trigger an event that will be handled in the same thread, which could be the UI thread itself
app.event('MyEventName', ['arg0', 'arg1'])
MyEventName
will be called outside of the UI threadapp.eventOutsideUI('MyEventName', ['arg0', 'arg1'])
app.eventAsync('MyEventName', ['arg0', 'arg1'])
app.eventPublishingEnabled = false
app.eventPublishingEnabled = true
5.5.1 Life Cycle Events
The following events will be triggered by the application during each one of its phasesBootstrapStart[app]
- after logging configuration has been setup, during the Initialize phase.BootstrapEnd[app]
- at the end of the Initialize phase.StartupStart[app]
- at the beginning of the Startup phase.StartupEnd[app]
- at the end of the Startup phase.ReadyStart[app]
- at the beginning of the Startup phase.ReadyEnd[app]
- at the end of the Startup phase.ShutdownRequested[app]
- before the Shutdown begins.ShutdownAborted[app]
- if a Shutdown Handler prevented the application from entering the Shutdown phase.ShutdownStart[app]
- at the beginning of the Shutdown phase.
5.5.2 Artifact Events
The following events will be triggered by the application when dealing with artifactsNewInstance[klass, type, instance]
- when a new artifact is created.DestroyInstance[klass, type, instance]
- when an artifact instance is destroyed.LoadAddonsStart[app]
- before any addons are initialized, during the Initialize phase.LoadAddonsEnd[app, addons]
- after all addons have been initialized, during the Initialize phase.addons
is a Map of <name, instance> pairs.LoadAddonStart[name, addon, app]
- before an addon is initialized, during the Initialize phase.LoadAddonEnd[name, addon, app]
- after an addon has been initialized, during the Initialize phase.
InitializeMVCGroup[configuration, group]
- when a new MVC group is initialized.configuration
is of type MVCGroupConfiguration;group
is of type MVCGroup.CreateMVCGroup[group]
- when a new MVC group is created.configuration
is of type MVCGroupConfiguration;group
is of type MVCGroup.DestroyMVCGroup[group]
- when an MVC group is destroyed.group
is of type MVCGroup.
5.5.3 Miscellaneous Events
These events will be triggered when a specific condition is reachedUncaughtExceptionThrown[exception]
- when an uncaught exception bubbles up to GriffonExceptionHandler.WindowShown[window]
- triggered by the WindowManager when a Window is shown.WindowHidden[window]
- triggered by the WindowManager when a Window is hidden.
5.5.4 Custom Events
Any artifact that holds a reference to the current application may trigger events at its leisure by calling theevent()
or eventAsync
methods on the application instance. The following example demonstrates how a Controller triggers a "Done" event after an action has finishedclass MyController { def action = { evt = null -> // do some work app.event('Done') } }
event()
method. The first takes just the name of the event to be published; the second accepts an additional argument which should be a List of parameters to be sent to every event handler. Event handlers notified by this method are guaranteed to process the event in the same thread that published it. However, if what you need is to post a new event and return immediately then use the eventAsync
variants. If you want the event to be handled outside of the UI thread then use the eventOutsideUI()
variants.
5.5.5 Event Handlers
Any artifact or class that abides to the following conventions can be registered as an application listener, those conventions are:- it is a Script, class, Map, RunnableWithArgs or closure.
- in the case of scripts or classes, they must define an event handler whose name matches on<EventName>, this handler can be a method, RunnableWithArgs or a closure property.
- in the case of a Map, each key maps to <EventName>, the value must be a RunnableWithArgs or a closure.
- scripts, classes and maps can be registered/unregistered by calling
addApplicationListener
/removeApplicationListener
on the app instance. - RunnableWithArgs and closure event handlers must be registered with an overloaded version of
addApplicationListener
/removeApplicationListener
that takes <EventName> as the first parameter, and the runnable/closure itself as the second parameter.
Events.groovy
inside griffon-app/conf
. Lastly both Controller and Service instances are automatically registered as application event listeners. This is the only way to declare event listeners for the BootstrapStart
event.You can also write a class namedThese are some examples of event handlers:Events.java
insrc/main
as an alternative togriffon-app/conf/Events.groovy
, but not both!
- Display a message right before default MVC groups are instantiated
File: griffon-app/conf/Events.groovy
onBootstrapEnd = { app -> println """Application configuration has finished loading. MVC Groups will be initialized now.""" }
- Quit the application when an uncaught exception is thrown
File: src/main/Events.java
import griffon.util.ApplicationHolder;public class Events { public void onUncaughtExceptionThrown(Exception e) { ApplicationHolder.getApplication().shutdown(); } }
- Print the name of the application plus a short message when the application is about to shut down.
File: griffon-app/controller/MyController.groovy
class MyController {
def onShutdownStart = { app ->
println "${app.config.application.title} is shutting down"
}
}
- Print a message every time the event "Foo" is published
File: griffon-app/controller/MyController.groovy
class MyController { void mvcGroupInit(Map args) { app.addApplicationListener([ Foo: {-> println 'got foo!' } ]) } def fooAction = { evt = null -> // do something app.event('Foo') } }
- An alternative to the previous example using a closure event handler
File: griffon-app/controller/MyController.groovy
class MyController { void mvcGroupInit(Map args) { app.addApplicationListener('Foo'){-> println 'got foo!' } } def fooAction = { evt = null -> // do something app.event('Foo') } }
- Second alternative to the previous example using a RunnableWithArgs event handler
File: griffon-app/controller/MyController.java
import java.util.Map; import griffon.util.RunnableWithArgs; import org.codehaus.griffon.runtime.core.AbstractGriffonController;public class MyController extends AbstractGriffonController { public void mvcGroupInit(Map<String, Object> params) { getApp().addApplicationListener("Foo", new RunnableWithArgs() { public void run(Object[] args) { System.out.println("got foo!"); } }); } public void fooAction() { // do something getApp().event("Foo"); } }
5.5.6 Custom Event Publishers
As the name implies application events are sent system wide. However there is an option to create localized event publishers. Griffon provides a @griffon.transform.EventPublisher AST transformation that you can apply to any class that wishes to be an event publisher.This AST transformation will inject the following methods to the annotated classes:- addEventListener(Object)
- addEventListener(String, Closure)
- addEventListener(String, RunnableWithArgs)
- removeEventListener(Object)
- removeEventListener(String, Closure)
- removeEventListener(String, RunnableWithArgs)
- publishEvent(String)
- publishEvent(String,List)
- publishEventOutsideUI(String)
- publishEventOutsideUI(String,List)
- publishEventAsync(String)
- publishEventAsync(String,List)
- isEventPublishingEnabled()
- setEventPublishingEnabled(boolean)
@griffon.transform.EventPublisher class Publisher { void doit(String name) { publishEvent('arg', [name]) } void doit() { publishEvent('empty') } }class Consumer { String value void onArg(String arg) { value = 'arg = ' + arg } void onEmpty() { value = 'empty' } }p = new Publisher() c = new Consumer() p.addEventListener(c) assert !c.value p.doit() assert c.value == 'empty' p.doit('Groovy') assert c.value == 'arg = Groovy'