Customizing Oracle ADF  Error Messages in Jdeveloper

 

Environment

 

Jdeveloper  10.1.3.2

ADF BC   JSF

 

It is often required to control ADF/JSF error messages in order to display them in an more error friendly format.  For example, if you rely on Data Base triggers to implement business rules, or you want constraint violation to be more readable  you might as well need to show the business rules violation is different formats.

 

Background

 

We need first to understand how the error message are handled by the ADF by default before we attempt to override the default behavior

 

1-     Any exception thrown by ADF application is caught by the Binding Container, in particular by a class called DCErrorHandlerImp.

2-     A method called ReportException  then can passes the exception back to the Binding Container

3-     During Prepare Render Case, the ADFLifecycle executes reportError(context)

 

How to Customize the default Error Messages

1-     you need to write a new errorhandler class that extends the default   DCErrorHandlerImp class

2-     you need to override the ReportException method and write the necessary code to handle and display the error messages the way you want

3-     You want to find a way to tell the lifecycle to execute the new errorhandler instead the default one.

 

 

Example:

  

Implementing steps (1) and (2)

 

Create  a  class called AmmarErrorHandler that extends the DCErrorHandlerImpl Class

Override the reportException Method to customize the way you want to display the errors

 

package view.backing;

import com.evermind.server.Application;

import javax.faces.application.FacesMessage;

import javax.faces.context.FacesContext;

import javax.faces.el.ValueBinding;

import oracle.adf.model.binding.DCBindingContainer;

import oracle.adf.model.binding.DCErrorHandlerImpl;

import oracle.jbo.DMLConstraintException;

import oracle.jbo.JboException;

import oracle.jbo.Row;

import realsoft.com.helper.JSFHelper;

 

public class AmmarErrorHandler extends DCErrorHandlerImpl{

  /**

   * Constructor for custom error handler.

   * @param setToThrow should exceptions throw or not

   */

   public AmmarErrorHandler(boolean setToThrow) {

       super(setToThrow);

   }

  /**

   * Overridden ADF binding framework method to customize the way

   * that Exceptions are reported to the client.

   * @param bc BindingContainer

   * @param ex exception being reported

   */

  public void reportException(DCBindingContainer bc, Exception ex) {

    

    FacesContext.getCurrentInstance().addMessage("myMessage",new FacesMessage(FacesMessage.SEVERITY_ERROR,"Test Message is my message",null));

    this.displayProperly( ex,  bc);

 

// super.reportException(bc, ex);

  }

 

  private void displayProperly(Exception ex, DCBindingContainer bc )

  {

    if( ex instanceof oracle.jbo.JboException )

                                  System.out.println( ex.getClass().getName() + " :: at tryToCommit(){ commit() ; } , Details : " + ((oracle.jbo.JboException)ex).getDetailMessage() ) ;

 

                            DMLConstraintException dmlEx  ;

                            Row proRow ;

                            String[] attsNames ;

                            Object[] attsValues ;

 

                            if( ex instanceof DMLConstraintException )

                            {

                                    dmlEx = ((DMLConstraintException)ex) ;

                                    proRow = dmlEx.getEntityRow() ;

                                    attsNames = proRow.getAttributeNames() ;

                                    attsValues = proRow.getAttributeValues() ;

                                      JSFHelper.addFacesErrorMessage(dmlEx.getErrorCode());

                                      JSFHelper.addFacesErrorMessage(dmlEx.getConstraintName());

                                         for( int i = 0 ; i < proRow.getAttributeCount() ; i ++ )

                                              log.error( attsNames[i] + " = " + attsValues[i] ) ;           

                            }

 

          // if you want to print the entire error stack    JSFHelper.addFacesErrorMessage(ex.getMessage());                                                      

 

                     }

}

 

 

Now , we need to implement step (3).  In order to make the application use the AmmarErrorHandler class created above, we need to create a custom lifecycle class that override prepareModel.  In this class, we test if the we instruct the PageLifeCycle to execute the AmmarErrorHandler Instead of the default errorHanlderImpl class

 

package view.backing;

 

import oracle.adf.controller.faces.lifecycle.FacesPageLifecycle;

import oracle.adf.controller.v2.context.LifecycleContext;

 

public class customLifecycle extends FacesPageLifecycle

{

  public void prepareModel(LifecycleContext ctx) {

      if (!(ctx.getBindingContext().getErrorHandler() instanceof

            AmmarErrorHandler)) {

          ctx.getBindingContext().setErrorHandler(new AmmarErrorHandler(true));

      }

      //etc

      super.prepareModel(ctx);

  }

}

 

The custom lifecycle needs to be executed as part of the ADFLifecycle, so we still need to create yet another class that extends ADFPhaseListener and in its construct instantiates our previously created customLifecycle.

 

package view.backing;

 

import oracle.adf.controller.faces.lifecycle.ADFPhaseListener;

import oracle.adf.controller.v2.lifecycle.PageLifecycle;

 

public class MyAdfPhasesLitener extends ADFPhaseListener {

  protected PageLifecycle createPageLifecycle() {

    return new customLifecycle();

  }

}

 

 

To clarify, the following dependencies are shown

 

MyAdfPhasesListener à  Returns  customLifecycle() à makes AmmarErrorHandler  the default error handling routine

 

Finally, the Faces-config needs to be configured

 

 

Running a simple example with Unique key violation