Sunday, May 2, 2010

Handling Exceptions in Oracle UI Shell and ADF Dynamic Regions

Today is a next post in integration series, check my previous posts for the same topic. I will describe how you can handle exceptions with ADF Task Flow exception handler activity. Usually, we define separate Web page and render it, when exception occurs. However, its not user friendly - its better to inform user about exception and remain in the system. I will explain one undocumented technique for exception handling - combination between ADF Task Flow exception handler activity and dynamic regions. Described approach is applicable not only to Oracle UI Shell, but to the screens with dynamic regions as well.

Download sample application - ADFIntegrationUIShell2.zip. This sample is based on my previous post about Oracle UI Shell - Oracle UI Shell Update Available (1.02). I simulated Null Pointer Exception in one of the libraries and implemented exception handling approach.

In Departments library, I intentionally changed Commit operation reference in backing bean from Commit to CommitCorrupt:


Page Definition file defines Commit operation, this means on runtime OperationBinding object will be NULL and Null Pointer Exception will be thrown when trying to execute it:


At first, let's follow most common approach and declare separate JSF page for exception handler activity in ADF Task Flow - error page:


We open Departments application in UI Shell:


If Save button will be pressed, it will generate Null Pointer Exception, because OperationBinding will not be found (as described above). Since we have declared Exception Handler activity on error page, this page will rendered and user will be navigated away from the system:


It is not good, because it will look as whole system is down - nothing is shown, no menus and no navigation buttons. Most of the users will close and open their Web browser again.

In order to make it more user friendly, let's remove error page and mark the same main page as error activity by itself. This means, whenever exception will happen in the system, we will not navigate to any specific error page - but will stay on the same main page (where UI Shell is implemented):


You may ask, how we inform user about exception? Its quite simple - we define and render separate dynamic region with information about exception. I have defined new ADF Task Flow with one fragment - error.jsf:


This means in case of exception, we render only error fragment, and main page will remain the same - all menus and navigation buttons will remain present. How we can do this? Let me describe.

Oracle UI Shell contains facet for welcome region, instead having static region there, we can have dynamic. Let's add dynamic region ID calculation method into UI Shell launcher bean:


Now we need to change static welcome region ID:


To dynamic one from UI Shell launcher bean:


We have welcome region and can generate it dynamically. Now we need to define a reference to dynamic error region. In order to render error region only when its needed, we need to add some logic into dynamic region ID calculation method. First, we access ControllerContext object in order to check if there is any registered exception. And if there is exception, we clear this exception, close all currently open tabs and render error region. Because we declared ADF Task Flow exception handler on the same main page, after exception happens, framework again renders the same page and it triggers dynamic region ID calculation method - where we can render error region now, instead of default welcome region:


We need to clear exception, otherwise it will remain in ControllerContext object during next requests.

Now, we test the same Departments application and press Save button to generate Null Pointer Exception:


System is not navigating anymore to error page, but instead renders error region:


This is great, because user can use menu items and navigation buttons, to continue his work with the system:

18 comments:

HongMing said...

Hello Andrejus,

Thank you.
I learn a lot from you blog.

For this example, I would like to express my opinion.

1) Once hit error and error message shows on Welcome page, it covers the rest tags which has been launched.
2) If user wants to go back those launched tags, he must click navigation item again. If there are more tags opened before, he need to remember them and click one by one.
3) Is it possible to launch error message in the same tag window as a Popup window. So user close the Pop Window and still remain all the tags .

HongMing

HongMing said...

Hi Andrejus

I would like to know how to pass a parameter to region task flow through manage bean like launcher.java. It means I can launch a task flow via java program calling and pass the parameter at the same time.

Andrejus Baranovskis said...

Hi Hong,

Thats good idea, I will test to open error activity in Pop Window, and if it works - will update blog.

Regarding region task flow parameters, you want to do this in UI Shell? If in UI Shell, you can launch activity and pass parameters to dynamic region at the same time.

Regards,
Andrejus

HongMing said...

Hi Andrejus

I am looking forward to getting your latest blogs which can have the Popup error message window.

Regarding the parameter pass to Dynamic Region in UI Shell, I will use method to launch task flow

public void launchEmployeesApplication(ActionEvent actionEvent) {
_launchActivity(
"Employees Application",
"/WEB-INF/employees-flow.xml#employees-flow",
false);
}

If I have defined input parameter for this task flow, how am I passing the parameter in method?

By dropping a task flow with input parameter, I understand there is pop window allows me define parameter mapping.

Another question. In this example, I find Employee, Department, location are in separate application. I do not see where to include those applications in UIShellApp.

Appreciate if you can advise

Regards

HongMing

Andrejus Baranovskis said...

Hi,

Regarding parameters:

Latest UI Shell v 1.02 - http://andrejusb.blogspot.com/2010/04/oracle-ui-shell-update-available-102.html provides functionality to pass parameters directly through standard addTab method. See sample code:

private void startActivity(String title, String taskid, boolean isNew, Map parameters) {
try {
if (isNew) {
TabContext.getCurrentInstance().addTab(title, taskid, parameters);
} else {
TabContext.getCurrentInstance().addOrSelectTab(title, taskid, parameters);
}

} catch (TabContext.TabOverflowException e) {
e.handleDefault();
}
}

Regarding Task Flows:

In this sample, Task Flows are imported from ADF libraries.

Regards,
Andrejus

Andrejus Baranovskis said...

Hi,

Updated blog post, to render exception message in popup window: http://andrejusb.blogspot.com/2010/06/handling-exceptions-in-oracle-ui-shell.html

Regards,
Andrejus

Marvin said...

Hello Andrejus,

This is a very helpful blog.

Is there a way to push BC exceptions to be caught by taskflow exceptions as well?

So far, whenever i throw an exception from BC, it always gets shown with the popup.

Thanks,

Marvin

Andrejus Baranovskis said...

Hi Marvin,

No actually, with task flow exception handler you can handle only view/controller error. If you want to prevent ADF BC errors, you can define DCErrorHandler class on DataBindings, there you can listen for ADF BC exception.

Regards,
Andrejus

Anonymous said...

Hello Andrejus,
I tried to implement the same as above but I am not able to get the error page to display. Instead I keep getting the java popup error message.
I have emailed you a test application.
Can you please let me know what I am missing here?
Thanks
Harleen

Anonymous said...

Just wanted to say again Thank You soooo much for your help.
=)

Prasath said...

Hi Andrejus,
This is very useful. I am trying to simulate this for one of my webcenter portal use case.

I have a content presenter taskflow wrapped in a taskflow say MyContentPresenterTF with some lesser properties exposed to the user. If there is any error in the tasflow due to invalid content id or the UCM connection is null, i want to catch this exception and show an empty region instead...To simulate this, i have created an ExceptionTF with a exceptionView Page fragment and a dynamic region which shuttles between MyContentPresenterTF and ExceptionTF based on exception. But in the bean where i check for exception using ViewPortContext currentRootViewPort = context.getCurrentRootViewPort();
Exception exceptionData = currentRootViewPort.getExceptionData();
is coming as null (exceptionData is null always) So i am not able to switch to my ExceptionTF....I am creating a page using Webcenter Administration at runtime and click AddContent and add MyContentPresenterTF and pass ContentId (invalid) ...I am not able to catch this error. At the moment, it is showing this in default popup ...

Andrejus Baranovskis said...

Try to override DCErrorHandler class, may be it will be catched there.

Andrejus

Prasath said...

But the exception thrown by ContentPresenter Taskflow is Of ADF Faces not JBO.

ADF_FACES-60096:Server Exception during PPR, #1
javax.servlet.ServletException: oracle.webcenter.content.integration.RepositoryException: 03-Aug-2011 09:38:07 oracle.webcenter.content.integration.federated.internal.ContentValidator validateId
SEVERE: Please specify a valid ID object. Make sure the repository name is not null.

at weblogic.servlet.jsp.PageContextImpl.handlePageException(PageContextImpl.java:417)


More over, i assume that DCErrorHandler class catches only Model or Service level exception but not Controller or View level exceptions. Please advise on this scenario.

Andrejus Baranovskis said...

Controller exception handler will catch only exceptions happened during navigation in TF.

Andrejus

harini peraka said...

Hi Andrejus,

Thanks for your example.
I have declared a view jspx page as an exception handler in adfc-config.xml in my webcenter application.
1. I am using default navigation model.If I click on one of the pages and throw an exception during the initialization of backing bean class that is associated with that page, I get the error message in a pop up. Is there any way to redirect to my error page instead of displaying in a pop up.
2. In the default navigation model in another page on click of a command button i am invoking a method of backing bean of that page. In that method I am throwing a null pointer exception. Even in this case the exception comes in a pop up. I am not sure why it is not redirected to my error page.
3. In case of JBOExceptions is there any way to redirect to an error page instead of displaying in a popup

Thanks in advance,
Harini.

Andrejus Baranovskis said...

Yes, in WebCenter you would need to write your custom error handler to redirect to error page.

Andrejus

harini peraka said...

Hi Andrejus,

Thanks for your reply.

Yes, I have written a custom error handler method call and placed it in adfc-config.xml.

In the navigation model in the menu bar of home page I have placed links to different pages. In one of the pages I threw an exception but the exception still comes in a popup instead of being caught by the method call exception handler.

But if I access the url of the page directly the control goes to the exception handler.

Appreciate if you can advice why the control doesnt go to the exception handler in case of navigation model.

Dinesh said...

Hi Andrejus,

I would like to have Custom Error Handler method for "JDBC Datasource not found exception".

But I don't know where exactly my implementation should be or what classes my implementation class should extend.

Could you please provide your suggestions.

Thanks,
Dinesh