views:

2788

answers:

5

Is there any way to create a custom ActionListener class in JSF so that I can intercept an exception if it occurs on pressing the command button using my own ActionListener class

I tried using the following code:

firstpage.jsp
<f:view>
  <html>
    <head>
      <title>firstpage</title>
    </head>
    <body>
      <h:form>    
        <h:commandButton id="button" value="submit"
                         actionListener="#{databasebean.fetchUserName}"/>
      </h:form>
    </body>
  </html>
</f:view>
Dao.java
package getexception;

import java.sql.*;
import java.util.ArrayList;
import javax.faces.event.ActionEvent;

public class Dao {

    String firstname;
    private Connection con=null;
    private Statement stmt = null;
    private ResultSet rst = null;
    private ArrayList ar;
    String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
    String url = "jdbc:odbc:" + "new";
    public Dao() {

    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getFirstname() {
        return firstname;
    }
    public void fetchUserName(ActionEvent ae) throws Exception{
        Driver d= (Driver)Class.forName(driver).newInstance();
        con = DriverManager.getConnection(url,"","");
        stmt = con.createStatement();
        rst=stmt.executeQuery("select firstname from employee where firstname like '%e'");
        if(rst.next()) {
            this.setFirstname(rst.getString("firstname"));
        }
        rst.close();
        stmt.close();
        con.close();
    }}
NewActionListener.java
package getexception;

import com.sun.faces.application.ActionListenerImpl;
import javax.faces.application.Application;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

public class NewActionListener extends ActionListenerImpl{

    public void processAction(ActionEvent event) {
    try {
        System.out.println("try block");
        super.processAction(event);

    } catch (Exception exception) {
        System.out.println("catch block");
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Application application = facesContext.getApplication();
        NavigationHandler navigationHandler = application.getNavigationHandler();
        navigationHandler.handleNavigation(facesContext,null,"exceptionNavigation");
        facesContext.renderResponse();
        }
    }}
faces-config.xml
<faces-config xmlns="http://java.sun.com/JSF/Configuration"&gt;
  <managed-bean>
    <managed-bean-name>databasebean</managed-bean-name>
    <managed-bean-class>getexception.Dao</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
  </managed-bean>

  <navigation-rule>
    <navigation-case>
      <from-outcome>exceptionNavigation</from-outcome>
      <to-view-id>/error.jsp/<to-view-id>
    </navigation-case>
  </navigation-rule>

  <application>
    <action-listener>getexception.NewActionListener</action-listener>
  </application>

  <managed-bean>
    <managed-bean-name>backing_hellopage</managed-bean-name>
    <managed-bean-class>getexception.backing.Hellopage</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>
</faces-config>
error.jsp
  <html>
    <f:view>
      <head>
        <title>firstpage</title>
      </head>
      <body>
        <h:form>
          <h:outputText value="Exception succesfully navigated"/>
        </h:form>
      </body>
    </f:view>
  </html>

The code generated an SQL exception but it was not showing me the error.jsp page.

What have I misconfigured so that the error page is not showing when an exception fired?

A: 

Here you can find, how to implement an Action Listener

and here, how to register a listener on components (even an example for the commandButton).

Peter
A: 

tried but it doesnt work

+1  A: 

javadoc for Application.setActionListener:

Set the default ActionListener to be registered for all ActionSource components.

The ActionListener set on an Application is not responsible for invoking other listeners. It does not call anything set via the actionListener attribute nor the f:actionListener tag. It is responsible for processing the action attribute, which is bound to methods that return a navigation-case string (see get/setAction on ActionSource).

So, the listener on the application can't catch events from other listeners because it doesn't call them.

Summary:

<h:commandButton action="#{bean.foo1}" actionListener="#{bean.foo2}">
    <f:actionListener type="type.Foo3" />
</h:commandButton>
  1. foo1: (method public String foo1()) uses faces-config ActionListener
  2. foo2: (method public void foo2(ActionEvent)) uses MethodExpressionActionListener
  3. Foo3: (class public class Foo3 implements ActionListener) is registered directly on the component


As an aside, it is probably better to use this pattern to create the ActionListener registered in faces-config.xml:

public class MyActionListener implements ActionListener {

    private final ActionListener delegate;

    public MyActionListener(ActionListener delegate) {
     this.delegate = delegate;
    }

    public void processAction(ActionEvent event)
      throws AbortProcessingException {
     delegate.processAction(event);
    }

}

When the JSF framework configures itself, it will pass the underlying ActionListener implementation to the constructor. This applies to many JSF artefacts (factories, etcetera).

McDowell
+1  A: 

You have a unnecessary slash (/) in the line:

<to-view-id>/error.jsp/<to-view-id>

Should be

<to-view-id>/error.jsp<to-view-id>
Daniel
A: 

I believe you need:

/*

after navigation rule and before navigation case.

Don

don
Incorrect. This is already the *default*.
BalusC