This is a webapp running on Tomcat, using Guice. According to the docs we should be able to call ResourceBundle.clearCache(); to clear the ResourceBundle cache and presumably get the latest from the bundle property files.
We have also tried the following:
Class klass = ResourceBundle.getBundle("my.bundle").getClass().getSuperclass();
Field field = klass.getDeclaredField("cacheList");
field.setAccessible(true);
ConcurrentHashMap cache = (ConcurrentHashMap) field.get(null);
cache.clear(); // If i debug here I can see the cache is now empty!
and
ResourceBundle.clearCache(this.class.getClassLoader());
The behavior that I am expecting is:
Start up tomcat and hit a page and it says 'Hello World'
Change the properties file containing 'Hello World' to 'Goodbye Earth'
Clear the cache using a servlet
Hit the page and expect to see 'Goodbye Earth'
So question is, how is ResourceBundle.clearCache() actually working ? And is there some generic file cache we need to clear also ?
This worked for me:
ResourceBundle.clearCache();
ResourceBundle resourceBundle= ResourceBundle.getBundle("YourBundlePropertiesFile");
String value = resourceBundle.getString("your_resource_bundle_key");
Notes:
ResourceBundle.clearCache() is added at Java 1.6
Do not use a static resourceBundle property, use
ResourceBundle.getBundle() method after invoking clearCache()
method.
I do not believe you can effect the reloading of an already created ResourceBundle instance since its internal control class has already been created. You may try this as an alternative for initializing your bundle:
ResourceBundle.getBundle("my.bundle", new ResourceBundle.Control() {
#Override
public long getTimeToLive(String arg0, Locale arg1) {
return TTL_DONT_CACHE;
}
});
I have found this solution (works with tomcat):
use a custom ResourceBundle.Control (because I need UTF8)
add the getTimeToLive as "Perception" description
force the reload flag
the "ResourceBundle.clearCache" doesn't work
How to call :
ResourceBundle bundle = ResourceBundle.getBundle("yourfile", new UTF8Control());
The custom class :
public class UTF8Control extends Control
{
public ResourceBundle newBundle(
String baseName,
Locale locale,
String format,
ClassLoader loader,
boolean reload)
throws IllegalAccessException, InstantiationException, IOException
{
// The below is a copy of the default implementation.
String bundleName = toBundleName(baseName, locale);
String resourceName = toResourceName(bundleName, "properties");
ResourceBundle bundle = null;
InputStream stream = null;
// FORCE RELOAD because needsReload doesn't work and reload is always false
reload = true;
if (reload) {
URL url = loader.getResource(resourceName);
if (url != null) {
URLConnection connection = url.openConnection();
if (connection != null) {
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
}
else {
stream = loader.getResourceAsStream(resourceName);
}
if (stream != null) {
try {
// Only this line is changed to make it to read properties files as UTF-8.
bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
}
finally {
stream.close();
}
}
return bundle;
}
// ASK NOT TO CACHE
public long getTimeToLive(String arg0, Locale arg1) {
return TTL_DONT_CACHE;
}
}
maybe this post can solve your problem.
this is one more possibility to clear cache
Class<ResourceBundle> type = ResourceBundle.class;
try {
Field cacheList = type.getDeclaredField("cacheList");
cacheList.setAccessible(true);
((Map<?, ?>) cacheList.get(ResourceBundle.class)).clear();
}
catch (Exception e) {
system.out.print("Failed to clear ResourceBundle cache" + e);
}
This works, iff you can intercept the very first creation of the resource bundle:
while (true) {
ResourceBundle resourceBundle = ResourceBundle.getBundle("SystemMessages", new Locale("hu", "HU"),
new ResourceBundle.Control() {
#Override
public List<String> getFormats(String baseName) {
return ResourceBundle.Control.FORMAT_PROPERTIES;
}
#Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException {
System.err.println(this.toBundleName(baseName, locale) + ": " + format + " - " + reload);
return super.newBundle(baseName, locale, format, loader, reload);
}
#Override
public long getTimeToLive(String baseName, Locale locale) {
long ttl = 1000;
System.err.println(this.toBundleName(baseName, locale) + " - " + ttl + "ms");
return ttl;
}
#Override
public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) {
System.err.println(baseName + "_" + locale + " - " + new Date(loadTime));
return true;
}
});
System.out.println(resourceBundle.getString("display.first_name") + ": John");
System.out.println(resourceBundle.getString("display.last_name") + ": Doe");
Thread.sleep(5000);
}
Related
I am new to OpenTelemetry word. I have created spans for my services separately, but when i am try to combine spans of two different services, using context propogation, I am not able to do it successfully.
I have used following code:
// at client side:
public static void sendContext(String resource) {
TextMapSetter<HttpURLConnection> setter =
new TextMapSetter<HttpURLConnection>() {
#Override
public void set(HttpURLConnection carrier, String key, String value) {
carrier.setRequestProperty(key, value);
}
};
HttpURLConnection transportLayer = null;
String urlString = "http://127.0.0.1:8080" + resource;
try {
URL url = new URL(urlString);
transportLayer = (HttpURLConnection) url.openConnection();
} catch (MalformedURLException ex) {
System.out.println(ex.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
GlobalOpenTelemetry.getPropagators()
.getTextMapPropagator()
.inject(Context.current(), transportLayer, setter);
}
// at server side:
public static Context getContext(HttpServletRequest request) {
TextMapGetter<HttpServletRequest> getter =
new TextMapGetter<HttpServletRequest>() {
#Override
public String get(HttpServletRequest carrier, String key) {
Enumeration<String> headerNames = carrier.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println("headerNames.nextElement(): " + headerName);
if (headerName.equals(key)) {
String headerValue = request.getHeader(headerName);
System.out.println("headerValue): " + headerValue);
return headerValue;
}
}
}
return null;
}
#Override
public Iterable<String> keys(HttpServletRequest carrier) {
Set<String> set = new HashSet<String>();
Enumeration<String> headerNames = carrier.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
set.add(headerNames.nextElement());
}
}
return set;
}
};
Context extractedContext =
GlobalOpenTelemetry.getPropagators()
.getTextMapPropagator()
.extract(Context.current(), request, getter);
At server, i am not able to get parent span.
Kindly help on this.
You can refer to OpenTelemetry main documentation from here. It contains the context propagation part but I used HttpHeader type getter as the TextMapGetter with the same functionality which shows in the doc and instead of using
Scope scope = extractedContext.makeCurrent()
as the scope to create a child span, better to use directly without the scope,
tracer.spanBuilder(spanName).setParent(extractedContext)
Because sometimes the automated way to propagate the parent span on the current thread does not work fine.
I've encountered a situation that looked more or less like this while refactoring code; rewritten here for the sake of the example:
public class UrlProbe {
private final OkHttpClient http;
private final String url;
private final Function<Response, Object> transform;
private Object cachedValue;
public UrlProbe(OkHttpClient http, String url) {
this(http, url, this::debuggingStringTransform);
}
public UrlProbe(OkHttpClient http, String url, Function<Response, Object> transform) {
this.http = http;
this.url = url;
this.transform = transform;
}
private Object debuggingStringTransform(Response response) {
String newValue = response.body().toString();
System.out.println("Debugging new value from url " + url + ": " + newValue);
return newValue;
}
public synchronized Object probe() {
if (cachedValue != null) {
return cachedValue;
}
try (Response response = http.newCall(new Request.Builder().url(url).get().build()).execute()) {
cachedValue = transform.apply(response);
return cachedValue;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
This code will not compile because we cannot reference this before supertype constructor has been called:
public UrlProbe(OkHttpClient http, String url) {
this(http, url, this::debuggingStringTransform);
}
The following will not compile either:
public UrlProbe(OkHttpClient http, String url) {
this(http, url, response -> debuggingStringTransform(response));
}
The only way I've found around this is to explicitly use a non-chaining constructor:
public UrlProbe(OkHttpClient http, String url) {
this.http = http;
this.url = url;
this.transform = this::debuggingStringTransform;
}
While it makes sense to restrict the use of this in constructors chaining arguments, I find it surprising in this particular context as there doesn't appear to be any kind of evaluation of the object being constructed caused by the use of this when it comes to method references and the contents of a lambda expression.
Is there a rationale behind this restriction other than it is because JLS §8.8.7.1 says so?
Allowing referencing this scope that early would break code that looks like this
public class UrlProbe {
final String url;
final String param2;
public UrlProbe(String url) {
this(url, this::debuggingStringTransform);
}
public UrlProbe(String url, Function<String, String> transform) {
this(url, transform.apply("")); // <-- What should happen when url is referenced here?
}
public UrlProbe(String url, String param2) {
this.url = url;
this.param2 = param2;
}
private String debuggingStringTransform(String response) {
System.out.println("Debugging new value from url " + url + ": " + response);
return response;
}
}
That's at least one way of violating the rules.
IntelliJ shows this on the tooltip for why this code is "bad":
Cannot reference 'this' before supertype constructor has been called
This makes sense. You're in the middle of constructing your object and the method reference as defined only exists after the class is instantiated. It can't realistically exist before it's fully instantiated, since from a semantic standpoint, you can't actually do anything with it until it's "ready".
If you wanted to get around this, you could change that function to a static one, since there's no state required for it:
public UrlProbe(OkHttpClient http, String url) {
this(http, url, UrlProbe::debuggingStringTransform);
}
private static Object debuggingStringTransform(Response response) {
String newValue = response.body().toString();
System.out.println("Debugging new value from url " + url + ": " + newValue);
return newValue;
}
...although admittedly it looks weird to see a private static method.
Alternatively, have this function exist elsewhere in the same package, like in a static class at the bottom of this one:
public UrlProbe(OkHttpClient http, String url) {
this(http, url, Functions::debuggingStringTransform);
}
static class Functions {
static Object debuggingStringTransform(Response response) {
String newValue = response.body().toString();
System.out.println("Debugging new value from url " + url + ": " + newValue);
return newValue;
}
}
I manage two properties is one for the generic messages and one for each module belonging to my system, but the problem I'm having is that when invoking the first method getMessage() always invokes the properties of the resource, when it should go the message.
public class ResourceBundleUtil implements Serializable {
private static final long serialVersionUID = 1L;
public static final String MESSAGE_PATH = "messages";
public static final String RESOURCE_PATH = "resources";
private static HashMap<String, Object> messageBundles = new HashMap<String, Object>();
public static String getMessage(String key) {
if (key == null) {
return null;
}
try {
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
if (locale == null) {
locale = Locale.ENGLISH;
}
ResourceBundle messages = (ResourceBundle) messageBundles.get(locale.toString());
if (messages == null) {
messages = ResourceBundle.getBundle(MESSAGE_PATH, locale);
messageBundles.put(locale.toString(), messages);
}
return messages.getString(key);
} catch (Exception e) {
return key;
}
}
public static String getResource(String key) {
if (key == null) {
return null;
}
try {
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
if (locale == null) {
locale = Locale.ENGLISH;
}
ResourceBundle messages = (ResourceBundle) messageBundles.get(locale.toString());
if (messages == null) {
messages = ResourceBundle.getBundle(RESOURCE_PATH, locale);
messageBundles.put(locale.toString(), messages);
}
return messages.getString(key);
} catch (Exception e) {
return key;
}
}
}
The problem I have is that the getMessage() method always invokes the resource propertie, when should the message:
if (messages == null) {
messages = ResourceBundle.getBundle(MESSAGE_PATH, locale);
messageBundles.put(locale.toString(), messages);
}
No enters the conditional, and noticed that comes with name value is resource.
Unlike the method getResource() if I notice that operating normally.
Please I could comment on that problem should, thanks.
Looks like the problem is that you store both kinds of bundles in single map. So if resources bundle is used first, it is added to map. The key is current locale (e.g. "en").
Then if you try to retrieve messages bundle with the same locale you in fact get resources bundle instead of messages one because you use the same key.
To solve this problem either use two separate maps or prepend key with bundle identifier like this:
messageBundles.put("resources_" + locale.toString(), messages);
Btw. you use standard Java bundles. More hints on how to use bundles defined in faces-config.xml can be found here:
How can I get a message bundle string from inside a managed bean?
I'm using java.util.resourcebundle to format my JSTL messages and this works fine:
I use the class MessageFormat you can see here. Now I want to encapsulate this to a method that is just getParametrizedMessage(String key, String[]parameters) but I'm not sure how to do it. Now there is quite a lot of work to display just one or two messages with parameters:
UserMessage um = null;
ResourceBundle messages = ResourceBundle.getBundle("messages");
String str = messages.getString("PF1");
Object[] messageArguments = new String[]{nyreg.getNummer()};
MessageFormat formatter = new MessageFormat("");
formatter.applyPattern(messages.getString("PI14"));
String outputPI14 = formatter.format(messageArguments);
formatter.applyPattern(messages.getString("PI15"));
String outputPI15 = formatter.format(messageArguments)
if(ipeaSisFlag)
if(checkIfPCTExistInDB && nyreg.isExistInDB()) {
//um = new ExtendedUserMessage(MessageHandler.getParameterizedMessage("PI15", new String[]{nyreg.getNummer()}) , UserMessage.TYPE_INFORMATION, "Info");
um = new ExtendedUserMessage(outputPI15 , UserMessage.TYPE_INFORMATION, "Info");
…and so on. Now can I move this logic to a static class MessageHandler.getParameterizedMessage that now is not working and looking like this:
private final static String dictionaryFileName="messages.properties";
public static String getParameterizedMessage(String key, String [] params){
if (dictionary==null){
loadDictionary();
}
return getParameterizedMessage(dictionary,key,params);
}
private static void loadDictionary(){
String fileName = dictionaryFileName;
try {
dictionary=new Properties();
InputStream fileInput = MessageHandler.class.getClassLoader().getResourceAsStream(fileName);
dictionary.load(fileInput);
fileInput.close();
}
catch(Exception e) {
System.err.println("Exception reading propertiesfile in init "+e);
e.printStackTrace();
dictionary=null;
}
}
How can I make using my parametrized messages as easy as calling a method with key and parameter?
Thanks for any help
Update
The logic comes from an inherited method that in in the abstract class that this extends. The method looks like:
protected static String getParameterizedMessage(Properties dictionary,String key,String []params){
if (dictionary==null){
return "ERROR";
}
String msg = dictionary.getProperty(key);
if (msg==null){
return "?!Meddelande " +key + " saknas!?";
}
if (params==null){
return msg;
}
StringBuffer buff = new StringBuffer(msg);
for (int i=0;i<params.length;i++){
String placeHolder = "<<"+(i+1)+">>";
if (buff.indexOf(placeHolder)!=-1){
replace(buff,placeHolder,params[i]);
}
else {
remove(buff,placeHolder);
}
}
return buff.toString();
}
I think I must rewrite the above method in order to make it work like a resourcebundle rather than just a dictionary.
Update 2
The code that seems to work is here
public static String getParameterizedMessage(String key, Object [] params){
ResourceBundle messages = ResourceBundle.getBundle("messages");
MessageFormat formatter = new MessageFormat("");
formatter.applyPattern(messages.getString(key));
return formatter.format(params);
}
I'm not really sure what you're trying to achive, here's what I did in the past:
public static final String localize(final Locale locale, final String key, final Object... param) {
final String name = "message";
final ResourceBundle rb;
/* Resource bundles are cached internally,
never saw a need to implement another caching level
*/
try {
rb = ResourceBundle.getBundle(name, locale, Thread.currentThread()
.getContextClassLoader());
} catch (MissingResourceException e) {
throw new RuntimeException("Bundle not found:" + name);
}
String keyValue = null;
try {
keyValue = rb.getString(key);
} catch (MissingResourceException e) {
// LOG.severe("Key not found: " + key);
keyValue = "???" + key + "???";
}
/* Message formating is expensive, try to avoid it */
if (param != null && param.length > 0) {
return MessageFormat.format(keyValue, param);
} else {
return keyValue;
}
}
I have a file called mybundle.txt in c:/temp -
c:/temp/mybundle.txt
How do I load this file into a java.util.ResourceBundle? The file is a valid resource bundle.
This does not seem to work:
java.net.URL resourceURL = null;
String path = "c:/temp/mybundle.txt";
java.io.File fl = new java.io.File(path);
try {
resourceURL = fl.toURI().toURL();
} catch (MalformedURLException e) {
}
URLClassLoader urlLoader = new URLClassLoader(new java.net.URL[]{resourceURL});
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle( path ,
java.util.Locale.getDefault(), urlLoader );
As long as you name your resource bundle files correctly (with a .properties extension), then this works:
File file = new File("C:\\temp");
URL[] urls = {file.toURI().toURL()};
ClassLoader loader = new URLClassLoader(urls);
ResourceBundle rb = ResourceBundle.getBundle("myResource", Locale.getDefault(), loader);
where "c:\temp" is the external folder (NOT on the classpath) holding the property files, and "myResource" relates to myResource.properties, myResource_fr_FR.properties, etc.
Credit to http://www.coderanch.com/t/432762/java/java/absolute-path-bundle-file
When you say it's "a valid resource bundle" - is it a property resource bundle? If so, the simplest way of loading it probably:
try (FileInputStream fis = new FileInputStream("c:/temp/mybundle.txt")) {
return new PropertyResourceBundle(fis);
}
1) Change the extension to properties (ex. mybundle.properties.)
2) Put your file into a jar and add it to your classpath.
3) Access the properties using this code:
ResourceBundle rb = ResourceBundle.getBundle("mybundle");
String propertyValue = rb.getString("key");
From the JavaDocs for ResourceBundle.getBundle(String baseName):
baseName - the base name of the
resource bundle, a fully qualified
class name
What this means in plain English is that the resource bundle must be on the classpath and that baseName should be the package containing the bundle plus the bundle name, mybundle in your case.
Leave off the extension and any locale that forms part of the bundle name, the JVM will sort that for you according to default locale - see the docs on java.util.ResourceBundle for more info.
For JSF Application
To get resource bundle prop files from a given file path to use them in a JSF app.
Set the bundle with URLClassLoader for a class that extends
ResourceBundle to load the bundle from the file path.
Specify the class at basename property of loadBundle tag.
<f:loadBundle basename="Message" var="msg" />
For basic implementation of extended RB please see the sample at Sample Customized Resource Bundle
/* Create this class to make it base class for Loading Bundle for JSF apps */
public class Message extends ResourceBundle {
public Messages (){
File file = new File("D:\\properties\\i18n");
ClassLoader loader=null;
try {
URL[] urls = {file.toURI().toURL()};
loader = new URLClassLoader(urls);
ResourceBundle bundle = getBundle("message", FacesContext.getCurrentInstance().getViewRoot().getLocale(), loader);
setParent(bundle);
} catch (MalformedURLException ex) { }
}
.
.
.
}
Otherwise, get the bundle from getBundle method but locale from others source like Locale.getDefault(), the new (RB)class may not require in this case.
If, like me, you actually wanted to load .properties files from your filesystem instead of the classpath, but otherwise keep all the smarts related to lookup, then do the following:
Create a subclass of java.util.ResourceBundle.Control
Override the newBundle() method
In this silly example, I assume you have a folder at C:\temp which contains a flat list of ".properties" files:
public class MyControl extends Control {
#Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
if (!format.equals("java.properties")) {
return null;
}
String bundleName = toBundleName(baseName, locale);
ResourceBundle bundle = null;
// A simple loading approach which ditches the package
// NOTE! This will require all your resource bundles to be uniquely named!
int lastPeriod = bundleName.lastIndexOf('.');
if (lastPeriod != -1) {
bundleName = bundleName.substring(lastPeriod + 1);
}
InputStreamReader reader = null;
FileInputStream fis = null;
try {
File file = new File("C:\\temp\\mybundles", bundleName);
if (file.isFile()) { // Also checks for existance
fis = new FileInputStream(file);
reader = new InputStreamReader(fis, Charset.forName("UTF-8"));
bundle = new PropertyResourceBundle(reader);
}
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(fis);
}
return bundle;
}
}
Note also that this supports UTF-8, which I believe isn't supported by default otherwise.
This worked for me very well. And it doesn't reload the bundle everytime. I tried to take some stats to load and reload the bundle from external file location.
File file = new File("C:\\temp");
URL[] urls = {file.toURI().toURL()};
ClassLoader loader = new URLClassLoader(urls);
ResourceBundle rb = ResourceBundle.getBundle("myResource", Locale.getDefault(), loader);
where "c:\temp" is the external folder (NOT on the classpath) holding the property files, and "myResource" relates to myResource.properties, myResource_fr_FR.properties, etc.
Note: If you have the same bundle name on your classpath then it will be picked up by default using this constructor of URLClassLoader.
Credit to http://www.coderanch.com/t/432762/java/java/absolute-path-bundle-file
Find some of the stats below, all time in ms.
I am not worried about the initial load time as that could be something with my workspace or code that I am trying to figure out but what I am trying to show is the reload took way lesser telling me its coming from memory.
Here some of the stats:
Initial Locale_1 load took 3486
Reload Locale_1 took 24
Reload Locale_1 took 23
Reload Locale_1 took 22
Reload Locale_1 took 15
Initial Locale_2 load took 870
Reload Locale_2 took 22
Reload Locale_2 took 18
Initial Locale_3 load took 2298
Reload Locale_3 took 8
Reload Locale_3 took 4
I would prefer to use the resourceboundle class to load the properties - just to get it done in one line instead of 5 lines code through stream, Properties class and load().
FYI ....
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
try {
/*** Type1 */
Properties props = new Properties();
String fileName = getServletContext().getRealPath("WEB-INF/classes/com/test/my.properties");
// stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
// stream = ClassLoader.getSystemResourceAsStream("WEB-INF/class/com/test/my.properties");
InputStream stream = getServletContext().getResourceAsStream("/WEB-INF/classes/com/test/my.properties");
// props.load(new FileInputStream(fileName));
props.load(stream);
stream.close();
Iterator keyIterator = props.keySet().iterator();
while(keyIterator.hasNext()) {
String key = (String) keyIterator.next();
String value = (String) props.getProperty(key);
System.out.println("key:" + key + " value: " + value);
}
/*** Type2: */
// Just get it done in one line by rb instead of 5 lines to load the properties
// WEB-INF/classes/com/test/my.properties file
// ResourceBundle rb = ResourceBundle.getBundle("com.test.my", Locale.ENGLISH, getClass().getClassLoader());
ResourceBundle rb = ResourceBundle.getBundle("com.ibm.multitool.customerlogs.ui.nl.redirect");
Enumeration<String> keys = rb.getKeys();
while(keys.hasMoreElements()) {
String key = keys.nextElement();
System.out.println(key + " - " + rb.getObject(key));
}
} catch (IOException e) {
e.printStackTrace();
throw new ServletException("Error loading config.", e);
} catch (Exception e) {
e.printStackTrace();
throw new ServletException("Error loading config.", e);
}
}
I think that you want the file's parent to be on the classpath, not the actual file itself.
Try this (may need some tweaking):
String path = "c:/temp/mybundle.txt";
java.io.File fl = new java.io.File(path);
try {
resourceURL = fl.getParentFile().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
URLClassLoader urlLoader = new URLClassLoader(new java.net.URL[]{resourceURL});
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("mybundle.txt",
java.util.Locale.getDefault(), urlLoader );
The file name should have .properties extension and the base directory should be in classpath. Otherwise it can also be in a jar which is in classpath
Relative to the directory in classpath the resource bundle can be specified with / or . separator. "." is preferred.
If you wanted to load message files for different languages, just use the
shared.loader=
of catalina.properties...
for more info, visit http://theswarmintelligence.blogspot.com/2012/08/use-resource-bundle-messages-files-out.html
This works for me:
File f = new File("some.properties");
Properties props = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
props.load(fis);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
fis = null;
} catch (IOException e2) {
e2.printStackTrace();
}
}
}
public class One {
private static One one = null;
Map<String, String> configParameter = Collections.synchronizedMap(new HashMap<String, String>());
private One() {
ResourceBundle rb = ResourceBundle.getBundle("System", Locale.getDefault());
Enumeration en = rb.getKeys();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = rb.getString(key);
configParameter.put(key, value);
}
}
public static One getInstance() {
if (one == null) {
one= new One();
}
return one;
}
public Map<String, String> getParameter() {
return configParameter;
}
public static void main(String[] args) {
String string = One.getInstance().getParameter().get("subin");
System.out.println(string);
}
}
ResourceBundle rb = ResourceBundle.getBundle("service"); //service.properties
System.out.println(rb.getString("server.dns")); //server.dns=http://....