Any web application contains boilerplate text: text that is not part of the enterprise data from web services or databases that is manipulated by the end users using the application but that is part of the application definition itself. Text that is shown as prompt, title, message, hint text and in other ways. Developers can sprinkle the boilerplate text all throughout the application, in pages, JavaScript and other code sections. But they should not do that. Changing boiler plate text is a frequent requirement from the business. Having all boilerplate text in a central location makes such changes a lot easier. Additionally, many organizations require applications to be multi-lingual: different groups of users speak different languages and want to have the application support them in their own language. That means boiler plate text is not just defined once in that central location, but once for every language the application needs to support.
In previous articles I discussed how resource bundles can be used for centralizing the boilerplate text items and how a resource bundle can be implemented in a database table. I also demonstrated I how to support not just different boilerplate text items for different languages but also different sets of boiler plate text for user groups that vary by location, role, department, age or personal preference. One important aspect was not discussed thus far: how to refresh the resource bundle after the application has been started. It is very nice to use a database table to store the resource bundle entries, but one of the suggested advantages is that resource bundle entries can be added and modified while the application is running and these changes would be absorbed without having to redeploy or restart the application. This article will explain how to implement that ‘refresh resource bundle while running’ option.
Steps to add the force refresh resource bundle to an ADF application with database backed resource bundles
This article continues the story that was last told in this article: https://technology.amis.nl/2012/08/13/adding-customization-or-context-sensitivity-to-boilerplate-text-from-database-backed-resource-bundles-in-adf-applications. The application discussed here is the one created in that and previous articles.
The essence of refreshing the resource bundle is also discussed in this article: https://technology.amis.nl/2006/10/14/testing-i18n-features-of-jsf-applications-forcing-a-refresh-of-the-resource-bundles/. The initial findings in this article still hold true today – except that in JDK 6 the option to refresh the cache of resource bundles was built into the JRE as intrinsic option. For Java 6 and later, the code is therefore extremely simple. For previous versions, the code is a little more elaborate.
The implementation consists of two steps. One is the creation of a commandLink that the user can activate to start the refresh. That is easy:
The second half of the implementation consists of the actionListener actionForceBundleRefresh() in the MessageManager class – and the code that this method invokes.
Initially, forceBundleRefresh attempts to use the Java 6 approach: ResourceBundle.clearCache(). That does it at the JVM level – fairly coarse grained!
More fine grained would be to retrieve all individual resource bundles by name and refresh those (and not for example touch resource bundles for other applications running on the same JVM):
When the Java 6 approach does not work, the code calls back to the ‘old fashioned’ alternative. Bundle by bundle is processed and for each bundle, the refreshBundle() method is invoked:
using some helper methods:
To see this in action. Run the application.
Now change one of the resource bundle entries displayed in the page, in the underlying database table:
make the change to this entry that is used for the button label:
Return to the page and press the refresh link:
now the bundle’s cache is emptied and when next a value is requested from the bundle it is reloaded from the database.
Resources
Download the ADF application that is discussed in this article: ADFFacesWithResourceBundle_Step5_WithForceRefresh.
Other articles in this series:
-
Introduction to Resource Bundles in ADF applications for centralizing (management of) boilerplate text
-
Implement resource bundles for ADF applications in a database table
-
Supporting multiple languages in ADF applications backed by resource bundles – and programmatically controlling the JSF locale
-
Adding customization (or context sensitivity) to boilerplate text from database backed resource bundles in ADF applications
-
Refresh resource bundle from within the ADF application – to absorb changes in database backed bundles
-
Live update of Resource Bundle from within running ADF application
-
Live resource bundle entry editing in a generic way through declarative component and UI component tree manipulation
-
Creating reusable ADF Library with generic live resource bundle editing functionality and reusing it in any ADF application
Hi Lucas Jellema,
Thanks for the article. I have downloaded your work and it is working fine for me.
But when I try to implement same on my project, content not getting refreshed on the fly. I am able to fetch the data from the database.
seems like I missed some settings or something, I am not able to find it.
I tried to debug your application, I have some doubts here.
after executing ‘ResourceBundle.clearCache()’ line (MessageManager.java –> forceBundleRefresh()),
how are we calling getResourceBundle AM method to fetch the updated data. I don’t see any explicit call to AM method or to getContents() method of resouce bundle class method.
Or is it going to happen automatically, but not happening in my case( Am I missing any thing)?
Even i tried calling getContents() method of resouce bundle class manually after executing ResourceBundle.clearCache(). I am able to do it but still UI text is not getting refreshed on the fly.
Please help me in this regard. If you have some time I can share my sample application.
Thanks,
Poli
Thanks for the clear and helpful articles. Can you suggest a way to refresh all the JVMs in a multi-JVM application? It would be very useful to be able to keep our applications available while we fix or update our boilerplate text, but we need to be sure that all our customers are seeing the same thing…
Dear Mike,
That is an execellent question. It would seem that the best approach in a clustered situation is using MBeans to access the application. This article http://www.j2eegeek.com/blog/2004/09/23/weblogic-and-jmx/ explains how all nodes of a WebLogic cluster can be identified (for each AppServer this code will be different of course). An MBean can be invoked for each of the nodes (or rather WLS Servers on those nodes) that is thus discovered. The MBean will have to perform the action currently implemented in the MessageManager class.