I am working on a J2SE application (think kiosk-style app) that makes heavy use of resource bundles and i18n. This includes not just translations but also formatting and other i18n concerns. We have custom logic in place to homogenize the resource loading, but it is fairly straightforward. The issue I have is the MissingResourceException. Even if I bypass the custom logic in place in the application and call directly into the ResourceBundle class to load this specific bundle, Java is not able to load it for a specific locale. Here is the root exception with stack trace:
Caused by: java.util.MissingResourceException: Can't find bundle for base name version1/FormatResource, locale en_GB
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:836)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:726)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:576)
The resource bundle is in a directory "version1" placed in a class folder in Eclipse which is at the top of my class path. This folder contains other resource bundles which are loaded fine using the same resource bundle loading logic, as well as numerous XML configs which also load fine when loaded using the system class loader. The relevant files for the resource bundle are:
FormatResource_cs_CZ.properties
FormatResource_en_GB.properties
FormatResource_fr_BE.properties
FormatResource_fr_FR.properties
FormatResource_hu_HU.properties
FormatResource_nl_BE.properties
FormatResource_nl_NL.properties
FormatResource_pl_PL.properties
FormatResource_sk_SK.properties
When my application starts up in the Polish locale, everything is fine. If I log in as a user with the Polish locale, everything is fine. If I log in as a British user, the application attempts to load all the en_GB bundles (translations, formatters, etc) and fails on this bundle. It cannot find FormatResource_en_GB.properties, which is clearly in the class path: the above file list is a copy and paste from the command line.
One final issue that I find interesting is that if I define FormatResource_en_US.properties in the version1 directory, then even the FormatResource_pl_PL.properties file fails to load and the application will not even start.
Anyone have any ideas?
I would try to test for file & operating system issues like permissions.
Rename your FormatResource_en_GB.properties so it's out of the way and copy one of the working FormatResource files in its place.
I find it interesting that you mention when you put the US at the top of the list that it loads that one and not any other (similar for when Polish was at the top). Are you switching the locale when you look up the next resource bundle? or is it holding onto the default set by when the program first fired up?
Another thought is with class loaders....whenever I have encountered properties files not being located properly (even though they are where I expect them), I've ended up having to look at how the classloader is loading things. Usually it has been different from what I suspected (like a duplicate file someplace else, or multiple classloaders conflicting with each other).
Just two thoughts to try.
Related
I am currently working on an API for a server software so users can extend my software by programming plugins for it instead of modifying the software themselves, and allow other users without programming knowledge to easily change the software by adding these plugins. So far, everything is working fine. But, I am running into a problem with configuration.
You see, each plugin has a plugin.yml file stored with these 4 attributes:
Main: The main class is stored here
Name: This is where the plugin name is stored
Version: This is where the plugin version is stored
Author: This is where the plugin author is stored
Now, in order for the plugin to print something to the console, they use a function called: this.getServer().getLogger().info("MESSAGE); (They extend another class for plugins, thats why they use "this" instead of another class to log)
But, I do not have any idea on how to get which plugin is which when they are calling the function. I have a ArrayList of PluginSessions which event handlers use to cycle through to run Event Functions.
My solution is to get the jar from which a class is being called so I can then get the plugin.yml from there. But, I have NO idea on how to get that, I have tried using Class.forName(); and some other code. But because the class is non-existent within the jar/project running the code, It will throw a ClassNotFoundException.
Does anyone here know how to get the jar from which a class is coming from without using Class.forName()? Thanks! -Trent
Take a look at Class.getResource.
If you call MyClass.getResource("plugin.yml") (or "/plugin.yml" with leading slash, I forget) you get back a file URL pointing to the plugin.yml file in the same jar as MyClass. (Or null if the path is wrong or the jar doesn't contain a "plugin.yml" file.) You can then open an InputStream to that resource. In a plugin framework you may want to use myPluginInstance.getClass().getResource.
Assuming jar for 'PluginSessions' is already added in you classpath by eclipse then you can try the following trick -
Select/highlight PluginSessions by double clicking on it
Now press CTRL+SHIFT+T
A dialog named Open Type is appeared. Here you found from where the PluginSessions class is coming from. If you have more than one jar containing PluginSessions class than you have a list of them.
To benefited from this CTRL+SHIFT+T trick you need to add all of your jar need by the project to be added in your classpath.
I have following conf files in my play2.1.0 application
application.conf
override.dev.conf
override.qa.conf
override.prod.conf
And there is a application.mode property in the application.conf file which will have either one of dev/qa/prod values.
application.conf also has a line to include env/mode specific conf files as override. This is what is not working with substitution.
Reason:
To have the override properties in the env/mode specific conf files.
Referred:
http://www.playframework.com/documentation/2.0/Configuration
If an unquoted include at the start of a key is followed by anything other than a single quoted string, it is invalid and an error should be generated.
No substitutions are allowed, and the argument may not be an unquoted string or any other kind of value.
Tried:
Able to get the substitution done for another property but not for include like this
my.prop="override."${?application.mode}".conf"
The above outputs to override.dev.conf if application.mode=dev
If I have something like below its not working and i suppose its what is expected as per the documentation reference.
include "override."${?application.mode}".conf"
Expected the above to include/override props in a file named override.dev.conf
Question:
Should this be a future enhancement or this is what is expected out of it?
What are the other ways to implement what I wanted?
Any help would be really appreciated.
I prefer to override the GlobalSettings.onLoadConfig as described in PlayFramework 2 load different config according to current mode. It is done in Scala but it should be possible to do in Java as well.
It lets you overload configurations in a very nice way without the need to start the application with command line arguments, you still start the app with play run, play start, etc.
You should be able to use this method if you change your override.qa.conf to override.test.conf since qa is not a known mode in Play.
All shared settings in the application.conf and then override in the other ones.
We wanted to do something similar and the only way we got it to work was to reverse it.
In each environment we have a main-config.conf that has all of the configuration specific for that environment. Basically, what you are calling your override.[env].conf. The first line in each of those files is includes "application.conf" to merge in the default configuration for the application. So, application.conf has the general project configuration and the other files have the stuff specific to the environment.
To start your app you just tell it to use the environment-specific config file.
play -Dconfig.file=/path/to/main-config.conf start
The application will load main-config.conf which, in turn, includes the default application.conf from the project.
We actually also modify the build shell script (in the /framework directory, I believe) so it always specifies that config file parameter. That way we don't have to type that in when we're developing.
I am helping to code a stop-motion program that is to be cross platform, and on windows it works great. For those who do not know, stop motion is just a fancy term for animation. This program allows users to plug in Nikons, Canons, and Webcams into the computer, and have the program display a live view of the scene, and then have the ability to manually control the camera from there. Included is a framework file from canon for the camera, with a path defined as shown
import com.sun.jna.Native;
initialization and such
public static EdSdkLibrary EDSDK = (EdSdkLibrary) Native.loadLibrary("Macintosh/EDSDK.framework/EDSDK",EdSdkLibrary.class, options);
The error is thrown at the "public static int..." saying that the image is not found. I have tried numerous times redefining the path, moving the framework, and using various other frameworks identical to the one I'm using. Remember, this works flawlessly on Windows, but on Mac there is a problem.
Are frameworks different on macs, or are they to be defined differently? I have looked and found no other solutions.
EDIT: Okay, I defined the path and it now has this symbol > with no text next to it. WHat do I do now?
EDIT: It is saying that this % is not a command. Without it, it still fails to work.
JNA will successively attempt to load frameworks from ~/Library/Frameworks, /Library/Frameworks, and /System/Library/Frameworks, based on the core framework name (EDSDK in this case).
If the loadLibrary call succeeds, then the library was found. If the library was not found, you'll get an UnsatisfiedLinkError.
Frameworks are basically bundles of a shared library with other resources; ESDK.framework/ESDK is the actual shared library (for frameworks, OSX omits the "dyld" suffix normally found on a shared library on OSX).
EDIT
Here's how to make a symlink so that the paths look more like what JNA is expecting. From a terminal (run Terminal.app):
% ln -s /your/complete/path/to/Macintosh/EDSDK.framework ~/Library/Frameworks/EDSDK.framework
When this is done successfully, you should see the following when listing (ls) the symlink:
% ls -l ~/Library/Frameworks/EDSDK.framework
lrwxrwxr-x 1 YOU YOU 50 Mar 31 01:13 /Users/YOU/Library/Frameworks/EDSDK.framework -> /your/complete/path/to/Macintosh/EDSDK/Framework/EDSDK.framework
You should see the symlink path (where JNA will look) on the left, with the path to the real file on the right. If not, delete the symlink file and try again. Note that you may need to create the directory ~/Library/Frameworks first; it may not yet exist.
Finally, make sure that the library you're trying to load matches the VM you're trying to load with; 64-bit with 64-bit, 32-bit with 32-bit. Canon does not provide a universal binary of their library, so you'll need to point to one or the other or merge the two using lipo.
Not really an answer, but more information on the same problem, which I'm experiencing myself.
I can add that JNA will find my frameworks if they're in one of the standard public locations an executable looks for its frameworks, i.e.
~/Library/Frameworks - (public frameworks for the use of the current user)
/Library/Frameworks - (public frameworks for the use of any user)
/System/Library/Frameworks - (public system frameworks)
However, If I want my custom framework to be private - i.e. - not discoverable to other processes than my java vm -- then for some reason JNA doesn't do it.
I know MacOS dynamic loader, when trying to locate a library/framework for any normal (native) MacOS process, does NOT start searching the above locations, but first within several standard "private" locations: (also known as rpath search-path)
in the "Frameworks" directory at the same location as the binary from which the process was loaded: e.g. path/to/my/binary/Frameworks/mySDK.framework
in the "Frameworks" directory at the place where dynamic loader loaded the process (in Application bundles, that would be the myApp.app/Contents/Frameworks/mySDK.framework folder.
So, you can usually create a 'Frameworks' directory of your own right next to your binary, and place your framework in it.
However - JNA misses that. I tried to create a "Frameworks" directory within the "Zulu" - in zulu-11.jre/Contents/Home/bin right next to the 'java' binary, and in other places - but JNA won't find in any of them.
I wonder why, and if there is any documentation for that.
The trick of installing a symlink to my custom framework in /Library/Frameworks may serve you, but I cannot allow other processes to find or load my framework.
I am working with development of an application which, among other pieces of code, contains a number of servlets. The development environment I use is Eclipse (3.2.1, which is rather old) in which I run a Tomcat server (5.5.23, rather old as well) using the Eclipse Tomcat Wrapper plug-in for the task. All this runs on a RedHat 5.2 Linux system.
The Java runtime I use is JDK 1.6.0(21), which I upgraded to (from a previous JDK 1.5 version) quite recently and as far as I can recall, the software combination above (together with the application I'm working with) did actually work: I could start the Tomcat server, it got up without errors or complaints and the application's servlets were available on port 8080.
However, something has changed somewhere (could be in the application jarfiles themselves, I'm suspicious of essentially everything on the host to be the root cause of this). Now, when I try to start up the Tomcat server, I get the error sun.misc.InvalidJarIndexException in the console output. This happens for the following classes and methods:
org.apache.commons.modeler.Registry registerComponent (happens 3 times)
org.apache.catalina.core.StandardServer initialize (happens once)
org.apache.catalina.connector.Connector start (happens twice)
I did find this stack overflow question regarding how to find the JAR of a Java Class useful and I did run find /usr -name \*name-of-suspected-jar\*.jar a few times to track down a number of suggested offending JARS. I also tried to check the runtime configuration of the Tomcat server in Eclipse, but could really not match the JAR files on the system with the CLASSPATH of neither the Tomcat runtime setup (or with the CLASSPATH used in the environment when starting Eclipse). That effort probably requires some more rigor on my part but before doing that (and that is why I right now don't post all the gory details regarding CLASSPATHs here), I did a read up on exactly what InvalidJarIndexException really is about.
So, JAR files may contain an optional INDEX.LIST file which contains information about what classes (and methods?) to find in the JAR file. The idea is to short-circuit the search throughout all JARS in the CLASSPATH which is useful in a number of circumstances. Problem is when the INDEX.LIST file happens to be corrupt (or, is believed to be corrupt), that causes the loading of the class to be completely given up (the class loader does not fall back to searching all JARs in the CLASSPATH) and the error InvalidJarIndexException to be thrown. To make things more messy, the order in which JARs are searched might affect how the class loader treats the INDEX.LIST file: the INDEX.LIST file of one JAR might refer to other JARS and if those referred to JARS are not in sync with the first JAR's INDEX.LIST file, the class loader fails with this InvalidJarIndexException error.
So (according to this StackOverflow question), it seems like this error can be thrown not only because a JAR file has a corrupt INDEX.LIST, it seems it can even be thrown on a JAR even if the JAR has a valid INDEX.LIST or legitimately is lacking a INDEX.LIST simply because a previously searched JAR has confused the class loader. (To put in another way, as things are, this exception might be thrown even for "innocent" non-corrupted JAR files due to offenders elsewhere on the system).
So, after writing a mere novel, here comes my main set of questions:
What is the best way to track down the precise .jar file for which each InvalidJarIndexException is thrown?
What is the best way check if a randomly picked .jar file has an INDEX.LIST file and if so, if said file is valid (that is, non-corrupt)? What tools exist for this task?
Is there an efficient way to automatically deduce the search order of .jar files? I can try to follow the CLASSPATH manually but to be honest, that is error prone and tedious.
Is there an efficient way to figure out what .jar file there is in a search order which might confuse the class loader to accuse innocent, non-corrupt .jar files later in the search to have incorrect INDEX.LIST files?
Disclaimer: I know I run old versions software (even if I have the latest updates of my Redhat 5.2 installed though) and I know a knee-jerk reaction for many people is to suggest that I don't put any effort whatsoever in debugging this but instead upgrade to a more recent version of Tomcat, Eclipse and Linux (Java is recent though). The reason I would prefer not to is that after looking into things, I've found it rather messy to do an upgrade or to try to install a separate modern Tomcat or Eclipse next to the RHEL5.2 provided Tomcat/Eclipse I use today. Also, I consider this kind of troubleshooting an opportunity to learn some useful nitty gritty details about Java and it's associated tools and features. Figuring out how the class loading works and what causes it to throw this InvalidJarIndexException on my system would be very educating!
(But if this troubleshooting fails, I'll seriously consider to use a modern Linux, Eclipse and Tomcat... I promise)
Take the following steps to diagnose the problem:
Add an exception breakpoint in Eclipse (it's the J with an
exclamation mark icon), and set it to halt for caught and uncaught
exceptions, of type InvalidJarIndexException.
Start debugging your program.
Eclipse will halt at your exception breakpoint, when the InvalidJarIndexException is thrown. Even without the source for URLClassPath, you will still be able to inspect the variables on the stack leading to the exception, including the name of the class that URLClassPath is attempting to locate. Knowing the name of the class should significantly narrow the list of JAR's you need to examine.
Perhaps you've locally added a new class to a package and the contents of that package are described by the index file in a stale JAR on your classpath?
Try Tattletale which is a good reporting tool for jars. What I have done in this case was to eliminate INDEX.LIST from jars one by one until I did not get InvalidJarIndexException any more
I have a folder with a lot of .class files. This classes are updated from 'app 1'. And there is 'app 2' that loads those classes dinamically.
And the problem is....
'app 2' uses a class file, 'app 1' update that file, then 'app 2' needs again the class but it seemes to keep and to use a copy of the older class.
so, I checked the folder and the class was updated successfully, I tried to reload 'app 2' but it keeps using the older class.
Only if I restart tomcat 'app 2' reads the new class.
Why is that?
I'm allowed to reload 'app 2' but, in production enviroment, I cant restart tomcat.
Its very important in my job, I appreciate any idea.....
I'm using a clean installation of tomcat6 and I load the class files with:
Class.forName(<classname>).newInstance()
thx a lot
The problem is that the runtime has already loaded the old classfile into the classloader being used by the code that wants to use the modified class. You'd have to find a way to get the classloader to refresh its class contents from disk in order to achieve what you want. This is why Class.forName() isn't working : it's accessing the already loaded (and cached) version of the class. Alex R is right that you should try to restructure your code to separate your classes for these two projects. But, if you're dead set on trying to reload that class and keep things they way they are, you can try experimenting with Classloader.defineClass() and loading the new version of the class from its .class File into a byte[], then passing that byte[] to Classloader.defineClass(). You'll most likely want to use the context classloader associated with your application by Tomcat (rather than the top level Tomcat classloader). There's documentation distinguishing between the two in the Tomcat project documentation.
Default behaviour is that classes are cached by the ClassLoader that loaded them. If you do: Class.forName('MyClass') two times in a row, you will only load the class the first time.
To reload a class, you need not only to release any reference you already have to any instance of this class, but also any reference you have to the ClassLoader that loaded it. Only then can you be sure the whole class can be garbage collected (or you will end up with memory leaks - a perennial problem in reloading webapps).
You may be able to extends ClassLoader and alter the caching behaviour.
You are right!
This is a great explanation with an example about Alex´s idea
I think that you should try to separate classes for these 2 applications. Try first to create 2 identical directories. One for app1, second for app2. If this solves your problem pack your classes into jar and keep just 2 duplicate jar files. I think that the problem is not in java but in filesystem. I believe that you are using windows. If so probably try to do what you are doing now in linux (unless it is irrelevant for your company).