Event Driven Programming with JSF

1) Introduction

This article discusses theories and concepts related to JSF Event Model. It details the supporting high level classes and interfaces that are involved in JSF Event Handling Mechanism. The logical categorization of JSF Events is also explained along with code snippets. Then, the tags available in the core JSF Framework are also discussed. This article doesn’t provide an introduction so first-time readers of JSF are advised to read Introduction to Java Server Faces in JavaBeat before beginning this article.

2) JSF Event Model

2.1) Introduction

The model that JSF implements for handling Events is based on the standards defined in Java Beans Specification. The basic model goes like this. JSF User Interface Components are sources that can emit some kind of signals based on user actions. These signals are often termed as Events. Applications who want to process the Events can attach any number of Event Listeners to Event Sources. This simple model is also followed in Swing Components. However, the difference here is, the Event Sources (i.e, the UI Components) reside in the Client whereas the Listeners (Application Logic that does something in response to Events) will reside on the Server.

also read:

2.2) Event Classes

The classes/interfaces related to JSF Events are contained in the package 'javax.faces.event'. All Events (standard Events or User-defined Events) in JSF should extend the javax.faces.event.FacesEvent. The constructor for this class has an argument of type UIComponent which specifies for which UI Component the Event is for.

UIComponent someComponent = new UIComponent();
MyFacesEvent event = new MyFacesEvent(someComponent);

UIComponent sourceCompoenent = event.getComponent();

If the above code, the source component that generated a particular Event can be obtained by calling the method event.getComponent(). This class has a method called queue() which is used to queue the Event at the end of the current request processing life-cycle. If we want the Event to be queued and occur at a particular request processing phase, then this can be achieved by the following lines of code,

MyFacesEvent event = new MyFacesEvent();
event.setPhaseId(PhaseId.PROCESS_VALIDATIONS);

In the above code, the event MyFacesEvent will occur at the end of the 'Process Validations' life-cycle phase.
JSF defines two concrete set of Events namely ActionEvent and ValueChangeEvent and they both extend the base Event class FacesEvent. They are discussed in greater depth in the subsequent sections.

2.3) Listener Classes

There is a corresponding Listener Class for each type of Event in JSF. For example, consider the case of ActionEvent, in which there exists an equivalent Listener class called ActionListener. Same is the case of ValueChangeEvent, in which case the corresponding Listener class is ValueChangeListener.
The JavaBeans Specification mandates the support for the following methods for registering a Listener to a particular Event. For example, if the Event name is MyCustomEvent and the corresponding Listener class is MyCustomListener and we want this Event to happen for a component called MyCustomComponent, then the following methods shall be defined in the MyCustomComponent class for registering the Listeners.

public void addMyCustomListener(MyCustomListener listener)

public void removeMyCustomListener(MyCustomListener listener)

public MyCustomListener[] getMyCustomListeners()

3) Types of JSF Events

3.1) Introduction

The logical categorization of JSF Events fall under three categories and they are listed as follows,

  • Action Events
  • Value Change Events
  • Phase Events

We will discuss about these Events in the following sections along with code snippets.

3.2) Action Events

Action Events are emitted for UI Command objects like Command Button or a Hyper-link. Whenever a user presses a Command Button or clicks a hyper-link these Events get generated. It is possible to attach any number of Listeners to these Sources. For example, consider the following code snippet,

<h:commandButton value = "Test Action Listener"
actionListener = "#{testActionListener.doSomeAction}" />

We have defined an attribute called 'actionListener' pointing to a method expression. This method expression will resolve to a method called doSomeAction() which is defined in the Managed Bean with identifier 'testActionListener'. The signature of the method for the 'actionListener' attribute must be,

public void anyMethod(ActionEvent actionEvent)

Given below is the definition of the Managed Bean in the Faces Configuration file,

<managed-bean>
    <managed-bean-name>testActionListener</managed-bean-name>
        <managed-bean-class>
            net.javabeat.articles.jsf.events.actions
                   .TestActionListener
        </managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

It is also possible to programmatically register any number of Listeners for a particular UI Component. Say for example, the following code snippet attached two listeners to the component identified by myComponent,


UIComponent myComponent = new UIComponent();
myComponent.addActionListener(new TestActionListener());
myComponent.addActionListener(new CustomActionListener());

Given below is the definition for the class TestActionListener,
TestActionListener.java

package net.javabeat.articles.jsf.events.actions;

import javax.faces.component.UIComponent;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

public class TestActionListener implements ActionListener
{
    public TestActionListener()
    {
    }

    public void processAction(ActionEvent event)
               throws AbortProcessingException
    {
        System.out.println("Test Action Listener called..");
        UIComponent source = event.getComponent();
        System.out.println("Source of the Event is "
               + source.getClass().getName());
    }
}

Whenever the Button is clicked, the method processAction(ActionEvent event) will be called and the business logic will be executed. Same is the case with the following CustomActionListener class,
CustomActionListener.java

package net.javabeat.articles.jsf.events.actions;

import javax.faces.component.UIComponent;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

public class CustomActionListener implements ActionListener
{
    public CustomActionListener()
    {
    }

    public void processAction(ActionEvent event)
            throws AbortProcessingException
    {
        System.out.println("Custom Action Listener called..");
        UIComponent source = event.getComponent();
        System.out.println("Source of the Event is " +
            source.getClass().getName());
    }
}

The order of execution of Action Events follows this way. If the attribute 'actionListener' is defined for the Component, then it is executed first, followed by the Event Listeners that are registered programmatically by calling the method addActionListener(ActionListener actionListener).

3.3) Value Change Events

Value Change Events are applicable for UI Components like Text Field, Check-Box, List and Radio Buttons. The Value Change Event is fired as soon as the value that is displayed in the view is modified. Listeners that are attached to this Value Change Event usually perform some sort of validation to check whether the new input is acceptable.
For example, consider the following code snippet,

<h:selectOneMenu value="#{addressBean.country}"
    valueChangeListener="#{addressBean.populatePinNumber}">
</h:selectOneMenu>

Note the use of the attribute 'valueChangeListener'. In the above code, whenever the value of the country name is changed, then the PIN value for the country name is auto-populated in the relevant text-field.
CountryValueChangeListener.java

package net.javabeat.articles.jsf.events.actions;

import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;

public class CountryValueChangeListener
{

    public CountryValueChangeListener()
    {
    }

    public void populatePinNumber(ValueChangeEvent event)
    {
        Object oldValue = event.getOldValue();
        Object newValue = event.getNewValue();

        if (oldValue != newValue)
        {
            // Get the country name and populate the pin value.
            String countryName = (String)newValue;
        }
    }
}

In the above code, an attempt is made to fetch the PIN number for the corresponding country name. If we wish to add Value Change Listeners to a particular UI Component, then make use of the method addValueChangeListener(ValueChangeListener valueChangeListener). The Custom ValueChangeListener class must define a processValueChange() with a single argument of type ValueChangeEvent.

3.4) Phase Events

As we are aware that the Request processing life-cycle in JSF includes six phases and any JSF implementation will fire Phase Events during the start and end of each phase. If we want to capture the Phase Events, then can define a Phase Listener class as follows,
CustomPhaseListener.java

package net.javabeat.articles.jsf.events.actions;

import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

public class CustomPhaseListener
            implements PhaseListener
{
    public CustomPhaseListener()
    {
    }

    public void afterPhase(PhaseEvent event)
    {
        System.out.println("After Phase->"
             + event.getPhaseId());
    }

    public void beforePhase(PhaseEvent event)
    {
        System.out.println("Before Phase->"
            + event.getPhaseId());
    }

    public PhaseId getPhaseId()
    {
        return PhaseId.ANY_PHASE;
    }
}

Note that the Application specific Phase Listener class implements the interface PhaseListener. The methods afterPhase() will be called once a Phase gets ended. And the method beforePhase() will be called even before a phase begins. To register this Phase Listener to our Application, we have to define an entry in the Faces Configuration file like this,

<lifecycle>
    <phase-listener>
        net.javabeat.articles.jsf.events
           .actions.TestActionListener
    </phase-listener>
</lifecycle>

It is possible to define any number of Phase Listeners for an Application as follows,

<lifecycle>
    <phase-listener>PhaseListener1</phase-listener>
    <phase-listener>PhaseListener2</phase-listener>
</lifecycle>

The following code will now list down all the phase listeners that are defined in the Faces Configuration file,

public void listAllPhaseListeners()
{
    LifecycleFactory lifecycleFactory =
        (LifecycleFactory)FactoryFinder.getFactory(
        FactoryFinder.LIFECYCLE_FACTORY);
    Lifecycle applicationLifecycle =
        lifecycleFactory.getLifecycle(LifecycleFactory
               .DEFAULT_LIFECYCLE);

    PhaseListener phaseListeners[] = applicationLifecycle
              .getPhaseListeners();
    for (PhaseListener phaseListener : phaseListeners)
    {
        System.out.println(phaseListener.getPhaseId());
    }
}

4) Conclusion

This article discussed about the Event Driven Modeling in JSF Framework. More specifically, it dealt with the JSF Events and the JSF Listener Classes for supporting Event Handling. Then the final sections concentrated on the various types of JSF Events like Action Events, Value Change Events and Phase Events and how they can be configured and registered to the source components.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Comments

  1. Ahmed Adel says:

    Amazing
    Thank you very much

  2. Hi ,
    I am trying to add a valuechange Listener to dynamically created selectonemenu.Below is the code:
    SelectOneMenu selectmsgtype = new SelectOneMenu();
    UISelectItems msgtypeitems = new UISelectItems();
    final String selecttypeBinding = “#{bean.selectmsgtypehash.key”
    + compCount + “}”;
    final ValueExpression selecttypeValueExp = FacesContext
    .getCurrentInstance()
    .getApplication()
    .getExpressionFactory()
    .createValueExpression(getELContext(), selecttypeBinding,
    Integer.class);
    selectmsgtype.setValueExpression(“value”, selecttypeValueExp);
    selectmsgtype.addValueChangeListener(valueChangeListener);
    selectmsgtype.setImmediate(true);
    selectmsgtype.getChildren().add(msgtypeitems);
    component.getChildren().add(selectmsgtype)

    I am trying to add a valuechange Listener to dynamically created selectonemenu.Below is the code:

    SelectOneMenu selectmsgtype = new SelectOneMenu();
    UISelectItems msgtypeitems = new UISelectItems();
    selectmsgtype.setId(“selecttype” + compCount + “s”);
    final String selecttypeBinding = “#{bean.selectmsgtypehash.key”
    + compCount + “}”;
    final ValueExpression selecttypeValueExp = FacesContext
    .getCurrentInstance()
    .getApplication()
    .getExpressionFactory()
    .createValueExpression(getELContext(), selecttypeBinding,
    Integer.class);
    selectmsgtype.setValueExpression(“value”, selecttypeValueExp);
    selectmsgtype.addValueChangeListener(valueChangeListener);
    selectmsgtype.setImmediate(true);
    selectmsgtype.getChildren().add(msgtypeitems);
    component.getChildren().add(selectmsgtype);*

    Here valueChangeListener is a managedproperty

    public class CustomValueChangeEvent implements ValueChangeListener {

    @Override
    public void processValueChange(ValueChangeEvent arg0)
    throws AbortProcessingException {
    System.out.println(“Valuechange Changed”);
    }
    }
    Can anyone let me know what is missing in the above so that the valuechange listener gets executed on change of value? I am using jsf 2.0 and primefaces 3.4.1

  3. Viddya Sagar says:

    Thank you very much Krishna Srinivasan.

Speak Your Mind

*