Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reload resource bundle in web application?

I have resource bundle as Java class that read values from database. When i update db i need to reload bundle, but i don't know how. Anybody helps ?

package model.helpers;
public class Messages_en extends ListResourceBundle {
      protected Object[][] getContents() {
            // from DB
            // ...
      }
}

In view i use bundle as below:

<f:loadBundle basename="model.helpers.Messages" var="m" />
like image 548
marioosh Avatar asked Dec 01 '10 14:12

marioosh


People also ask

How do I add a ResourceBundle to ADF?

Open the faces-config. xml file. Open the Application tab. Add a Resource Bundle.

What is the use of ResourceBundle?

ResourceBundle class is used to store text and objects which are locale sensitive. Generally we use property files to store locale specific text and then represent them using ResourceBundle object. Following are the steps to use locale specific properties file in a java based application.

What is JSP ResourceBundle?

Resource bundles are properties files which contain key-value pairs. Each value is a message which we want to show on the page. Whereas the key will be used to refer to that value on our JSP page.

Why ResourceBundle is used in Java?

Resource bundles contain locale-specific objects. When your program needs a locale-specific resource, a String for example, your program can load it from the resource bundle that is appropriate for the current user's locale.


3 Answers

This is not exactly trivial.

For one just clearing the ResourceBundle via clearCache() doesn't always yield the desired results. Often you need at least also try to clear using the context class loader:

ResourceBundle.clearCache(Thread.currentThread().getContextClassLoader());

This however will still not reload the resource bundle defined in a faces-config.xml file. At least the Mojarra JSF 1.2 implementation privately caches the resource bundle internally. This happens in:

FacesContext -> Application -> associate (ApplicationAssociate) -> resourceBundles (Map<String, ApplicationResourceBundle>()) -> resources (Map<Locale, ResourceBundle>) 

It's possible to clear this cache via reflection (at the end of the day, it's just an entry in a Map), or you might wanna replace the Application. Both are not things you normally do lightheartedly.

Purely for development you could use JRebel, which probably already has knowledge of Mojarra and most likely does the reflection trick mentioned above.

After some experimenting, I came to the following code which does the trick on JBoss AS 5/JSF 1.2. It does tie your code to Mojarra (imports sun packages) and can break with any upgrade because of reflective tricks being used. But anyway, this is the code:

public static void reloadBundle() {

    ResourceBundle.clearCache(Thread.currentThread().getContextClassLoader());

    ApplicationResourceBundle appBundle = ApplicationAssociate.getCurrentInstance().getResourceBundles().get("your_bundle_name");               
    Map<Locale, ResourceBundle> resources = getFieldValue(appBundle, "resources");          
    resources.clear();
}

@SuppressWarnings("unchecked")
private static <T> T getFieldValue(Object object, String fieldName) {
    try {
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        return (T) field.get(object);
    } catch (Exception e) {
        return null;
    }       
}

(replace the getFieldValue helper method with your own favorite reflective util if necessary and sprinkle with exception and null handlers where appropriate)

like image 131
Arjan Tijms Avatar answered Nov 11 '22 10:11

Arjan Tijms


ResourceBundle.clearCache();     

OR

Messages_en .clearCache();

Calling this method will reload the resources, it will refresh the bundle

  • Reference
like image 41
jmj Avatar answered Nov 11 '22 08:11

jmj


You can even avoid to have to import weld and jsf-impl classes in your module with some more lines of reflection:

Class<?> applicationAssociateClass = Class.forName("com.sun.faces.application.ApplicationAssociate");
Method getCurrentInstance = applicationAssociateClass.getMethod("getCurrentInstance");
Object applicationAssociate = getCurrentInstance.invoke(null);
Method getResourceBundles = applicationAssociate.getClass().getMethod("getResourceBundles");
Map<String, ?> resourceBundles = (Map<String, ?>)getResourceBundles.invoke(applicationAssociate);
Object appBundle = resourceBundles.get(name);
Map<Locale, ResourceBundle> resources = getFieldValue(appBundle, "resources");
resources.clear();

(works well with Wildfly 10)

like image 1
menotyou Avatar answered Nov 11 '22 09:11

menotyou