Last year June, I was blogging about how to use ADF Libraries for calling remote ADF Task Flows - How To Call Remote Task Flow in JDeveloper 11g. Recently in our project we decided to split one big application into smaller ones and to create separate ViewController projects per each module implemented by Model projects. Splitting was divided into two steps - extract modules into separate ADF applications and then integrate all those applications back. Key requirement is to have one deployment archive, centralized security and at the same time to work on separate applications without any interruption. In order to implement this task, I decided to revisit ADF Libraries topic and actually I saw that in new JDeveloper 11g release integration can be implemented much easier than before. I will not focus in this post on ADF Libraries and ADF Task Flows description, you can check my older post for this. I will describe today how integration could be done now and one problem I faced (with solution of course :).
Developed sample application - ADFIntegration.zip, contains three ADF applications - LocalApp, RemoteApp and RemoteSecondApp. LocalApp acts as main application, where other two are integrated. I'm integrating two applications, because problem I faced is not reproduced in basic case - when integrating only one.
For overview purpose, main application contains one page and two ADF Task Flow calls defined. Its calling two integrated applications through ADF Task Flows:
You can see that two ADF Task Flow calls are just usual calls:
This means that we can integrated separate application through ADF Task Flow in so called plug and play way. Both ADF Task Flows are integrated through ADF Libraries generated from separate applications:
You can just drag and drop ADF Task Flow from ADF Library and it works fine - it can access your ADF BC, Bindings and Web pages. When libraries are added into your main application, you can see them listed under ADF Library definition:
And perfect news, when main application is starting, WebLogic loads all three DataBindings files (just provide different names for them and dont forget to update adfc-config.xml also). You can see from the log that DataBindings.cpx from main application is loaded first, then DataBindings from integrated libraries are loaded - DataBindings1.cpx and DataBindings2.cpx accordingly:
Along with DataBindings, all Page Definition entries are loaded.
Everything seems fine, but during integration in my project I have faced a problem (as usual :)). When loading one of ADF Task Flows from integrated application I got NullPointerException. I reproduced this in my sample, you can see it from the log:
From the first line of log, you can see that it tries to load RemoteModuleDataControl from DataBindings2.cpx file, which is incorrect - RemoteModuleDataControl is defined in first ADFLibrary, inside DataBindings1.cpx file. After some thinking, I saw in previous log message with DataBindings load order, that DataBindings2.cpx is loaded the last. This means, my integrated form was trying to use incorrect DataBindings.cpx file. I was even more sure about this, when I saw that form from second application was working, its because its based on last load DataBindings2.cpx file. At first I was thinking may be its Oracle bug, but then I found its actually was our bug - we were calling Application Modules from default Method Call activities in our ADF Task Flows directly, bypassing Binding layer. Let's describe a best practice how it should be done.
I fixed this integration error, by going to ADF Task Flow from application I was integrating:
I have opened selected ADF Task Flow and it looks like this - Method Call is defined as default activity, and it was cause of problem. We are using Method Calls as default activities, because we are invoking specific actions before opening page, I believe its common requirement:
I have checked what is invoked from this Method Call - its Backing bean method:
Then I opened this method and I saw it calls Application Module directly, bypassing Bindings layer - which is bad practice. We always should access Application Module through Bindings in ModelViewController type applications. Bad practice example:
In general, we should get DataBindings and invoke method from Application Module, this method also should be defined in Page Definition. However, in this specific case, we even don't need method in Backing bean. Better we can declare Method Call through Binding layer in ADF Task Flow directly:
Separate Page Definition file was created for this Method Call and action from Application Module defined:
We are invoking custom method from Application Module using Method Call declared as default ADF Task Flow activity:
After fix, don't forget to redeploy ADF Library, main application will pick-up changes automatically. On runtime, when opening form from first integrated ADF Library, correct DataBindings1.cpx is loaded now:
Form screen from integrated application is successfully loaded:
It seems, application splitting and integration is pretty good in latest JDeveloper 11g release.