Event Listener Adapter
As described in Chapter 2, the UIInput component delivers a ValueChangeEvent to all registered event listeners. In addition, the ValueChangeEvent is also delivered to the backing bean via a MethodBinding stored in the UIInput's valueChangeListener attribute. The valueChangeListener attribute is exposed as a tag attribute on the standard input tags, such as <h:inputText valueChangeListener="#{backingBean.doValueChange}" >.In JSF 1.2, the valueChangeListener attribute is deprecated on the UIInput component but is still present on the JSP tag as a JSP 2.1 MethodExpression, so an adapter class is needed to adapt the MethodExpression into a ValueChangeListener instance. This allows the backing bean to still be called when a ValueChangeEvent occurs but without needing a separate valueChangeListener attribute on the UIInput component. This simplifies and clarifies component development by more closely following the JavaBeans specification while preserving MethodBinding support for application development.
We will show how to follow this design pattern to adapt a JSF 1.1 MethodBinding into a ShowListener instance. Code Sample 3-7 shows the implementation of this design pattern, ShowAdapter.
Code Sample 3-7. The ShowAdapter Class package com.apress.projsf.ch3.event;
import javax.faces.component.StateHolder; import javax.faces.component.UIComponentBase; import javax.faces.context.FacesContext; import javax.faces.el.MethodBinding;
* The ShowAdapter calls a MethodBinding with the same signature
* as the <code>processShow</code> method.
public class ShowAdapter implements ShowListener,
StateHolder
* The MethodBinding signature for ShowListener methods.
public static Class[] SIGNATURE = new Class[] { ShowEvent.class };
* Creates a new ShowAdapter.
* @param showMethod the MethodBinding to adapt
public ShowAdapter( MethodBinding showMethod)
_showMethod = showMethod;
* Processes a ShowEvent.
* @param event the show event
public void processShow( ShowEvent event)
FacesContext context = FacesContext.getCurrentInstance(); _showMethod.invoke(context, new Object[]{event});
* Saves the internal state of this ShowAdapter.
* @param context the Faces context
* @return the saved state public Object saveState( FacesContext context)
return UIComponentBase.saveAttachedState(context, _showMethod);
* Restores the internal state of this ShowAdapter.
* @param context the Faces context
* @param object the state to restore
public void restoreState( FacesContext context, Object object)
_showMethod = (MethodBinding)
UIComponentBase.restoreAttachedState(context, object);
* Returns true if this ShowAdapter is transient and should
* not be state saved, otherwise false.
* @return the value of transient
public boolean isTransient() {
return _transient;
* Indicates whether this ShowAdapter is transient and should
* not be state saved.
* @param isTransient the new value for transient
public void setTransient( boolean isTransient)
_transient = isTransient;
private MethodBinding _showMethod; private boolean _transient;
The ShowAdapter implements the processShow method, calling the specified MethodBinding with the ShowEvent parameter. It is important that the MethodBinding passed to the ShowAdapter constructor matches the signature of the processShow method. Therefore, the ProShowOneDeckTag uses the SIGNATURE constant to create the MethodBinding with the correct signature.
It is important to implement the StateHolder interface on this adapter class so that the state can be properly saved and restored when an instance is registered as a listener on a component in the component hierarchy.
You must provide an implementation of the saveState() method to store to the MethodBinding state as the UIShowAdapter state, so you need to use a static method from UIComponentBase called saveAttachedState(). This convenience method does the work of state saving attached objects that may or may not implement the StateHolder interface.
You must also provide an implementation of the restoreState() method that takes the FacesContext and the state object as arguments. Note that using the saveAttachedState() method to save the MethodBinding state implies that you use the restoreAttachedState() method to restore the MethodBinding state.
Post a comment