Tuesday, January 7, 2014

Simple Example for ADF Active Data Service

Active Data Service in ADF is very useful functionality, it allows to push data to the UI, without extra refresh/reload. However, due to its complexity, is not used too often. My goal is to provide as much as possible simple example for ADS use case in this post. In the future posts, I plan to post updated samples with more complex use case implementations.

ADS is configured in adf-config.xml file, here you can download complete sample application - LongRunningTaskPushApp.zip. There is active output text component, it displays number of open jobs and is refreshed by ADS:


Once we navigate to the Employees tab - Open jobs counter is reloaded:


Separate thread, where we generate new jobs is started when ADS is activated and is stopped automatically, when ADS is deactivated (when navigating away from page or closing browser):


Thread is stopped automatically, when browser is closed or navigating away to other page:


Active output text value is retrieved from managed bean method:


This managed bean is registered in session scope and is responsible to manage ADS lifecycle:


We can see that managed bean method is accessing binding and gets initial value from there - it comes from ADF BC attribute:


This relationship is defined in Page Definition - initial value is retrieved from ADF BC:


There is post construct method - we are setting up ADS model info, basically registering active output text component value to be reloaded automatically by push from ADS:


There are two standard methods from ADS model overridden to control ADS lifecycle start and stop events:


As you can see above - thread to push ADS changes is created in start method, automatically when ADS gets initialised after post construct method. Thread is stopped automatically, when ADS is deactivated (this happens when browser is closed or navigated to other page).

Active output text is reloaded by triggered method, where ADS event is generated - using registered active output text value:


When opening Employees tab, Open jobs counter is reloaded from resetData method, referenced from panel collection visible property:

11 comments:

Phai Vv said...

nices post. Thank you for keep it up

Andrejus Baranovskis said...

Thanks.

Anonymous said...

Hi,

I am trying to extend the application and adding code to get BindingContext in AdsController triggerActiveDataUpdateEvent method. But BindingContext.getCurrent() is returning null. Can you please suggest what could me the issue. Currently i am only displaying the counter on jspx page with page definition file. The code itself is working fine.

Thanks

Andrejus Baranovskis said...

I'm not sure if this would work with ADS, this was the reason in my sample app not to use Binding Context directly.

Andrejus

FrankD said...

What if i will need to do an executeQuery from the BindingContext or do something that is specified in the bindings ?

Andrejus Baranovskis said...

I don't think this is supported, this is why I was not using it directly in this sample - but publishing data from Model through push.

Andrejus

Raguraman said...

Andrejus,

I have a workaround to access the bindingcontext whenever ADF push happens. Steps are given below. I follow the same for my requirement. Correct me if the approach is wrong.

1. AdsControllerBean is registered at session scope, thus retains value across the request. We should keep a boolean variable (say dueTOADSPush) with public setter/getter exposed.

2. Add a hidden UIComponent (Say OutputText) which is mapped to a request scoped manage bean getter. (This is the place where we will be having code that first check the AdsControllerBean::isDueToADSPush using if condition. If it is true, it goes inside and work with binding context and finally refreshes the desired UIComponent. Make sure you set the dueToADSPush flag to false as first line inside if condition )

3. Add javascript method during propertychange event of activeoutputText component. This javascript code should access the hidden outputtext component and refresh it (so that getter will be invoked)


4. Whenever ADS push happens, in addition to calling 'fireActiveDataUpdate', set this boolean value to true.


Behavior:

1. ADS push happens and we set 'dueTOADSPush' flag to true.
2. OutputText UIComponent refresh happens due to actual ADSPush and our extra javascript code.
3. Getter method mapped to OutputText component fires.
4. If condition check happens (to identify whether this request is because of ADSpush)
5. Control goes inside if condition, does our logic by working with bindingcontext and finally refereshes the desired components and set the dueTOADSPush flag to false)

Actually we are making one extra request whenever ADS push happens to get our desired behavior

Andrejus Baranovskis said...

Thanks for update, this could be useful for readers. I would need to test this approach.

Regards,
Andrejus

Raguraman said...

Andrejus,

One more info from what I experienced while working with ADS particularly with af:ActiveOutputText component.

If we keep the code, that sets up the active model info, inside post construct method, application looses ADS connection whenever full submission (or at least F5 refresh for sure) happens. As a result, after page full refresh, ADS will stop working. You can confirm this using chrome/firebox debugger console by checking the connection state of ads.

Instead of postConstruct, if we keep the code inside the getter (i.e. getOpenJobs in this sample), it works fine all the time. af:Table component doesn't contain this issue.

Thanks

Andrejus Baranovskis said...

Thanks, your comments are very useful !

Andrejus

mrigendra singh said...

Very helpful example Andrejus!
I am also using ADS in my project and have hit a roadblock.
For my project I am trying to update the table directly when the table in updated in the database. I receive the DatabaseChangeEvent from the OracleDB but don't know where to get new row data from, to pass to buildActiveDataUpdateEvent method (image11 above). Do I need to? Any suggestions?