In this post I'm going to show how the "viewable" attribute of the binding container can change the ADF controller exception handling behavior.
Let's consider a very simple task flow:
Here we go from the view1 to the view2, calling the badMethod on the way. The badMethod method call, as the name suggests, causes an exception. Always. It invokes a managed bean method:
Since the badServiceMethod is invoked via ADF model using methodAction binding definition, the methodCall method is not going to be interrupted. The exception is going to be caught and processed by the binding layer and registered with the binding container of the task flow activity. The badMethod method call has its own binding container, containing the methodAction binding. After invoking the method call, the controller checks whether the activity's binding container has any exceptions, and if it has then the further control will be passed to the exception handler. This is the exception handler's job to take care about errors. For example, like this:
The binding container has the "viewable" attribute, which is true by default. It can be changed in the page definition file:
When the ADF binding layer processes an exception it starts with the root binding container and goes down registering the exception for each nested binding container if it is a viewable one. So switching off the viewable property will prevent the framework from registering an exception for this binding container. That means, that our "Help!" JboException will not be registered for the badMethod's binding container, and the control will not be passed to the ExceptionHandler after invoking the method. The controller will go further to the view2. However, the exception is going to be registered for the parent binding container, containing the task flow. So, the user will see the error message anyway, but at the view2 view activity. Note, that the ExceptionHandler is not going to be invoked in this case at all.
This behavior is demonstrated across all ADF 11g versions (both R1 and R2) except 11gR1 PS6. In the 11.1.1.7.0 the exception handler is going to be invoked anyway, without bothering whether the binding container causing the exception is viewable or not. In this case the control flow will not go forward, it's going to stop, and the user will see the error message at the view1 view activity.
That's it!
Let's consider a very simple task flow:
Here we go from the view1 to the view2, calling the badMethod on the way. The badMethod method call, as the name suggests, causes an exception. Always. It invokes a managed bean method:
public String methodCall() { BindingContainer bindings = getBindings(); OperationBinding operationBinding = bindings.getOperationBinding("badServiceMethod"); operationBinding.execute(); return "go"; }The methodCall uses the binding layer in order to invoke the badServiceMethod business service method:
public void badServiceMethod() { throw new JboException("Help!"); }
Since the badServiceMethod is invoked via ADF model using methodAction binding definition, the methodCall method is not going to be interrupted. The exception is going to be caught and processed by the binding layer and registered with the binding container of the task flow activity. The badMethod method call has its own binding container, containing the methodAction binding. After invoking the method call, the controller checks whether the activity's binding container has any exceptions, and if it has then the further control will be passed to the exception handler. This is the exception handler's job to take care about errors. For example, like this:
public void exceptionHandler() { ControllerContext context = ControllerContext.getInstance(); ViewPortContext currentRootViewPort = context.getCurrentViewPort(); if (currentRootViewPort.isExceptionPresent()) { Exception ex = currentRootViewPort.getExceptionData(); if (ex != null) { FacesContext fc = FacesContext.getCurrentInstance(); FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), null); fc.addMessage(null, facesMessage); } } }So, this is the default framework behavior. According to that we'll never reach view2. After the exception has been thrown, we go back to the view1 showing the exception message to the user. This message will be kindly added to the FacesContext by the ExceptionHandler.
The binding container has the "viewable" attribute, which is true by default. It can be changed in the page definition file:
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel" version="11.1.2.62.76" id="task_flow_definition_task_flow_definition_badMethodPageDef" Package="com.cs.blog.checkactionexception.view.pageDefs" SkipValidation="true" viewable="false" >Note, that "viewable" starts with a lower case letter.
When the ADF binding layer processes an exception it starts with the root binding container and goes down registering the exception for each nested binding container if it is a viewable one. So switching off the viewable property will prevent the framework from registering an exception for this binding container. That means, that our "Help!" JboException will not be registered for the badMethod's binding container, and the control will not be passed to the ExceptionHandler after invoking the method. The controller will go further to the view2. However, the exception is going to be registered for the parent binding container, containing the task flow. So, the user will see the error message anyway, but at the view2 view activity. Note, that the ExceptionHandler is not going to be invoked in this case at all.
This behavior is demonstrated across all ADF 11g versions (both R1 and R2) except 11gR1 PS6. In the 11.1.1.7.0 the exception handler is going to be invoked anyway, without bothering whether the binding container causing the exception is viewable or not. In this case the control flow will not go forward, it's going to stop, and the user will see the error message at the view1 view activity.
That's it!
No comments:
Post a Comment
Post Comment