FROM THE BLOG

ADF Tutorials: Time Manager and Application Scoped Object Update

Let’s start explaining the use case:

An ADF Application is storing an Object in the application scope and it needs to be always up to date. The object may be updated by externals sources at any time so it needs to be constantly refreshed to avoid stale data. So, how do you keep up to date this object? We have created a simple application where the ApplicationModule reads the first line of a file and store it in the application scope. This object needs to be updated all the time in order to get the latest data in case the file is modified later on.

In order to achieve the solution, a mix of documentation, blog posts and strategies were used. To start with, we need a job which tasks is to keep the application scope object up to date. For this, we found really useful the following blog entry from Andrejus Baranovskis http://andrejusb.blogspot.com/2013/03/optimizing-long-running-adf-operations.html.

So let’s start with the screenshots:

This is a method in our application module implementation. As I said earlier, it will read the first line of a file and store it in the application scope.

adf_update_app_scope_automatically_1

We then created a Context Initializer class which basically will trigger the job to start working as soon as the application is deployed using the TimeManager object;

adf_update_app_scope_automatically_2

Next, the class which will be doing the job. The code is self-explanatory. An application module instance is create which then is used to call the syncMessage method to update the application scope object.

adf_update_app_scope_automatically_3

We then consume the object in our page as a outputText with the value

#{applicationScope.announcement}

adf_update_app_scope_automatically_7

We make sure our announcement file has a text on it:

adf_update_app_scope_automatically_4

We run the application and once it’s deployed we can immediately see the following messages in the log:

<Info> <ky.oralution.appscoperfrsh.view.contextInit.ContextInitializer> <BEA-000000> <Task created to update announcements> 
<Info> <ky.oralution.appscoperfrsh.view.jobs.UpdateJob> <BEA-000000> Syncroning Data> 
<Info> <ky.oralution.appscoperfrsh.model.bc.services.AppModuleImpl> <BEA-000000> <Before: null> 
<Info> <ky.oralution.appscoperfrsh.model.bc.services.AppModuleImpl> <BEA-000000> <After: Thank you for reading...> 
   Syncronized. Took: 0>

We run the page expecting to see our message with no problem:

adf_update_app_scope_automatically_5

No, you are not blind… The message doesn’t appear and if we don’t change the implementation will never appear. Reason is, as we found out later is that the Job, scheduled by the TimerManager, runs in different context. We can see this by adding the highlighted line of code in our applicationModule syncMessage method:

adf_update_app_scope_automatically_6

Now, we run the application again. We can see in the log the following entries:

<Info> <ky.oralution.appscoperfrsh.view.jobs.UpdateJob> <BEA-000000> Syncroning Data> 
<Info> <ky.oralution.appscoperfrsh.model.bc.services.AppModuleImpl> <BEA-000000> <Before: Thank you for reading...> 
<Info> <ky.oralution.appscoperfrsh.model.bc.services.AppModuleImpl> <BEA-000000> <After: Thank you for reading...> 
defaultApplicationName

But then, using the UI, we call the syncMessage manually and surprisingly we get our text in the screen;

adf_update_app_scope_automatically_8

We now check the log entries;

<Info> <ky.oralution.appscoperfrsh.model.bc.services.AppModuleImpl> <BEA-000000> <Before: null> 
<Info> <ky.oralution.appscoperfrsh.model.bc.services.AppModuleImpl> <BEA-000000> <After: Thank you for reading...> 
RefreshAppScopeObjectAutomatically

As you can see, the application names are not the same

defaultApplicationName != RefreshAppScopeObjectAutomatically

At this point, we have two options to go forward and accomplished our task.

  1. Use coherence (or third-party cache solution) to cache instead the application scope (We tested with coherence and it works just fine!)
  2. Tweak the implementation so the call to the application module method is made within the context of our application.

Since option 1 is trivial and it works, I decided to keep going and implement the 2nd option as well. This time, we will use the TimerManager to invoke a servlet and do the update from there by using the existing binding layer of the application. For this, we followed the following blog post from Timo Hahn http://tompeez.wordpress.com/2011/12/16/jdev11-1-2-1-0-handling-imagesfiles-in-adf-part-3/. Please refer to it (point 2) to learn more about this approach.

We create the pageDefinition for our sync process and added our method call.

adf_update_app_scope_automatically_9

We then proceed to create a servlet and execute from there the syncMessage method we exposed in our dummy page definition.

adf_update_app_scope_automatically_10

We need now to register the servlet in our web.xml;

adf_update_app_scope_automatically_15

We now update our Context Initializer to pass the servlet url to out modified UpdateJob;

adf_update_app_scope_automatically_14

Now we update our UpdateJob class to invoke the servlet:

adf_update_app_scope_automatically_11

Now, we all is set to run the application one more time, this time expecting to see the message in screen and expect the value to maintain updated:

adf_update_app_scope_automatically_12

Now, we update the message in announcements.txt

adf_update_app_scope_automatically_13

Once we save the file, and refresh the browser (after waiting few seconds to give time to the job to run):

adf_update_app_scope_automatically_16

The only drawback of this approach that I see is that you need to hardcode the servlet URL. You could use a web.xml init param to store this but still you will need to hardcode it somewhere unless you are willing to implement a complicated way to get the whole URL for the servlet.

We would also like to thank kdario and Cvele_new_account (from OTN Community) for their help through out this solution.

2 comments

  1. Pandurang Parwatikar

    on

    Reply

    Thanks Oralution!
    This covers more knowledge about ContextListeners and WLS TimeManager.

    Regards,
    Pandurang

  2. Cvele_new_account

    on

    Reply

    Hey, excellent article!
    It was a pleasure to read.
    You are welcome, and – cheers 😉

Leave a comment

Your email address will not be published. Required fields are marked *

Social Media

Stay up-to-date with our latest ADF and related technical posts via your favourite social network services.