Thursday, January 16, 2014

ADF Exception Handling - Taskflow, Controller, Model

Exception handling in ADF can be done at following three places:
a. Taskflow Exception Handler
b. Extending Controller level ExceptionHandler - for controller level exceptions
c. Extending DCErrorHandlerImpl- for model

  • Whenever there is an exception in model layer it is being handled by custom class extending DCErrorHandlerImpl.
  • Exception in ADF Controller can be handled by creating a custom class extending Controller level ExceptionHandler.
  • If an exception rethrown from above, it can be handled at TaskFlow level exception handler which can be a view activity, router or a method call.
One by one let`s discuss all of them:


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

a. Taskflow Exception Handler

Here We will discuss on session timeout and exception handling for at taskflow level by creating an Exception Handler

STEP 1: Task Flow changes

Create a router in your taskflow:

Add a condition which points to a method in backing bean. 
The method returns true if session expires and user is redirected to home/login page as needed.
And if method returns false, the user is redirected to default outcome - errorPage.

Mark the router as exception handler like this:


STEP 2: BEAN changes

Add the following method in your bean:

  public boolean isSessionExpired()
  {
    Exception e =
      ControllerContext.getInstance().getCurrentViewPort().getExceptionData();
    if (e != null && (e instanceof ViewExpiredException))
    {
// session  timeout case
      return true;
    }
// IF SOA is down or some other fault in SOA process
    else if (e != null &&
             (e instanceof ConnectException || e instanceof javax.xml.ws.WebServiceException ||
              e instanceof javax.xml.ws.soap.SOAPFaultException || e.toString().contains("Failed to access the WSDL")))
      putParameterinPageFlowScope("errorMessage",
                                  "Currently the system is in maintenance mode. Please try after sometime.");
    else
      putParameterinPageFlowScope("errorMessage",
                                  "Some unexpected error has occurred. Please try after sometime.");
    if (e != null)
    {
      StringWriter errors = new StringWriter();
      e.printStackTrace(new PrintWriter(errors));
      if(errors != null)
         putParameterinPageFlowScope("detailedException",errors.toString());
    }
    return false;
  }

In case where there is an exception other than ViewExpiredException(session timeout), write two parameters in request or pageFlowScope as written above:
  •   putParameterinPageFlowScope("errorMessage", "Currently the system is in maintenance mode. Please try after sometime.");
  •  putParameterinPageFlowScope("detailedException",errors.toString());

STEP 3 : Error Page

  <af:outputFormatted value="#{pageFlowScope.errorMessage}"/>
  <af:outputFormatted value="#{pageFlowScope.detailedException}" visible="false"/>

 visible="false" makes sure the detailed exception is there in source of the page and user doesn`t see it.
You can see the same in page source.

You can add more conditions and messages in your bean method based on your scenarios like Content Server related exceptions, etc.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

b. Extending Controller level ExceptionHandler

Any exception in controller will first come here and if re-thrown will be handled at taskflow level(explained before).

STEP 1: Declaring custom exception handler class

You need to create a folder named services under Application Resources -> Descriptors -> ADF META-INF. Under the folder create a file named oracle.adf.view.rich.context.ExceptionHandler and inside the file just mention the name of your custom exception handler.


STEP 2: Custom Exception Class

We are creating a custom exception class which will be thrown in our code whenever we want to show a faces message for any validation, failure, etc.


public class XxCustomException
  extends JboException
{
  private String resourceBundleKey;
  private String error_type;
  private String client_id;
  private MessageToken[] tokens;
  
//setters and getters with required constructors
}

STEP 3: Custom ExceptionHandler Class


import oracle.adf.view.rich.context.ExceptionHandler;
public class XxControllerExpHandler
  extends ExceptionHandler
{
  public void handleException(FacesContext facesContext,
                              Throwable throwable, PhaseId phaseId)
    throws Throwable
  {

boolean isCustomExp  = false;
    for (int i = 0; i < 10; i++)
    {
      if (throwable instanceof XxCustomException)
      {
        isCustomExp = true;
        break;
      }
      if (throwable != null)
      {
        throwable = throwable.getCause();
      }
   }

    if (isCustomExp)
    {
      if (throwable!= null)
      {
// The below method will show a Faces Message. If client id of xxCustomException is not null then it will show a faces message on that component. It will try to get the message from resource bundle based on resourceBundleKey attribute. Error_type will decide if it is info, warning, severe
        XxUtils.showMessage((XxCustomException)throwable);
      }
    }
    else
    {
//this will be handled at taskflow level
      throw z;
     }
 }
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

c. Extending DCErrorHandlerImpl- for model

STEP 1: Custom ExceptionHandler Class for model


package xx.view.exp.model;

import javax.faces.application.FacesMessage;
import oracle.adf.model.binding.DCErrorHandlerImpl;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.jbo.JboException;

public class XxModelExpHandler
  extends DCErrorHandlerImpl
{
  public XxModelExpHandler()
  {
    super(true);
  }

  public XxModelExpHandler(boolean b)
  {
    super(b);
  }

  @Override
  public String getDisplayMessage(BindingContext ctx, Exception th)
  {
    return super.getDisplayMessage(ctx, th);
  }

  @Override
  public void reportException(DCBindingContainer formBnd, Exception ex)
  {
    if (ex instanceof XxCustomException)
    {
//get message to be displayed from resource bundle or hardcode the message when throwing exception
        String msg = XxUtils.getMessageString((XxCustomException) ex);
        JboException jex=new JboException(msg);
        super.reportException(formBnd,jex);
    }

    else
    {
      super.reportException(formBnd, ex);
    }
  }

}

STEP 2: Databindings.cpx


Specify your custom handler as ErrorHandlerClass in databindings.cpx:


<Application xmlns="http://xmlns.oracle.com/adfm/application"
             version="11.1.1.59.23" id="DataBindings" SeparateXMLFiles="false"
             Package="xx.view" ClientType="Generic"
             ErrorHandlerClass="xx.view.exp.model.XxModelExpHandler">



------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

With all the above setups you can throw an exception from your model as well as controller whenever there is any validation failure, etc and it should handle all unexpected exceptions also.

Please let me know if there is any issue in this.

I hope this is helpful.


Regards,
Deepak

15 comments:

  1. Hi Deepak,

    I created a custom exception handler class , created text file in services folder and in the file I mentioned the exception handler class name like view.CustomExceptionHandler as my custom class is in view package of view controller. The exception handler class is not invoked. Please help me to fix this.

    Thanks,
    Ravi

    ReplyDelete
  2. Are you extending ExceptionHandler class and overrriding handleException method?
    Also make sure the name of the file under services is correct.

    ReplyDelete
  3. Yes Deepak I extended ExceptionHandler class. In the text file under service folder, I mentioned the view.CustomExceptionHandler in the file. My CustomExceptionHandler is in view package of ViewController project. Please help to fix this.

    Thanks,
    Ravi

    ReplyDelete
  4. Hi Ravi,

    It should work. Please confirm the following:
    a. The name of the folder is services and not service
    b. oracle.adf.view.rich.context.ExceptionHandler file doesn`t have any extension
    c. The path of the services folder is like this: .adf\META-INF\services

    Regards,
    Deepak

    ReplyDelete
  5. Hi Deepak,

    It worked. I had txt extension for the file under services folder. I created a file under services folder with no extension. It worked. Thanks for your kind and quick response. Your blog is very helpful.

    Thanks,
    Ravi

    ReplyDelete
  6. Hi Deepak,

    I have a question regarding the Custom ExceptionHandler Class. Why do you have this lie Throwable throwable = z;? What is z and why are you assigning it to throwable? My IDE won't even let me do this because an input parameter of a method is named the same. I suppose it's some kind of mistake..

    Thanks,

    Maja

    ReplyDelete
  7. Yeah that line should not be there as I was doing some more stuff in my class and had a private variable z, which I forgot to remove. Thanks.

    ReplyDelete
  8. Are you still working in fujitsu

    ReplyDelete
    Replies
    1. No I left Fujitsu last month. Who is that anyways?

      Delete
    2. Dear Deepak can you please let me know how can we redirect to error page from custom exception handler handleexception().

      Delete
  9. Hi Deepak,

    Can you please share the source code for this.

    ReplyDelete
  10. Given so much information in it. its very useful .perfect explanation about Dot net framework.Thanks for your valuable information. dot net training in chennai velachery | dot net training institute in velachery

    ReplyDelete
  11. It is really a great work and the way in which u r sharing the knowledge is excellent.Thanks for helping me to understand basic concepts. As a beginner in Dot Net programming your post help me a lot.Thanks for your informative article.. dot net training and placement in chennai | best dot net training in chennai

    ReplyDelete