Please disable your adblock and script blockers to view this page

Search this blog

Sunday, 5 February 2017

Change live application language/resource in Oracle ADF, Change XML Resource file at runtime


Hello All

I have posted about using external XML file as List resource bundle earlier , the aim of resource file is to read application static text from some source so that we can change that without compiling and redeploying application

Next requirement is to change application language , sometimes we need support multiple langauge in ADF application and it requires change in all static text so for this I am going to use separate XML resource file for different language and in this post I'll show that how to update resource file in a live running application



Here I am using same sample application and after adding resource for English language , added a list on page to select language


created a value change listener in managed bean for this list

<af:selectOneChoice label="Select Language" id="soc1" autoSubmit="true"
                                    valueChangeListener="#{ResourceManagerBean.changeLanguageVCE}"
                                    contentStyle="width:100px;">
                    <af:selectItem label="English" value="English" id="si1"/>
                    <af:selectItem label="French" value="French" id="si2"/>
                    <af:selectItem label="Dutch" value="Dutch" id="si3"/>
                </af:selectOneChoice>

Here ResourceManagerBean is a session scope bean , Initialized a session scope variable that holds the path of resource file and on value change listener of choice list I'll change path of resource file on basis of selected language

In this demo I am using 3 XML resource files for 3 different languages (English, French and Dutch)
User will select any language from the list and resource values will be read from respective resource file after a page refresh and clearing resource cache


Managed Bean Code-



import java.io.Serializable;

import java.util.ResourceBundle;

import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;

import javax.servlet.http.HttpSession;

public class ResourceManagerBean implements Serializable {

    //String variable to hold locale
    private String appLocale;
    
    public void setAppLocale(String appLocale) {
        this.appLocale = appLocale;
    }

    public String getAppLocale() {
        return appLocale;
    }
    public ResourceManagerBean() {
        //Take a session variable to put resource file path
        FacesContext fc = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession) fc.getExternalContext().getSession(true);
        session.setAttribute("resName", "D://Resource_En.xml");
    }

    /**Method to forcefully refresh page
     */
    protected void refreshPage() {

        FacesContext fctx = FacesContext.getCurrentInstance();
        String page = fctx.getViewRoot().getViewId();
        ViewHandler ViewH = fctx.getApplication().getViewHandler();
        UIViewRoot UIV = ViewH.createView(fctx, page);
        UIV.setViewId(page);
        fctx.setViewRoot(UIV);

    }

    /**Method to change app language by changing locale and XML resource file of application
     * @param vce
     */
    public void changeLanguageVCE(ValueChangeEvent vce) {
        if (vce.getNewValue() != null) {
            if ("English".equalsIgnoreCase(vce.getNewValue().toString())) {
                //Change application locale to English
                setAppLocale("en");
                FacesContext fc = FacesContext.getCurrentInstance();
                HttpSession session = (HttpSession) fc.getExternalContext().getSession(true);
                session.setAttribute("resName", "D://Resource_En.xml");

            } else if ("French".equalsIgnoreCase(vce.getNewValue().toString())) {
                //Change application locale to French
                setAppLocale("fr");
                FacesContext fc = FacesContext.getCurrentInstance();
                HttpSession session = (HttpSession) fc.getExternalContext().getSession(true);
                session.setAttribute("resName", "D://Resource_fr.xml");

            } else if ("Dutch".equalsIgnoreCase(vce.getNewValue().toString())) {
                //Change application locale to Dutch (Netherland)
                setAppLocale("nl");
                FacesContext fc = FacesContext.getCurrentInstance();
                HttpSession session = (HttpSession) fc.getExternalContext().getSession(true);
                session.setAttribute("resName", "D://Resource_nl.xml");

            }
            //Clear Resource Bundle cache to load Resource.java file again
            ResourceBundle bundle = ResourceBundle.getBundle("listresourcebundle.view.bundle.Resource");
            bundle.clearCache();

            //Refresh Page after changing resource file
            refreshPage();
        }
    }
}

Small change in Resource.java file , Now it reads Resource file path from session scope variable that is initialized in managed bean

Resource.java file-



import java.io.File;

import java.util.ListResourceBundle;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;

import javax.faces.application.Application;
import javax.faces.context.FacesContext;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Resource extends ListResourceBundle {

    //Path to XML Resource File
    private String Res_path = 
    resolvEl("#{sessionScope.resName}");

    //Initialize an Object Array to hold label and key values
    public Resource() {
        for (int i = 0; i < 5000; i++) {
            contents[i][0] = "";
            contents[i][1] = "";
        }
    }

    private static final Object[][] contents = new Object[5000][2];

    /**Method to process XML file and get key and value of resource and put that in array
     * @return
     */
    public Object[][] getContents() {
        try {
            System.out.println("Resource path is- " + Res_path);
            File file = new File(Res_path);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(file);
            doc.getDocumentElement().normalize();
            NodeList nList = doc.getElementsByTagName("label");

            for (int temp = 0; temp < nList.getLength(); temp++) {
                Node nNode = nList.item(temp);
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {

                    Element eElement = (Element) nNode;
                    contents[temp][0] = getTagValue("key", eElement);
                    contents[temp][1] = getTagValue("value", eElement);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contents;
    }

    private static String getTagValue(String sTag, Element eElement) {
        NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
        Node nValue = nlList.item(0);
        return nValue.getNodeValue();
    }

    public String resolvEl(String data) {
        FacesContext fc = FacesContext.getCurrentInstance();
        Application app = fc.getApplication();
        ExpressionFactory elFactory = app.getExpressionFactory();
        ELContext elContext = fc.getELContext();
        ValueExpression valueExp = elFactory.createValueExpression(elContext, data, Object.class);
        Object expVal = valueExp.getValue(elContext);
        String Message = "D:\\Resource_En.xml";
        if (expVal != null) {
            Message = expVal.toString();
        }

        return Message;
    }
}

Next step is to refer page locale from managed bean , Open page and in structure window select f:view tag (container tag for all components used on page)


 Refer locale property to bean variable


All Done :) Run and Check Application



Sample ADF Application (Jdeveloper 12.1.3)- Download
Cheers :) Happy Learning

2 comments :

  1. its helpful, Thanks
    I am wondering If there any way to reload the resource bundle class after any changes.

    ReplyDelete