ADF BC and Faces: Fun with Bind Parameters Part Two – Locale specific database querying from the ViewObjects

0

In this article I would like to demonstrate another unexpected usage of ADF BC bind-parameters. In a previous entry I argued that bind parameters are typically seen as good only for the where-clause of an SQL query underlying a ViewObject. In that entry I showed using a bind parameter to select between very distinct order by clauses. Now we will take a look at using a bind parameter to select the meaning associated with domain values in the proper language, as defined through the UI locale. The article as an aside demonstrates how we can change the locale on the fly, by selecting the desired value from a set of radiobuttons. Note: that part of the discussion is based on one of the undocumented samples from Steve Muench.

....

Preparation

The table that holds our domains of allowable values:

create table domains<br />( name       varchar2(40)<br />, value      varchar2(100)<br />, meaning_en varchar2(500)<br />, meaning_nl varchar2(500)<br />, meaning_de varchar2(500)<br />, meaning_fr varchar2(500)<br />, meaning_it varchar2(500)<br />, meaning_es varchar2(500)<br />) <br />

Each supported language has its own language column. Of course we could have opted for a more normalized design, which would have had our table columns as name, value, locale, meaning. But we did not.

Entries in this table look like:

insert into domains<br />( name, value, meaning_en<br />, meaning_nl, meaning_de, meaning_fr<br />, meaning_it, meaning_es<br />)<br />values<br />( 'JOB', 'SALESMAN', 'Commercially active employee'<br />, 'Commerciële collega', 'Verkäufer' ,'Vendeur'<br />, 'Commesso', 'Vendedor'<br />)<br />/<br /><p>insert into domains<br />( name, value, meaning_en<br />, meaning_nl, meaning_de, meaning_fr<br />, meaning_it, meaning_es<br />)<br />values<br />( 'JOB', 'MANAGER', 'The Boss'<br />, 'Leidinggevende', 'Chef' ,'Directeur'<br />, 'Responsabile', 'Encargado'<br />)<br />&nbsp;</p>

Depending on the desired UI language, we should select the appropriate meaning-column.

 

ADF Business Components – The Model project

We can create a ViewObject JobsView that we can use for querying the Job domain, for example for populating Dropdownlists in User Interfaces where users can set the value for items based on this domain. The query for this read-only view object can be defined like this:
 

select value<br />,      case :locale<br />       when 'en'<br />       then  meaning_en<br />       when 'nl'<br />       then  meaning_nl<br />       when 'it'<br />       then  meaning_it<br />       when 'es'<br />       then  meaning_es<br />       when 'de'<br />       then  meaning_de<br />       when 'fr'<br />       then  meaning_fr<br />       end meaning<br />from   domains<br />where  name ='JOB'<br />and    nvl(:locale ,'XX') &lt;&gt; 'YY'<br />

 
The key thing to notice for the purpose of this article is the use of the bind parameter :locale to determine which value should be returned as the meaning.

 

Our Model also contains an EmpView ViewObject based on the EMP table in the SCOTT schema. 

Developing the User Interface

Having the ViewObject all set up is a good thing. However, we also need the User Interface to demonstrate how we can leverage this View Object. I make use of JHeadstart to generate a simple page that shows a table with all employees in my EMP table, with a Dropdown (SelectOneChoice) for the Job item. JHeadstart will also generate a  dropdownlist for selecting the current language, so we can easily toggle between locales. Note: we need more than just a dropdownlist with languages in order to toggle between languages. The code behind this is taken from a sample by Steve Muench (see list of Resources).

Steps:

1. Create a New ViewController project and JHeadstart-enable it using the JHeadstart wizard/plugin.

2. Create a New Application Definition File

3. Create a new dynamic domain Jobs, based on the JobsView. Set the Query Bind Parameters property for the Domain to locale=#{App.language}. This takes care of applying the value of the currently selected locale language to the bind parameter :locale in the JobsView.

4. Create a New Group, based on the EmpView, with Table Layout.

5. Associate the Job item with the Jobs domain; change the display type for Job to dropdownlist.

6. Create a Static Domain Locales, with the supported locales as allowable values  

7. Create an extra, unbound Item, called Locale. Set the display type to radio-vertical, set the domain to Locales; set Display in Table Layout to false and Display in Table Overflow to true.

 

The value of this item linked to the App backing bean’s language property, through an EL expression #{App.language}.

8. Set the property Depends on Item for the Job item (or any other item) to Locale.

Post generation changes:

Set the partialTriggers attribute for the generated table element – to have the table refreshed in a PPR operation when the Locale-selection is changed.

partialTriggers=&quot;EmployeesLocale&quot;&nbsp;

Configure the managed bean App in the faces-config.xml file:

 &lt;managed-bean&gt;<br />   &lt;managed-bean-name&gt;App&lt;/managed-bean-name&gt;<br />   &lt;managed-bean-class&gt;nl.amis.view.App&lt;/managed-bean-class&gt;<br />   &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt;<br /> &lt;/managed-bean&gt;<br />&nbsp;

The App class is a very simple bean:

package nl.amis.view;<br /><br />import java.util.Locale;<br /><br />public class App {<br />    public App() {<br />    }<br />    Locale preferredLocale= new Locale(&quot;en&quot;);<br />    String language = &quot;en&quot;;<br />    public void setPreferredLocale(Locale preferredLocale) {<br />      this.preferredLocale = preferredLocale;<br />    }<br /><br />    public Locale getPreferredLocale() {<br />        return preferredLocale;<br />    }<br /><br />    public void setLanguage(String language) {<br />        this.language = language;<br />        setPreferredLocale(new Locale(language));<br />    }<br /><br />    public String getLanguage() {<br />        return language;<br />    }<br />}<br />&nbsp;

Configure the supported locales in the faces-config.xml file – also configure a custom view-handler, that will set the locale on the ViewRoot, based on the setting in the App bean:

  &lt;application&gt;<br />    &lt;default-render-kit-id&gt;oracle.adf.core&lt;/default-render-kit-id&gt;<br />    &lt;locale-config&gt;<br />      &lt;default-locale&gt;en&lt;/default-locale&gt;<br />      &lt;supported-locale&gt;en&lt;/supported-locale&gt;<br />      &lt;supported-locale&gt;it&lt;/supported-locale&gt;<br />      &lt;supported-locale&gt;es&lt;/supported-locale&gt;<br />      &lt;supported-locale&gt;fr&lt;/supported-locale&gt;<br />      &lt;supported-locale&gt;de&lt;/supported-locale&gt;<br />      &lt;supported-locale&gt;nl&lt;/supported-locale&gt;<br />    &lt;/locale-config&gt;<br />    &lt;view-handler&gt;nl.amis.view.PreferredLanguageSettingViewHandler&lt;/view-handler&gt;<br />&lt;/application&gt;<br />&nbsp;

This custom ViewHandler class is developed by Steve Muench. My slightly modified class looks like this:

package nl.amis.vi
ew;<br /><br />import oracle.adfinternal
.view.faces.application.ViewHandlerImpl;<br />import java.io.IOException;<br /><br />import java.util.Locale;<br /><br />import javax.faces.FacesException;<br />import javax.faces.application.ViewHandler;<br />import javax.faces.component.UIViewRoot;<br />import javax.faces.context.FacesContext;<br />import javax.faces.el.ValueBinding;<br /><br /><br />/**<br /> * This custom view handler sets the preferred locale on the view root<br /> * if it's different from the current locale, based on the preferredLocale<br /> * property of the session-scoped managed bean named &quot;App&quot;.<br /> */<br />public class PreferredLanguageSettingViewHandler extends ViewHandlerImpl {<br />    public PreferredLanguageSettingViewHandler(ViewHandler delegate) {<br />        super(delegate);<br />    }<br /><br />    public void renderView(FacesContext facesContext, UIViewRoot uIViewRoot)<br />            throws IOException, FacesException {<br />        App    app             = (App) getEl(&quot;#{App}&quot;);<br />        Locale preferredLocale = app.getPreferredLocale();<br /><br />        if (preferredLocale == null) {<br />            app.setPreferredLocale(uIViewRoot.getLocale());<br />        } else {<br />            if (preferredLocale != uIViewRoot.getLocale()) {<br />                uIViewRoot.setLocale(preferredLocale);<br />            }<br />        }<br /><br />        super.renderView(facesContext, uIViewRoot);<br />    }<br /><br />    public static Object getEl(String expr) {<br />        FacesContext fc = FacesContext.getCurrentInstance();<br />        ValueBinding vb = fc.getApplication().createValueBinding(expr);<br /><br />        return vb.getValue(fc);<br />    }<br />}<br />&nbsp;

When we run the application, we see a table with Employees. The Job column is of displaytype dropdownlist. It shows all allowable values for Job in the currently selected language. When we change the Locale, the table is refreshed and we see the Job domain values for the new language. Notice that the Details button and Next link also change to the proper language.

In Dutch:

And in German:

Resources

Steve Muench’s Not Yet Documented Sample: Change Preferred UI Locale with a Button in the Page [10.1.3.1]

Download the JDeveloper 10.1.3.1 Application demonstrated above: LocaleAsBindParameter.zip.

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.

Comments are closed.