How to reload resource bundle in web application? - java

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" />

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)

ResourceBundle.clearCache();
OR
Messages_en .clearCache();
Calling this method will reload the resources, it will refresh the bundle
Reference

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)

Related

Initialize a static cache with command line arguments

I have a class that uses a static cache that is shared between all instances of the class. I'd like to be able to set the timeout of the cache at runtime.
To provide a concrete use case: I cache values fetched from cloud storage. I'd like to refresh the values much quicker in development environments than in prod. When deploying the code, it takes an argument for the config file corresponding to that environment. This config file can contain a value for the cache refresh time.
public class Pipeline {
private static final LoadingCache<BlobId, Definitions> CACHE =
CacheBuilder.newBuilder()
.refreshAfterWrite(VALUE, TimeUnit.MINUTES) // <-- how do I set VALUE from a config file?
.build(
new CacheLoader<BlobId, Definitions>() {
public Definitions load(BlobId key) throws Exception {
return DefinitionsLoader.load(key);
}
});
...
}
To dynamically load different configurations at runtime, you can use a .properties file. In the example below I load the properties file in a static block, but you can also implement the logic in a static method that initializes the cache.
https://docs.oracle.com/javase/tutorial/essential/environment/properties.html
private static final LoadingCache<BlobId, Definitions> CACHE;
static {
Properties prop = new Properties();
try {
prop.load(new FileInputStream("config.properties"));
} catch (IOException e) {
// handle exception
}
Long value = Long.parseLong(prop.getProperty("value", "5"));
CACHE = CacheBuilder.newBuilder()
.refreshAfterWrite(value, TimeUnit.MINUTES)
.build(new CacheLoader<Integer, Definitions>() {
public Definitions load(BlobId key) throws Exception {
return DefinitionsLoader.load(key);
}
});
}
Static field initialized in their declaration are not designed to be parameterized as you want to do.
Besides, your cache loading is not flexible.
If tomorrow you change your mind or you want to use multiple of them, you cannot.
At last, it is not testable either.
If you want to provide a specific behavior to the cache loading, the most natural way to do it is changing the API of the class that contains the field.
You could provide a Pipeline constructor with a long delayInMnToRefresh parameter and you could use this parameter to set the refresh time of the cache.
public Pipeline(int delayInMnToRefresh){
CacheBuilder.newBuilder()
.refreshAfterWrite(delayInMnToRefresh, TimeUnit.MINUTES)
....
}
If you use Spring, your could using a #Autowired constructor that uses a property defined at runtime when the Spring context is loaded :
#Autowired
public Pipeline(#Value("${clould.cache.delayInMnToRefresh}") int delayInMnToRefresh){
....
}
With a property defined in this way for example in env :
clould.cache.delayInMnToRefresh=5
And another property defined in this way for example in prod :
clould.cache.delayInMnToRefresh=15
Of course, you can implement this requirement without Spring (and Spring Boot) but you should simply perform more boiler plate tasks (load the properties file before to call this method and handle yourself the notion of environment).

How to get rid of OSGi bundle's properties that are not exist in their corresponding configuration ("service.pid", etc.)?

I have the class similar to the following:
#Component(configurationPid = "foo.bar", configurationPolicy = ConfigurationPolicy.REQUIRE)
public class MyClass {
#Activate
public void activate(Map<String, Object> properties) throws Exception {
for (String property : properties.keySet()) {
if (!isValidProperty(property)) {
throw new IllegalArgumentException("Unknown property: " + property);
}
...
}
}
}
The properties map must contain the properties from the corresponding configuration source (e.g. a file provided by an user). And it is, but it also contains some properties that are not really exist (service.pid, felix.fileinstall.dir, etc.), so my program is broken. I want to get rid of them somehow.
I tried to use ConfigurationAdmin.getConfiguration.getProperties and also blueprint cm-properties but this gives the same effect.
I can't hardcode the names of the properties to exclude, because I don't know what they are.
Is there any means to tell the OSGi runtime not to put them at all in my map?
I'm doing this using ServiceMix's OSGi support (which is essentially Karaf, Felix, and Aries).
Just ignore the properties you don't like/understand. The system is designed so that the party doing the configuration can add any property and that property will be passed to your component and thus be a service property on your component's service. Removing the properties you, the component developer, don't understand is overly restrictive. You would remove the ability of someone in the deployment process from decorating your service in a way meaningful to someone else.
Currently there is no way to exclude these artificial properties but I agree this is pretty bad.
You can open an issue and the Apache felix project jira.

Configuring DropWizard Programmatically

I have essentially the same question as here but am hoping to get a less vague, more informative answer.
I'm looking for a way to configure DropWizard programmatically, or at the very least, to be able to tweak configs at runtime. Specifically I have a use case where I'd like to configure metrics in the YAML file to be published with a frequency of, say, 2 minutes. This would be the "normal" default. However, under certain circumstances, I may want to speed that up to, say, every 10 seconds, and then throttle it back to the normal/default.
How can I do this, and not just for the metrics.frequency property, but for any config that might be present inside the YAML config file?
Dropwizard reads the YAML config file and configures all the components only once on startup. Neither the YAML file nor the Configuration object is used ever again. That means there is no direct way to configure on run-time.
It also doesn't provide special interfaces/delegates where you can manipulate the components. However, you can access the objects of the components (usually; if not you can always send a pull request) and configure them manually as you see fit. You may need to read the source code a bit but it's usually easy to navigate.
In the case of metrics.frequency you can see that MetricsFactory class creates ScheduledReporterManager objects per metric type using the frequency setting and doesn't look like you can change them on runtime. But you can probably work around it somehow or even better, modify the code and send a Pull Request to dropwizard community.
Although this feature isn't supported out of the box by dropwizard, you're able to accomplish this fairly easy with the tools they give you. Note that the below solution definitely works on config values you've provided, but it may not work for built in configuration values.
Also note that this doesn't persist the updated config values to the config.yml. However, this would be easy enough to implement yourself simply by writing to the config file from the application. If anyone would like to write this implementation feel free to open a PR on the example project I've linked below.
Code
Start off with a minimal config:
config.yml
myConfigValue: "hello"
And it's corresponding configuration file:
ExampleConfiguration.java
public class ExampleConfiguration extends Configuration {
private String myConfigValue;
public String getMyConfigValue() {
return myConfigValue;
}
public void setMyConfigValue(String value) {
myConfigValue = value;
}
}
Then create a task which updates the config:
UpdateConfigTask.java
public class UpdateConfigTask extends Task {
ExampleConfiguration config;
public UpdateConfigTask(ExampleConfiguration config) {
super("updateconfig");
this.config = config;
}
#Override
public void execute(Map<String, List<String>> parameters, PrintWriter output) {
config.setMyConfigValue("goodbye");
}
}
Also for demonstration purposes, create a resource which allows you to get the config value:
ConfigResource.java
#Path("/config")
public class ConfigResource {
private final ExampleConfiguration config;
public ConfigResource(ExampleConfiguration config) {
this.config = config;
}
#GET
public Response handleGet() {
return Response.ok().entity(config.getMyConfigValue()).build();
}
}
Finally wire everything up in your application:
ExampleApplication.java (exerpt)
environment.jersey().register(new ConfigResource(configuration));
environment.admin().addTask(new UpdateConfigTask(configuration));
Usage
Start up the application then run:
$ curl 'http://localhost:8080/config'
hello
$ curl -X POST 'http://localhost:8081/tasks/updateconfig'
$ curl 'http://localhost:8080/config'
goodbye
How it works
This works simply by passing the same reference to the constructor of ConfigResource.java and UpdateConfigTask.java. If you aren't familiar with the concept see here:
Is Java "pass-by-reference" or "pass-by-value"?
The linked classes above are to a project I've created which demonstrates this as a complete solution. Here's a link to the project:
scottg489/dropwizard-runtime-config-example
Footnote: I haven't verified this works with the built in configuration. However, the dropwizard Configuration class which you need to extend for your own configuration does have various "setters" for internal configuration, but it may not be safe to update those outside of run().
Disclaimer: The project I've linked here was created by me.
I solved this with bytecode manipulation via Javassist
In my case, I wanted to change the "influx" reporter
and modifyInfluxDbReporterFactory should be ran BEFORE dropwizard starts
private static void modifyInfluxDbReporterFactory() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("com.izettle.metrics.dw.InfluxDbReporterFactory"); // do NOT use InfluxDbReporterFactory.class.getName() as this will force the class into the classloader
CtMethod m = cc.getDeclaredMethod("setTags");
m.insertAfter(
"if (tags.get(\"cloud\") != null) tags.put(\"cloud_host\", tags.get(\"cloud\") + \"_\" + host);tags.put(\"app\", \"sam\");");
cc.toClass();
}

Configuration Admin and Declarative Services not created during pax exam test phase

I've written a #component in DS that is supposed to be instantiated and activated in multiple instances. In order to test that I've written a pax exam test where I boot karaf and added scr. Everything works fine, but... it will not instantiate the services until after the test method has run thus gives me no space to do assertions etc.
#Test
public final void testing() throws Exception {
props = createProperties(user, pass, host);
cfg = configurationAdmin.
createFactoryConfiguration(CouchbaseConnectionProvider.SVC_NAME);
cfg.update(props);
final ServiceTracker tracker = new ServiceTracker(bundleContext, CouchbaseConnectionProvider.class, null);
tracker.open();
CouchbaseConnectionProvider svc = (CouchbaseConnectionProvider) tracker.waitForService(5000);
// It will wait 5s and after testing exits it will create the service
}
What am I doing wrong here?
Since when method exits it will properly create and activate the service with all properties.
I may add that the test method using a thread "ion(3)-127.0.0.1" and when DS instantiates uses the thread "84-b6b23468b652)".
Cheers,
Mario
Update 3
There where actually two bugs, one on my side and one somewhere else (in felix CM?) since the config where accessable by my interface impl bundle after a while (while container was shutting down) but it should really been bound to the pax test bundle (and of course CM itself) and never been "free:d" when container was shutting down. Where it that bug is I do not know - I'll wrap up a minimalistic mvn project and try the felix cm guys and I'll post the update here.
Update 2
I've filed a bug (https://ops4j1.jira.com/browse/PAXEXAM-725) if someone is interested to follow the progress (if there's a bug ;))
Update 1
This is my configuration in the testclass
package se.crossbreed.foundation.persistence.provider.couchbase;
#RunWith(PaxExam.class)
#ExamReactorStrategy(PerClass.class)
public class CouchbaseConnectionProviderTests extends CbTestBase {
...
}
Here is the configuration in the testclass that will use base class for
base options.
#org.ops4j.pax.exam.Configuration
public Option[] config() {
List<Option> options = super.baseConfig();
options.addAll(Arrays
.asList(features(karafStandardRepo, "scr"),
mavenBundle()
.groupId("se.crossbreed.foundation.persistence")
.artifactId(
"se.crossbreed.foundation.persistence.core")
.versionAsInProject(),
mavenBundle().groupId("io.reactivex")
.artifactId("rxjava").versionAsInProject(),
mavenBundle()
.groupId("se.crossbreed.ports.bundles")
.artifactId(
"se.crossbreed.ports.bundles.couchbase.java-client")
.versionAsInProject(),
mavenBundle()
.groupId("se.crossbreed.foundation.persistence")
.artifactId(
"se.crossbreed.foundation.persistence.provider.couchbase")
.versionAsInProject()));
// above bundle is the one I'm trying to test and where
// this test resides in (project wise)
return options.toArray(new Option[] {});
}
The base configuration is gotten from a base class
protected List<Option> baseConfig() {
return new ArrayList<Option>(
Arrays.asList(new Option[] {
logLevel(LogLevel.INFO),
karafDistributionConfiguration().frameworkUrl(karafUrl)
.unpackDirectory(new File("target", "exam"))
.useDeployFolder(false),
configureConsole().ignoreLocalConsole(),
mavenBundle().groupId("biz.aQute.bnd")
.artifactId("bndlib").version("${version.bndlib}"),
mavenBundle()
.groupId("se.crossbreed.foundation")
.artifactId(
"se.crossbreed.foundation.core.annotations")
.versionAsInProject(),
mavenBundle()
.groupId("se.crossbreed.foundation")
.artifactId(
"se.crossbreed.foundation.core.interfaces")
.versionAsInProject() }));
}
The package for the test is
package se.crossbreed.foundation.persistence.provider.couchbase;
And the CouchbaseConnectionProvider is on the same package
package se.crossbreed.foundation.persistence.provider.couchbase;
import se.crossbreed.foundation.persistence.core.CbDbConnectionProvider;
public interface CouchbaseConnectionProvider extends CbDbConnectionProvider {
public final static String SVC_NAME = "couchbase.connection.provider";
}
The implementation:
package se.crossbreed.foundation.persistence.provider.couchbase.impl;
#Component(immediate = true, name =
CouchbaseConnectionProvider.SVC_NAME, provide = {
CouchbaseConnectionProvider.class, CbDbConnectionProvider.class,
CbService.class }, properties = { "providerType=DOCUMENT" },
configurationPolicy = ConfigurationPolicy.require)
public class CouchbaseConnectionProviderImpl implements
CouchbaseConnectionProvider { ... }
Here's the project structure of the Couchbase Provider and the test that I'm failing to get to work (until after the test has run ;).
(I don't actually see anything wrong with your code, the ConfigurationAdmin should work asynchronously. The new service comming up after the test still looks like a synchronization issue though. In that case, this setup might fix it.)
Instead of creating the configuration inside the test method you could use pax-exam-cm to create the factory configuration with the other options:
#org.ops4j.pax.exam.Configuration
public Option[] config() {
List<Option> options = super.baseConfig();
options.addAll(Arrays
.asList(features(karafStandardRepo, "scr"),
//missing conversion: putAll() needs a Map
ConfigurationAdminOptions.factoryConfiguration(CouchbaseConnectionProvider.SVC_NAME)
.putAll(createProperties(user, pass, host)).create(true).asOption(),
mavenBundle()
.groupId("se.crossbreed.foundation.persistence")
.artifactId(
"se.crossbreed.foundation.persistence.core")
.versionAsInProject(),
mavenBundle().groupId("io.reactivex")
.artifactId("rxjava").versionAsInProject(),
mavenBundle()
.groupId("se.crossbreed.ports.bundles")
.artifactId(
"se.crossbreed.ports.bundles.couchbase.java-client")
.versionAsInProject(),
mavenBundle()
.groupId("se.crossbreed.foundation.persistence")
.artifactId(
"se.crossbreed.foundation.persistence.provider.couchbase")
.versionAsInProject()));
// above bundle is the one I'm trying to test and where
// this test resides in (project wise)
return options.toArray(new Option[] {});
}
Maven settings:
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-cm</artifactId>
<version>${exam.version}</version>
</dependency>
You can then also simply use the #Inject annotation to get the CouchbaseConnectionProvider inside the test.
#Inject
CouchbaseConnectionProvider svc;
I suspect that the test deploys the CouchbaseConnectionProvider interface with itself. So you try to retrieve the service using a different interface than the one the real service provides.
You should try to add imports and exports to your test bundle for the package CouchbaseConnectionProvider resides in.
To do this use a ProbeBuilder
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
probe.setHeader(Constants.IMPORT_PACKAGE, "..");
probe.setHeader(Constants.EXPORT_PACKAGE, "..");
return probe;
}
thanks both of you for your input - I chose to answer this question myself since I had a bug in my code and got help from Christoph.
I quote the answer from him here if there someone else did what I did.
The problem was that I did not set the configuration ownership as anonymous via (pid, null) in createFactoryConfiguration. Instead I used createFactoryConfiguration(pid) then it got bound to the current executing bundle and not the bundle I was testing. As Christoph explained it was possible for me to get the bundle location of the service bundle and set that explicitly.
Cheers,
Mario
Here's Christoph Läubrich answer
"Christoph Läubrich added a comment - 13 minutes ago
Okay I think I know what might be the problem now:
You are using the createFactoryConfiguration(java.lang.String factoryPid), this means you will create a configuration that is exclusivly bound to your bundle! Thus no other bundle is allowed to access the configuration!
Use the createFactoryConfiguration(java.lang.String factoryPid, java.lang.String location) instead with a null argument for the location! This way you create an anonymous configuration that will be bound to the first bundle that fetches this config. Alternativly you can get the location of the target bundle and explicitly pass this as an parameter, but this is often not needed.
If this still do not work, we must take a closer look at your configuration, connect to the karaf shell (while stopped at a breakpoint) and get a list of all bundles (bundle:list) and a list of all components (scr:list).
Also you should collect detailed information about the probe bundle and the bundle that should provide the service (packages:imports)."

Finding unused values in message resource file

I am working on a project that has been through multiple hands with a sometimes rushed development. Over time the message.properties file has become out of sync with the jsps that use it. Now I don't know which properties are used and which aren't. Is there a tool (eclipse plugin perhaps) that can root out dead messages?
The problem is that messages may be accessed by JSP or Java, and resource names may be constructed rather than literal strings.
Simple grepping may be able to identify "obvious" resource access. The other solution, a resource lookup mechanism that tracks what's used, is only semi-reliable as well since code paths may determine which resources are used, and unless every path is traveled, you may miss some.
A combination of the two will catch most everything (over time).
Alternatively you can hide the functionality of ResourceBundle behind another façade ResourceBundle, which should generally pipe all calls to original one, but add logging and/or statistics collection on the top.
The example can be as following:
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
public class WrapResourceBundle {
static class LoggingResourceBundle extends ResourceBundle {
private Collection<String> usedKeys = new HashSet<String>();
public LoggingResourceBundle(ResourceBundle parentResourceBundle) {
setParent(parentResourceBundle);
}
#Override
protected Object handleGetObject(String key) {
Object value = parent.getObject(key);
if (value != null) {
usedKeys.add(key);
return value;
}
return null;
}
#Override
public Enumeration<String> getKeys() {
return EMPTY_ENUMERATOR;
}
public Collection<String> getUsedKeys() {
return usedKeys;
}
private static EmptyEnumerator EMPTY_ENUMERATOR = new EmptyEnumerator();
private static class EmptyEnumerator implements Enumeration<String> {
EmptyEnumerator() {
}
public boolean hasMoreElements() {
return false;
}
public String nextElement() {
throw new NoSuchElementException("Empty Enumerator");
}
}
}
public static void main(String[] args) {
LoggingResourceBundle bundle = new LoggingResourceBundle(ResourceBundle.getBundle("test"));
bundle.getString("key1");
System.out.println("Used keys: " + bundle.getUsedKeys());
}
}
Considering that some of your keys are run-time generated, I don't think you'll ever be able to find a tool to validate which keys are in use and which ones are not.
Given the problem you posed, I would probably write an AOP aspect which wraps the MessageSource.getMessage() implementation and log all the requested codes that are being retrieved from the resource bundle. Given that MessageSource is an interface, you would need to know the implementation that you are using, but I suspect that you must know that already.
Given that you would be writing the aspect yourself, you can create a format that is easily correlated against your resource bundle and once you are confident that it contains all the keys required, it becomes a trivial task to compare the two files and eliminate any superfluous lines.
If you really want to be thorough about this, if you already have Spring configured for annotation scan, you could even package up your aspect as its own jar (or .class) and drop it in a production WEB-INF/lib (WEB-INF/classes) folder, restart the webapp and let it run for a while. The great thing about annotations is that it can all be self contained. Once you are sure that you have accumulated enough data you just delete the jar (.class) and you're good to go.
I know that at least two of the major java IDEs can offer this functionality.
IntelliJ IDEA has a (disabled, by default) Inspection that you can
use to do this:
go to Settings -> Inspections -> Properties files -> ... and enable
the 'Unused property'
..Only problem I had was that it didn't pick up some usages of the property from a custom tag library I had written, which I was using in a few JSPs.
Eclipse also has something like this ( http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftasks-202.htm ) but I haven't really exhausted the how well it works.

Categories

Resources