Implement resource bundles for ADF applications in a database table

0

Any web application contains boiler plate 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.

Java (Web) applications typically make use of a built in structure for centralizing (and internationalizing) boiler plate text; it is called Resource Bundle. In a previous article – http://technology.amis.nl/2012/08/09/introduction-to-resource-bundles-in-adf-applications-for-centralizing-management-of-boilerplate-text – I described how resource bundles can be introduced into ADF applications (or basically and JSF application) to centralize (management of) boiler plate text, using file based resource bundles. This article you are currently reading continues from that article.

The purpose of this article is to demonstrate how you can implement your resource bundle using a database table instead of a file.

image

Managing database backed resource bundles can be a lot easier than managing their file based equivalent – through a simple edit page for example, used by an application administrator or business representative. Besides, with resource bundles in the database, changes can be applied without having to go through full redeployment of the application. Using a few simple steps including a table, a PL/SQL package, an ADF BC Application Module with a custom method in the client interface, a generic PageDefinition with one operationBinding for that custom method and a Java Class that extends the standard Java ListResourceBundle in order to leverage the database, you will quickly see the mechanism come together.

In later articles I will discuss 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. 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.

Steps for implementing the resource bundle in a relational database table

1. Let us first create a simple database table that will contain the resource bundle entries for our application.

image

it is the relational equivalent of the resource bundle in property file format: key and value, with the locale added in there as well to distinguish between different languages.

2. Instead of having the application define the SQL to execute for retrieving the resource bundle entries, I have decided to introduce a package that provides an API to the application.

image

This I consider a good practice – keeping SQL out of the application, thereby making life simpler for the ADF developers and adding additional decoupling that allows for optimizations behind the API without impacting the ADF application. In this case the function get_resource_bundle_entries will take the locale – Java term for language and optionally region – as input and return a Ref Cursor. The structure of the records returned by this cursor is (key, value).

The package implementation:

image

3. In ADF applications, a common way to interact with the database is of course through ADF BC. If we already have an Application Module, we can extend that one with a method for retrieving the contents of the resource bundle. In this case, we first need to add an Application Module to the Model project. Note: you can just as well use JPA (EclipseLink or Hibernate) or even create your own code that retrieves a Data Source can calls the PL/SQL package.

Create an Application Module – leveraging a database connection to the schema in which the package is created. Accept all defaults.

image

On step 4, mark the checkbox to generate the Application Module Class:

image

When the ApplicationModule is created, open the editor. Select the Java tab. Click on the link that takes you to the AppModuleImpl class:

image

Add the following method:

image

This method retrieves the database transaction from the ApplicationModule super class. It constructs a Callable statement to call out to the package. The package returns a Ref Cursor which maps to a JDBC ResultSet. This ResultSet is iterated through and all records are turned into Map entries – key/value pairs. The statement is closed, the Map is returned.

Back in the application module editor, click on the edit icon to start editing the client interface:

image

Add the newly added method to the client interface of the application module to make that method available across the data binding bridge:

image

Click OK. The Java tab in Application Module editor now looks like this:

image

and the Data Control that the ViewController project will use, now also exposes the operation getResourceBundle.

image

Insert a few resource bundle entries into the table:

image

Then run the Application Module to test the new method:

image

Click on the AppModule node. Enter the value en as the locale and press the execute button:

image

The results should be visible and the values you inserted into the database should be among them:

image

4. Create a generic PageDefinition with an operationBinding for getResourceBundle

The ViewController project contains the resource bundle. At this moment, the implementation is based on a property file, but before too long we will switch to a Resource Bundle that is implemented by a Java Class. And that Java Class needs to get hold of the resource bundle entries from the database. It will do so using the DataControl AppModuleDataControl (and indirectly the ApplicationModule and the underlying PL/SQL package). Programmatic access to an operation exposed by a Data Control can be done through a generic page definition that contains an operation binding for that operation. This page definition is accessed at run time from whatever Java code.

The easiest way to create a generic page definition is by creating a JSF page called Generic.jspx, dragging the operation from the Data Control palette to the page

image

- thus creating the page definition and the operation binding at the same time

image

and then deleting the page and removing the reference to the page from the file DataBindings.cpx:

image

5. Create a Java Class based Resource Bundle, backed by resource bundle entries from the database

Although it is common to see Resource Bundles based on files, they can just as easily be based on Java Classes. Any class for example that extends ListResourceBundle (see http://docs.oracle.com/javase/tutorial/i18n/resbundle/list.html) which requires the implementation of the getContents() method that returns an array of arrays (Object[][])

image

can be used as Resource Bundle.

Create a class called DatabaseResourceBundle in package nl.amis.view.bundles. Have the class extend ListResourceBundle and implement the required method:

image

Change the getContents() method to have it return one or multiple of the keys used in PageOne:

image

6. Registering a Java Class based Resource Bundle is very similar to registering a file based resource bundle. The fully qualified name of the class replaces the fully file-path-qualified name of the properties file in the faces-config.xml file:

image

or in source code:

image

7. Run the page

image

Not surprisingly, two resource bundle entries have been lost – and two are still there, this time returned from Java.

8. Hook up the DatabaseResourceBundle class with the actual database content.

The getContents() method is changed: it either returns the already initialized contents, or it first initializes the contents. The initResourceBundle() method is not tied to either database or ADF Binding – it relies on a method getResourceBundle(locale) to return a Map with the resource bundle entries and it will then prepare the Object[][] stored class member:

image

The real action is in the method getResourceBundle(). This method dives into the ADF Binding framework, gets hold of the Generic Page Definition and inside it of the getResourceBundle() operation binding that it will execute for the required locale:

image

 

Note: at this moment the implementation is still a little rough around the edges. This means for example that the page on which the database backed resource bundle is first accessed should have a Page Definition associated with it – otherwise there will not be a binding context to access the GenericPageDef in.

9. Run the page

image

Two resource bundle entries are retrieved from the database (two others have yet to be added).

The next articles will discuss support for multiple languages as well as multi-context resource bundles and on line editing for resource bundles.

Resources

Download the ADF application discussed in this article: ADFFacesWithResourceBundle_Step2_DatabaseBacked.

Previous article, introducing resource bundles in ADF applications: http://technology.amis.nl/2012/08/09/introduction-to-resource-bundles-in-adf-applications-for-centralizing-management-of-boilerplate-text .

Other articles in this series:

  1. Introduction to Resource Bundles in ADF applications for centralizing (management of) boilerplate text

  2. Implement resource bundles for ADF applications in a database table

  3. Supporting multiple languages in ADF applications backed by resource bundles – and programmatically controlling the JSF locale

  4. Adding customization (or context sensitivity) to boilerplate text from database backed resource bundles in ADF applications

  5. Refresh resource bundle from within the ADF application – to absorb changes in database backed bundles

  6. Live update of Resource Bundle from within running ADF application

  7. Live resource bundle entry editing in a generic way through declarative component and UI component tree manipulation

  8. Creating reusable ADF Library with generic live resource bundle editing functionality and reusing it in any ADF application

Other articles in this series:

  1. Introduction to Resource Bundles in ADF applications for centralizing (management of) boilerplate text

  2. Implement resource bundles for ADF applications in a database table

  3. Supporting multiple languages in ADF applications backed by resource bundles – and programmatically controlling the JSF locale

  4. Adding customization (or context sensitivity) to boilerplate text from database backed resource bundles in ADF applications

  5. Refresh resource bundle from within the ADF application – to absorb changes in database backed bundles

  6. Live update of Resource Bundle from within running ADF application

  7. Live resource bundle entry editing in a generic way through declarative component and UI component tree manipulation

  8. Creating reusable ADF Library with generic live resource bundle editing functionality and reusing it in any ADF application

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

Leave a Reply