Search
Calendar
December 2018
S M T W T F S
« Sep    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  
Your widget title
Archives

Posts Tagged ‘bus’

PostHeaderIcon 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 than Listeners.

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:
    EventTypeEnum getEventEnum();
  • lalou.jonathan.application.web.gwt.animal.handler.EventHandler: generic interface for a component able to handle an event. Abstract method:
    void handleEvent(HandledEvent handledEvent);
  • lalou.jonathan.application.web.gwt.animal.handler.EventHandlerBus: the actual bus. As a concrete class, it has two methods:
    /**
    	 * 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) {
                  // ...
            }

How to use the bus?

  1. 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”
  2. Add an entry in the enum EventTypeEnum. Eg: “ANIMAL_SELECTION_CHANGED
  3. in lalou.jonathan.application.web.gwt.animal.events, create an event, implementing HandledEvent and its method getEventEnum(). The match between EventTypeEnum and DTO is achieved here. Eg:
    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;
    	}
    
    }
  • When an event that should interest other component is fired, simply call the bus. The bus will identify the event type and dispatch it to the relevant handlers. eg:
    animalComboBox.addSelectionChangedListener(new SelectionChangedListener<AnimalDTO>() {
    
    			@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);
    
    			}
    		});
  • Handlers:
    • easy case: the component handles only one type of event: this handler must implement the right interface (eg: AnimalSelectionChangedEventHandler) and its method, eg:
      protected void handleAnimalSelectionChangedEvent(HandledEvent handledEvent) {
          return;
      }
    • 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:
      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
              }