-
1. Re: Hot redeploy of message bundles
vladimir.kovalyuk Oct 2, 2008 12:37 AM (in response to vladimir.kovalyuk)It turned out that it is not very difficult to override org.jboss.seam.i18n.Messages and org.jboss.seam.core.ResourceLoader. Overriding components uses custom Control with timeToLive about 15 seconds and they are installed only in debug mode, so they are not intrusive in production mode.
After that I can play with message files and see the result immediately.
I can post details if someone is interested in. -
2. Re: Hot redeploy of message bundles
joblini Oct 2, 2008 3:20 AM (in response to vladimir.kovalyuk)Hello,
Please post details.
Thanks!
-
3. Re: Hot redeploy of message bundles
vladimir.kovalyuk Oct 2, 2008 9:40 AM (in response to vladimir.kovalyuk)DynamicMessages.java:
import static org.jboss.seam.annotations.Install.APPLICATION; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.core.SeamResourceBundle; import org.jboss.seam.international.Messages; @Scope(ScopeType.STATELESS) @BypassInterceptors @Name("org.jboss.seam.international.messagesFactory") @Install(precedence = APPLICATION, debug = true) public class DynamicMessages extends Messages { @Override protected Map createMap() { return new FakeMap<String, String>() { protected ResourceBundle getSeamBundle() { ResourceBundle.Control control = DynamicResourceBundleControl.instance(); return ResourceBundle.getBundle(SeamResourceBundle.class.getName(), org.jboss.seam.core.Locale .instance(), Thread.currentThread().getContextClassLoader(), control); } @Override public String get(Object key) { if (key instanceof String) { String resourceKey = (String) key; String resource = null; if (getSeamBundle() != null) { try { resource = getSeamBundle().getString(resourceKey); } catch (MissingResourceException mre) { // Just swallow } } return resource == null ? resourceKey : resource; } else { return null; } } }; } }
DynamicResourceLoader.java:
import static org.jboss.seam.annotations.Install.APPLICATION; import java.util.MissingResourceException; import java.util.ResourceBundle; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.core.Locale; import org.jboss.seam.core.ResourceLoader; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; @Scope(ScopeType.STATELESS) @BypassInterceptors @Install(precedence = APPLICATION, debug = true) @Name("org.jboss.seam.core.resourceLoader") public class DynamicResourceLoader extends ResourceLoader { private static final LogProvider log = Logging.getLogProvider(DynamicResourceLoader.class); @Override public ResourceBundle loadBundle(String bundleName) { try { ResourceBundle.Control control = DynamicResourceBundleControl.instance(); ResourceBundle bundle = ResourceBundle.getBundle(bundleName, Locale.instance(), Thread.currentThread() .getContextClassLoader(), control); log.debug("loaded resource bundle: " + bundleName); return bundle; } catch (MissingResourceException mre) { log.debug("resource bundle missing: " + bundleName); return null; } } }
DynamicResourceBundleControl.java:
import java.util.ResourceBundle; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; @Name("dynamicResourceBundleControl") @BypassInterceptors @Scope(ScopeType.SESSION) @AutoCreate public class DynamicResourceBundleControl extends ResourceBundle.Control { public static DynamicResourceBundleControl instance() { return (DynamicResourceBundleControl) Component.getInstance(DynamicResourceBundleControl.class, true); } private long timeToLive = ResourceBundle.Control.TTL_NO_EXPIRATION_CONTROL; public long getTimeToLive() { return timeToLive; } @Override public long getTimeToLive(String baseName, java.util.Locale locale) { return timeToLive; } @Override public boolean needsReload(String baseName, java.util.Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) { return true; } public void setTimeToLive(long timeToLive) { this.timeToLive = timeToLive; } }
-
4. Re: Hot redeploy of message bundles
vladimir.kovalyuk Oct 2, 2008 9:47 AM (in response to vladimir.kovalyuk)You may play with timeToLive initializer, by default it is initialized as everlasting value ResourceBundle.Control.TTL_NO_EXPIRATION_CONTROL.
Or you can add to components.xml the following lines:<component name="dynamicResourceBundleControl"> <property name="timeToLive">15000</property> </component>
The second way is more convinient for me since I use an extra components.xml file in dev env.
-
5. Re: Hot redeploy of message bundles
vladimir.kovalyuk Oct 2, 2008 9:55 AM (in response to vladimir.kovalyuk)Just forgot to mention that FakeMap is a fake implementation of Map interface and looks as follows:
public abstract class FakeMap<TKey, TValue> implements Map<TKey, TValue> { @Override public void clear() { throw new UnsupportedOperationException(); } ... }
You get the idea.
-
6. Re: Hot redeploy of message bundles
pmuir Oct 2, 2008 12:08 PM (in response to vladimir.kovalyuk)Could you write this up as a blog or knowledge base tutorial? If you have any Java 5 recommendations, please put them in JIRA.
-
7. Re: Hot redeploy of message bundles
ahus1 Oct 4, 2008 9:22 PM (in response to vladimir.kovalyuk)Hi, i tried your code and it works great.
I had one little problem with the standard faces messages. It seems that the ResourceBundle loads the standard messages earlier without using a control or timeout as you do.
I used this workaround to clear the complete resource bundle cache and then asking seam to load the resources with the proper timeout.
I just added the following code as constructor for DynamicResourceLoader:
public DynamicResourceLoader() { ResourceBundle.clearCache(); new SeamResourceBundle(); }