Posts Tagged ‘GXT’
Tutorial: an Event Bus Handler for GWT / GXT
Overview
Introduction
Let’s consider a application, JonathanGwtApplication, divided in three main panels
- a panel to select animal name name
- a panel to display, expand and collapse trees of the animal ancestors
- a panel of information to display many indicators (colors, ages, etc.).
An issue we encounter is: how to make the different panels communicate? In more technical terms, how to fire events from a panel to another one?
A first solution would be to declare each panel as listener to the other panels. Indeed, this principle may go further, and declare each component as listener to a list of other components…
Main drawbacks:
- the code becomes hard to read
- adding or removing a component requires to modify many parts of the code
- we don’t follow GWT 2’s “philosophy”, which is to use
Handlers
rather thanListeners
.
Hence, these reasons incited us to provide a global EventBusHandler
.
The EventBusHandler
concept
The EventBusHandler
is a global bus which is aware of all events that should be shared between different panels, and fires them to the right components.
The EventBusHandler
is a field of JonathanGwtApplicationContext
.
Intrastructure
lalou.jonathan.application.web.gwt.animal.events.HandledEvent
: generic interface for a event. Abstract method:[java]EventTypeEnum getEventEnum();[/java]lalou.jonathan.application.web.gwt.animal.handler.EventHandler
: generic interface for a component able to handle an event. Abstract method:[java]void handleEvent(HandledEvent handledEvent);[/java]lalou.jonathan.application.web.gwt.animal.handler.EventHandlerBus
: the actual bus. As a concrete class, it has two methods:[java]/**
* Fires an event to all components declared as listening to this event
* event type.
*
* @param baseEvent
*/
public void fireEvent(HandledEvent baseEvent) {
// …
}/**
* Adds an listener/handler for the event type given as parameter
*
* @param eventTypeEnum
* @param eventHandler
* @return The List of handlers for the key given as parameter. This list
* contains the eventHandler that was given as second parameter
*/
public List<EventHandler> put(EventTypeEnum eventTypeEnum,
EventHandler eventHandler) {
// …
}[/java]
How to use the bus?
- Define an event: in JonathanGwtApplication, an event is decribed by two elements:
- a functionnal entity: eg: “animal”, “food”, “tree node”. The functionnal entity must be isomorph to a technical DTO, eg:
AnimalDTO
for an entity Animal.(in the scope of this turoriel we assume to have DTOs, even though the entities may ne sufficient) - a technical description of the event: “selection changed”, “is expanded”
- a functionnal entity: eg: “animal”, “food”, “tree node”. The functionnal entity must be isomorph to a technical DTO, eg:
- Add an entry in the enum
EventTypeEnum
. Eg: “ANIMAL_SELECTION_CHANGED
“ - in
lalou.jonathan.application.web.gwt.animal.events
, create an event, implementingHandledEvent
and its methodgetEventEnum()
. The match betweenEventTypeEnum
and DTO is achieved here. Eg:
[java]public class AnimalSelectionChangedEvent extends
SelectionChangedEvent<AnimalDTO> implements HandledEvent {public AnimalSelectionChangedEvent(
SelectionProvider<AnimalDTO> provider,
List<AnimalDTO> selection) {
super(provider, selection);
}public EventTypeEnum getEventEnum() {
return EventTypeEnum.ANIMAL_SELECTION_CHANGED;
}}[/java]
@Override
public void selectionChanged(SelectionChangedEvent<AnimalDTO> se) {
final AnimalDTO selectedAnimalVersion;
selectedAnimalVersion= se.getSelectedItem();
JonathanGwtApplicationContext.setSelectedAnimal(selectedAnimal);
final AnimalSelectionChangedEvent baseEvent = new AnimalSelectionChangedEvent(
se.getSelectionProvider(), se.getSelection());
JonathanGwtApplicationContext.getEventHandlerBus()
.fireEvent(baseEvent);
}
});[/java]
- easy case: the component handles only one type of event: this handler must implement the right interface (eg:
AnimalSelectionChangedEventHandler
) and its method, eg:[java]protected void handleAnimalSelectionChangedEvent(HandledEvent handledEvent) {
return;
}[/java] - frequent case: the component handles two or more event types. No matter, make the component implement all the needed interfaces (eg:
AnimalSelectionChangedEventHandler
,FoodSelectionChangedEventHandler
). Provide a unique entry point for the method to implement, which is common to both interfaces. Retrieve the event type, and handle it with ad hoc methods. Eg:[java]public void handleEvent(HandledEvent handledEvent) {
final EventTypeEnum eventTypeEnum;eventTypeEnum = handledEvent.getEventEnum();
switch (eventTypeEnum) {
case ANIMAL_SELECTION_CHANGED:
handleAnimalSelectionChangedEvent(handledEvent);
return;
case FOOD_SELECTION_CHANGED:
handleFoodSelectionChangedEvent(handledEvent);
return;
default:
break;
}
}protected void handleAnimalSelectionChangedEvent(HandledEvent handledEvent) {
// do something
}
protected void handleFoodSelectionChangedEvent(HandledEvent handledEvent) {
// do something else
}[/java]