1

I want to reload/refresh my resource bundle after data updates.

My ResourceBundle implementation is based on db, here the code:

public class DatabaseResourceBundle extends ResourceBundle {

  private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("ADAEcommerceEjbPU");
  private EntityManager _entityManager = factory.createEntityManager();
  private Map<String, String> _values = new HashMap<>();
  protected final static String BUNDLE_NAME = "com.infomaxgroup.adaecommerce.bundles";
  private final static Logger LOGGER = Logger.getLogger(DatabaseResourceBundle.class.getName());
  private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
  protected Control DB_CONTROL = new DBControl();

  /**
   * Public constructor setting the parent bundle
   */
  public DatabaseResourceBundle() {
    LOGGER.log(Level.FINE, "DatabaseResourceBundle()");
    setParent(ResourceBundle.getBundle(BUNDLE_NAME,
            FacesContext.getCurrentInstance().getViewRoot().getLocale(), DB_CONTROL));
  }

  public DatabaseResourceBundle(Locale locale) {
    LOGGER.log(Level.FINE, "DatabaseResourceBundle(Locale locale)");
    setParent(ResourceBundle.getBundle(BUNDLE_NAME, locale, DB_CONTROL));
  }

  @Override
  protected Object handleGetObject(String key) {
    LOGGER.log(Level.FINE, "handleGetObject() Locale {0} Key: {1} ", new Object[]{locale.toString(), key});
    return _values != null ? _values.get(key) : parent.getObject(key);
  }

  @Override
  public Enumeration<String> getKeys() {
    LOGGER.log(Level.FINE, "getKeys() Parent Locale {0} ", parent.getLocale());
    return parent.getKeys();
  }

  /**
   * The Control Callback.
   *
   * @see
   * http://docs.oracle.com/javase/6/docs/api/java/util/ResourceBundle.Control.html
   */
  protected class DBControl extends Control {

    @Override
    public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
            throws IllegalAccessException, InstantiationException, IOException {
      LOGGER.log(Level.INFO, "reload {0} ", reload);
      return new MyResources(locale);
    }

    /**
     * A simple ListResourceBundle
     */
    protected class MyResources extends ListResourceBundle {

      private Locale locale;

      /**
       * ResourceBundle constructor with locale
       *
       * @param locale
       */
      public MyResources(Locale locale) {
        this.locale = locale;
      }

      @Override
      protected Object[][] getContents() {
        if (locale == null) {
          locale = Locale.ITALY;
        }

        TypedQuery<ResourceEntity> query = _entityManager.createNamedQuery("ResourceEntity.findForLocale", ResourceEntity.class);
        query.setParameter("locale", locale.getLanguage());

        List<ResourceEntity> resources = query.getResultList();

        Object[][] all = new Object[resources.size()][2];
        int i = 0;
        for (Iterator<ResourceEntity> it = resources.iterator(); it.hasNext();) {
          ResourceEntity resource = it.next();
          all[i] = new Object[]{resource.getKey(), resource.getValue()};
          _values.put(resource.getKey(), resource.getValue());
          i++;
        }
        return all;
      }
    }
  }
}

When I update the data and call DatabaseResourceBundle.clearCache() I see that the next request calls the method:

MyResources.getContents()

If I debug what data is returned into

Object[][] all

here I see the updated data but on the JSF page I still see the old data, seems like the JSF uses cached data.

How can I see the updated data into JSF page ?

Many thanks in advance...

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
giates
  • 301
  • 4
  • 15
  • which application server are you using? – Dennis Kriechel Aug 04 '13 at 18:54
  • Glassfish 3.1.2 see question title ;) – giates Aug 04 '13 at 18:57
  • Ouch, your right, only concentrated on the text... So I'm not sure if this is the something I have seen yet, but its possible to inject resources with annotations. Not Sure if this is possible with resource bundles based on db. Those resourced can be reloaded with jndi lookups: https://blogs.oracle.com/chengfang/entry/how_to_inject_and_look – Dennis Kriechel Aug 04 '13 at 19:00
  • Your suggestion would be reloading the whole resource bundle using jndi ? – giates Aug 04 '13 at 19:05
  • yes, if this is something you can live with, this is the only way I see, but maby there are more options out there – Dennis Kriechel Aug 04 '13 at 19:06
  • possible duplicate of [Changes in property files does not reflect in page while using Glassfish 3.1.2 server](http://stackoverflow.com/questions/13174456/changes-in-property-files-does-not-reflect-in-page-while-using-glassfish-3-1-2-s) – BalusC Aug 05 '13 at 01:04
  • You don't need to yell SOLVED in title. Just post an answer and mark it accepted. It'll already appear differently in listings and be searchable as such. Look, you're here on a Question & Answer site designed specifically for asking questions and finding answers, not on an old fashioned discussion forum where this additional mess would be "necessary" because a discussion forum is the wrong platform for asking questions and finding answers. – BalusC Aug 06 '13 at 14:14
  • You're right BalusC, many thanks... – giates Aug 07 '13 at 08:58

1 Answers1

0

The issue has been solved with the steps below:

1) after modification (insert, update, delete) of any ResourceEntity I call

DatabaseResourceBundle.clearCache();

2) If I want to refresh the JSF resource labels I call this code (the suggested code comes from: How to reload resource bundle in web application?):

  ApplicationResourceBundle applicationBundle = ApplicationAssociate.getCurrentInstance().getResourceBundles().get("msg");
  Field field = null;
  try {
    field = applicationBundle.getClass().getDeclaredField("resources");
  } catch (NoSuchFieldException | SecurityException ex) {
    Logger.getLogger(UserRegistrationController.class.getName()).log(Level.SEVERE, null, ex);
  }
  if (field != null) {
    field.setAccessible(true);
    Map<Locale, ResourceBundle> resources = null;
    try {
      resources = (Map<Locale, ResourceBundle>) field.get(applicationBundle);
    } catch (IllegalArgumentException | IllegalAccessException ex) {
      Logger.getLogger(UserRegistrationController.class.getName()).log(Level.SEVERE, null, ex);
    }
    if (resources != null) {
      resources.clear();
    }
  }

Hope this helps...

Community
  • 1
  • 1
giates
  • 301
  • 4
  • 15