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. In this article I will describe 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. The example in this article is a variation of boilerplate text based on the selected age context (none, Junior or Senior):
Note that any context (or combination of contexts) can be used.
In a later piece we will discuss how to refresh a resource bundle in running application and finally we will see how we can create an in-line resource bundle editing mechanism that allows users to manipulate the boiler plate text in context in a running application.
Note: this article is a sequel to this article (http://https://technology.amis.nl/2012/08/10/implement-resource-bundles-for-adf-applications-in-a-database-table ) that introduces the database backed resource bundles, and this article (https://technology.amis.nl/2012/08/11/supporting-multiple-languages-in-adf-applications-backed-by-resource-bundles-and-programmatically-controlling-the-jsf-locale) that explains how the locale can be programmatically set.
Steps to introduce one context to vary boilerplate text (i.e. resource bundle entries) in
1. Add a column to specify the context to the table RESOURCE_BUNDLE_ENTRIES
2. Extend the PL/SQL API to cater for the context
This means: adding the input parameter p_context in function get_resource_bundle_entries in both specification and body and extending the SQL query to take the context into consideration.
and in the body:
3. Modify Java method getResourceBundle() in Class AppModuleImpl
Add a parameter context in the method signature, add an addition bind parameter in the callable statement and pass the context parameter as the additional bind parameter’s value:
4. Refresh the Client Interface of the Application Module AppModule (add the changed getResourceBundle() method to the client interface
5. Change the generic page definition GenericPageDef.xml
Add the context parameter to the operationBinding for getResourceBundle():
6. Modify the DatabaseResourceBundle Class
The DatabaseResourceBundle class contains method getResourceBundle() that retrieves the contents of the resource bundle from the database – through the GenericPageDef’s operation binding. This method needs to be extended for the new context parameter:
The call to getResourceBundle() needs to be modified as well:
And the method getContext1() is added:
For each context value, there will be separate class – just like there is one for each supported language. The method getContext1() needs to be implemented in each of these classes – returning null, Junior or Senior.
7. Create context specific DatabaseResourceBundle classes
Add a DatabaseResourceBundle class for every context value (and for each language) that is to be supported. Ensure that in this class the proper context value is returned by getContext1(), for example:
and
8. Create class MessageProvider
This class will return the resource bundle entries. It is directly referred to from within the boilerplate text properties in the pages – using expressions like #{msg[‘key’]}. Because this class implements the Map interface, it can be accessed with this type of EL expression. The msg bean – based on MessageProvider – gets the MessageManager passed in (to be discussed next). This MessageManager uses the current locale and context as well as all registered resource bundles (potentially more than one) to return the requested value.
9. Create class MessageManager
This class does the hard work when it comes to returning the appropriate resource bundle entry, given the locale and the context.
The class exposes method getMessage() that is invoked from the MessageProvider. This method will try to find the resource bundle entry with the best fit, given the key – and the current locale and context.
The current context is set in the property contextDimensionValue (by a selectOneChoice, as we will see in a little while). Method getMessage() first tries to find the resource entry in a context sensitive bundle. If that fails, it will try to look the resource in context neutral (ignorant) way:
Method getMessageFromResourceBundle() retrieves the current locale from the JSF ViewRoot (where our custom ViewHandler has put it). It iterates over the bundles (in this case there is only one) defined through the bundleNames member, set through a managed property in the faces-config.xml file. It attempts to find the entry for the given key in each of the bundles (that may be post fixed with the context specific postfix). As soon as the entry is found, the method returns.
10. Create managed bean definitions in the faces-config.xml file
Two new managed beans are required. Bean msg will be referred to in each page, whenever a resource bundle entry is required. Bean msgMgr is injected into bean msg and will provide it with the actual logic of retrieving the bundle entry.
11. Modify PageOne.jspx: replace bnd references (to JSF resource bundle) with msg references (to the msg bean)
12. Add a context selector to PageOne.jspx – a selectOneChoice that manipulates the context value in the msgMgr bean:
13. Create Resource Bundle Entry records in the database table for the resource keys and supported languages and context values:
14. Run the page and try out various combinations of language and context (Age Context)
Change the Age Context
(and press F5 to refresh the browser or reload from the browser address bar)
From Junior to Senior:
and on to Dutch:
Dutch in the Junior context:
and in the age neutral context:
Resources
Download the ADF application discussed in this article:ADFFacesWithResourceBundle_Step4_WithContextVariation .