mercredi 27 novembre 2013

Event based communication between wicket components


when we have a page structured with multiple panels, we need some times to update a component into a one panel following an event into another different panel in the same page, so how can we fix this type of scenario?
Starting from version 1.5 Wicket offers an event-based infrastructure for inter-component
communication. The infrastructure is based on two simple interfaces (both in package org.
apache.wicket.event) : IEventSource and IEventSink.

FIRST sending an event:

The first interface must be implemented by those entities that want to broadcast en event while the
second interface must be implemented by those entities that want to receive a broadcast event.
The following entities already implement both these two interfaces (i.e. they can be either sender or
receiver): Component, Session, RequestCycle and Application.
IEventSource exposes a single method named send which takes in input three parameters:
  1. sink: an implementation of IEventSink that will be the receiver of the event.
  2. broadcast: a Broadcast enum which defines the broadcast method used to dispatch the event to the sink and to other entities such as sink children, sink containers, session object,application object and the current request cycle. It has four possible values:
    1. BREADTH: The event is sent first to the specified sink and then to all its children components following a breadth-first order.
    2. DEPTH: The event is sent to the specified sink only after it has been dispatched to all its children components following a depth-first order.
    3. BUBBLE: The event is sent first to the specified sink and then to its parent containers.
    4. EXACT: The event is sent only to the specified sink.
  3. payload: a generic object representing the data sent with the event.
Each broadcast mode has its own traversal order for Session, RequestCycle and Application.
The below example shows an event sending. This method can be used from any other component: First you need to create one class to encapsulate the notification and the AjaxRequestTarget and pass them using the events infrastructure.
 
private class Notification {
    private String message;
    private AjaxRequestTarget target;
    ... constructor, getters, setters...
}
 
 send(getSession(), Broadcast.BREADTH, new Notification(message, target));

NEXT Receiving the event : 

Interface IEventSink exposes callback method onEvent(IEvent<?> event) which is triggered
when a sink receives an event. The interface IEvent represents the received event and provides getter
methods to retrieve the event broadcast type, the source of the event and its payload. Typically the
received event is used checking the type of its payload object :
 
@Override
public void onEvent(IEvent event) {
    if (event.getPayload() instanceof Notification) {
        Notification notification = (Notification) event.getPayload();
        ... do whatever you want before updating the panel ...
        // Update the panel 
        notification.getTarget().add(this);
    }
}
 You find in this link a project named InterComponetsEventsExample provides a concrete example of sending an event to a component (named 'container in the middle') using all the available broadcast methods: