Listener Methods

Listener methods are the main approach by which you add application-specific behavior to your application.

Listener methods are a kind of call back; they are triggered when a form is submitted or a link is clicked. The listener methods exist within your page and component classes. Components such as DirectLink and Form take a listener parameter, and you can use a listener: binding reference to use a listener method in your class as the listener. As of Tapestry 4.1.3, components that require a listener (XTile, DirectLink, InvokeListener, Suggest) no longer need an explicit listener provided for their "listener" parameter as long as a listener method exists on the component whose name is composed of the capitalized component id, prefixed by "do". For example, jwcid="clear@DirectLink" would expect a listener method called doClear() if the listener parameter is not used.

Note:

The parameter type for listeners is IActionListener . Internally, Tapestry creates an object that implements that interface and uses reflection to invoke the corrsponding method on your page or component instance. On rare occasions, it is useful to create objects that implement the interface directly. For pages, components and the engine, there is a listeners property whose keys are the names of listener methods, but the listener: binding reference is easier to use.

A listener method is always a public instance method. It may take parameters, or not, and may return void or certain other types.

Return Type

A listener method may return void, may return a string, or may return an object that implements IPage . The last two options are used to change the active page , the page which will render the response. Returning null will not change the active page (it defaults to the page containing the link or form components which invoked the listener method).

void
The listener method does not change the active page.
java.lang.String
The listener method may return the name of a page to activate (and render the response). Returning null does not change the active page.
IPage
A non-null IPage will activate that page instance. The page object may be obtained from the request cycle, or via page injection .
ILink
Returning a non-null ILink will send a redirect to the client for the URL associated with the link. This is commonly used to perform a redirect-after-post .

Listener Method Parameters

When using the DirectLink component, you may specify additional listener parameters . The listener parameters are encoded into the URL and will be available in a later request, when the listener is triggered.

Note:

In Tapestry 3.0 and earlier, listener parameters were known as service parameters . In addition, listener methods had to be in a very fixed form, taking exactly one parameter of type IRequestCycle and returning void.

The listener can gain access these parameters in one of two ways:

  • By invoking the getListenerParameters() method of IRequestCycle
  • By declaring a method parameter for each listener parameter (in order)
Using the second method is usually the best way. The link parameter values are not simply converted into strings, they are encoded as strings but maintain their type; therefore, the listener method parameters must be of the correct type. For example, suppose that the link encoded a String objectId and an integer index. The component in the template names the listener method, and the two parameters are passed into the DirectLink as an OGNL list expression:
<a jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:{ objectId, index }"> . . . </a>

In the Java class, the listener method might look like:

public void doClick(String objectId, int index)
{
  . . .
}

Alternately, the listener method could look like:

public void doClick(IRequestCycle cycle)
{
  Object[] parameters = cycle.getListenerParameters();
  String objectId = (String)parameters[0];
  int index = ((Integer)parameters[1]).intValue();
  
  . . .
}

This second case is maintained in Tapestry 4.0 mostly for backwards compatibility, or to handle the case where a single listener method must handle an indeterminate number of listener parameters.

In fact, Tapestry does a search for the most appropriate method, given the number of listener parameters:

  • public type method ( parameters )
  • public type method (IRequestCycle cycle, parameters )
  • public type method ()
  • public type method (IRequestCycle cycle)
Tapestry 3.0 and earlier only accepted the final variation (and it had to return void). Don't get too tricky with multiple overloadings of the method; Tapestry doesn't attempt to match the listener parameter types to the method parameter types (it works just by comparing the number of parameters). However, you can count on Java boxing and autoboxing the parameter values (so you can use int and java.lang.Integer interchangeably).

Invoking Listener Methods

When creating components that accept a listener as a parameter, you should not invoke the IActionListener directly, instead, you should inject the infrastructure:ListenerInvoker service into your component, and have it invoke the listener. The ListenerInvoker is extensible, and application logic may depend on ListenerInvoker's behavior (commonly, it is used to mark transactions boundaries). In your component specification:
  <parameter name="listener" required="yes"/>

  <inject property="listenerInvoker" object="infrastructure:listenerInvoker"/>
In your source code:
  public abstract IActionListener getListener();
  
  public abstract ListenerInvoker getListenerInvoker();
  
  . . .
  
  IActionListener listener = getListener();
  ListenerInvoker invoker = getListenerInvoker();
  
  invoker.invokeListener(listener, this, cycle);

It is acceptible to pass null as the listener; this saves you the necessity of checking for null when the listener is an optional parameter.