Notifying ADF applications of database changes - fast and lean using Active Data Service for Server to Client Push - Part Two image43

Notifying ADF applications of database changes – fast and lean using Active Data Service for Server to Client Push – Part Two

Yesterday I wrote that in two articles, I would demonstrate how we can ensure that changes in the database – new, changed or deleted data – can rapidly be reflected in ADF based user interfaces running in browsers. This story involves a two-step push-mechanism: push from database to middle tier and push from middle tier to browser. For the former – discussed in Notifying ADF applications of database changes – fast and lean using Database Query Result Change Notification – Part One – we will use the Oracle Database (and JDBC Driver) feature Query Result Change Notification and for the latter we leverage the Active Data Service in ADF Faces. The latter – server to browser push – is the topic of this second part. It will hook into where the first part took us (so you are advised to first read part one) and take the changes the database notifies us all the way up into the user interface.

A sketch of the architecture of the application we will create in this article looks like this:

image

The two push steps are marked with the green ellipses. The red box indicates the area under scrutiny in this article.

Part one concluded with a set up in which changes in the data in table EMP were reported through Database Query Result Change Notification to the ADF Model layer and from there via an Application Scope mediator bean to Session Scope beans. It also demonstrated how the ViewObject could be made to re-execute its query in order to retrieve the changed data from the database – through an invokeAction in the Page Definition that executes the ViewObject’s Execution operation and that has its refreshCondition tied to the sessionScope bean that receives word of changes in table EMP. The one thing still lacking from this pretty picture was the mechanism to let the browser know that a change is pending and a server request is desired from the browser. At this point we wait for such a request to take place in order to piggy back the pending changes on that request back to the browser.

ADF Faces provides a mechanism called Active Data Service that allows us push changes from the server to the client. Through Active Data Services, we can inform the browser about the fact that changes are available. The browser can respond by queuing a server event that through a serverListener results in a request that is handled by a bean in the server. At that point, the piggy back construction (mainly because of the change event policy on the iteratorBinding set to ppr) kicks in and the changes are automatically pushed on the response up to the browser.

Our challenge here is the mechanism that informs the browser and puts into motion the mechanism that sends the server event. What we will be using is the nudge pattern (described in my presentation at JavaOne 2011 – http://www.slideshare.net/lucasjellema/dont-call-us-well-push-cross-tier-push-architecture-javaone-2011) where a UI component is nudged to have it initiate a request. The nudge itself does not do anything more than tell the browser that stuff is waiting for it.

This illustration describes the nudge pattern:

image

The important elements are the activeOutputText component (invisible) in the UI that is bound to a session scope bean that extends the Active Data Service abstract class. This bean has registered with the application scope event handler that is notified from the model about any database changes. The activeOutputText has a clientListener that fires upon property changes. That means that it will fire (and invoke a Javascript function) whenever the active bean updates its state. The JavaScript function in this case will push a server event onto the queue that will be handled by a server listener, a method in bean on the server.

Implementation steps

These are steps for implementing the nudge based push of EMP changes to the UI:

  1. Create activeBean that registers as listener with application scope event handler
  2. Create activeOutputText bound to activeBean
  3. Add clientListener to activeOutputText, invoking a Javascript function
  4. Create JavaScript function that pushes the server event
  5. Create serverListener (in the page) to link the server event to a server side bean method
  6. Implement managed bean with method to handle server event by clearing the cache of the ViewObject (or making a boolean refreshIsInOrder available to the invokeAction that executes the ViewObject’s query action as was discussed in part one of this series).

 

Create activeBean that registers as listener with application scope event handler

The ActivePageNotifierBean is created, extending from the ADS base class BaseActiveDataModel and implementing the interface DataUpdateListenerI that was created to register listeners with the application scope DatabaseNotificationProcessor bean – the ones that routes through the EMP notifications received from the Model. When such a notification is handled, the processDataUpdate() method is invoked on the ActivePageNotifierBean and from this method, the triggerDataUpdate() method is called to handle updating the state of the Active bean.

image

Note how in the setupActiveData method – annotated with @PostConstruct, to be executed after the bean has been created by JSF – the object is registered as a listener with the DatabaseNotificationProcessor  bean that has been injected.

The configuration in the faces-config.xml file for this bean:

image

Create activeOutputText bound to activeBean

The activeOutputText component has its value attribute bound to the state property of the ActivePageNotifierBean . This means that whenever the fireActiveDataUpdate() method is invoked inside the bean, the ADS push mechanism kicks in and pushes the change to the browser.

image

Add clientListener to activeOutputText, invoking a Javascript function

When changes are received from ADS in the activeOutputText, its value is updated and an associated clientListener for the propertyChange event would fire. Here we tie a call to JavaScript function activeDataCallback to this event.

Create JavaScript function that pushes the server event

Function activeDataCallback that is invoked from the clientListener is the function that will push the server event to be sent back to the server in what is the start of the required request onto which the changes we need in the UI can be piggy backed.

image

This function locates the outputText component in the page with id tableToRefresh. This component is required because it has the serverListener that provides our bridge from browser to client. When the component is located, a server event called refreshDataEvent is push on to the queue, targeted at the outputText component.

Create serverListener (in the page) to link the server event to a server side bean method

The serverListener attached to the outputText component finally handles the the refreshDataEvent pushed by the activeDataCallback JavaScript function by sending it to the server side dataRefresher bean’s refreshDataFromTable method:

image

The dataRefresher bean to enforce requery of the ViewObject

Next we implement the managed bean with method to handle server event by clearing the cache of the ViewObject (or making a boolean refreshIsInOrder available to the invokeAction that executes the ViewObject’s query action as was discussed in part one of this series).

image

The configuration of this bean in the faces-config.xml file:

image

Application Architecture

The entire application architecture is outlined in this picture:

image

taken from the Oracle Open World 2011 presentation: http://www.slideshare.net/lucasjellema/push-to-the-limit-rich-and-proactive-user-interfaces-with-adf-oracle-open-world-2011.

And…Action

The application in action is not hugely spectacular, especially when all you see is screenshots. Just to give you a small taste I will show the browser with the Employees Table. Then the update (and commit) of EMP data in the database. Then the browser again, less than a second after committing the database transaction. I swear that I did not touch the browser nor did anything to make it refresh. The changes were pushed! Really!

The browser with the original table with Employee records:

image

Updating salaries and committing these changes in the database:

image

The browser with the changes pushed in:

image

Resources

Download the JDeveloper 11g (11.1.1.4) application with the complete example described in this article: ADFApplicationWithDBQRCN.