How do I set the classpath that rmiregistry uses? - java

I'm trying to make a Java RMI client/server app. I'm running into problems starting up the server side of my app, as it keeps running into a ClassNotFoundException during the call to the Registry.bind() method when I attempt to start up the server side of the app.
I started with the simple tutorial here: http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/hello/hello-world.html. After following those instructions, it was initially throwing a ClassNotFoundException complaining that it couldn't find "example.hello.Hello". I was able to resolve that by starting the rmiregistry FROM the destDir directory in the tutorial, since rmiregistry, apparently, uses its initial starting directory as part of its classpath.
I started on my other test app after that, and I was fine until I started to use third-party jar files in my server class. Now Registry.bind() throws a ClassNotFoundException if my server class references anything in any jar file since the rmiregistry app doesn't know about those jar files.
As far as I can tell, rmiregistry does not accept any sort of classpath startup arg, so I'm wondering how I can tell it what classpath I want it to acknowledge. According to the tutorial here: http://docs.oracle.com/javase/tutorial/rmi/running.html, "you must make sure that the shell or window in which you will run rmiregistry either has no CLASSPATH environment variable set or has a CLASSPATH environment variable that does not include the path to any classes that you want downloaded to clients of your remote objects." That sounds like the opposite of what I need... or am I reading it incorrectly? Has anyone had any success starting up a RMI client/server that uses third-party jars (commons-io, commons-logging, and rmiio, in my case)?
This is on Windows, by they way.
Update
I found a way around it. See my answer below.

The remarks about unsetting the CLASSPATH only apply if you're using the RMI codebase feature, as the cryptic remark about downloading classes is intended to imply.
If you're not using the codebase feature, just either:
Set the CLASSPATH environment variable as required before starting rmiregistry, as shown elsewhere here, or
Start rmiregistry with -J-Djava.class.path=...
Start the Registry inside your server JVM, with LocateRegistry.createRegistry(). This is in many ways the best solution, as it lives and dies with the JVM, shares its classpath, and incidentally complies with the requirements for the codebase feature as well.
If you do (3), you must store the return value into a static variable to prevent it from being garbage-collected, which causes the registry to be unexported, which can lead to DGC of the remote object, which can lead to it being GC'd, which will lead to the listening thread exiting, which can lead to the whole JVM exiting.

There is no RMI Registry specific java class path. It should use the same classpath as the rest of the Java system. You can set your classpath by specifying it on the command line, or in your OS environment. Though a little dated, this doc should point you in the right direction.

(I had originally posted this answer as an update to my question. Per Zecas's suggestion in one of the comments, I'm moving it to the answer section.)
I was able to get the server part to start up by disobeying the suggestion in the second tutorial referenced in my question above:
"you must make sure that the shell or window in which you will run
rmiregistry either has no CLASSPATH environment variable set or
has a CLASSPATH environment variable that does not include the path to
any classes that you want downloaded to clients of your remote
objects."
I created a CLASSPATH environment variable and added my .class output directory and each of the third-party jar files to that. I thought I had tried that before, but I guess not... Just thought I'd leave my solution in case someone else has the same problem.

An example of how to set classpath for rmiregistry
Win32:
set CLASSPATH=c:\home\ann\src;c:\home\ann\public_html\classes\compute.jar
UNIX:
setenv CLASSPATH /home/ann/src:/home/ann/public_html/classes/compute.jar

Related

Java Textio file addition [duplicate]

This question already exists:
how to add new class(textio.java) in jdk 12.0.1
Closed 3 years ago.
Where to put the textio.java and its classes. I am using jdk 12.0.1. it is the error cmd is showing on comipiling file that uses textio class.
Please tell me the correct directory where to put textio class file in jdk 12.0.1 folder.
There are numerous ways to add third party libraries to your runtime. Without more information, the lowest energy way you're looking for isn't quite clear.
I believe the CLASSPATH environment variable is what you want. If it's not defined, you may define one by whatever process matches your operating system.
CLASSPATH is one way for your machine to tell your java installation which folders jars and other jvm bytecode are located in so that your java runtime can load them when your program starts. This can be anywhere, but depending on your operating system, there are standard locations that are often good to follow.
In linux/unix/OSX, you may run echo $CLASSPATH, and a non-empty result means that it's set. If it doesn't exist, then you may run this command to create it pointing to the folder you choose. export CLASSPATH=/path/to/jars. Just keep in mind that without some extra steps, this will be reset on next reboot.
If you're using an IDE such as eclipse or idea, then there are project-specific solutions that can be done as configuration options within your IDE, which will keep things you don't want globally available on your machine from being loaded up every time.

VLCJ setting custom library location at runtime

I have a Java program that uses vlcj to play videos and that packages the VLC libs in the jar. At runtime, the VLC libs are extracted to the user's home, let's say path A. The normal way to indicate this path to vlcj is through the jna method:
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "A");
This works under Windows and MacOSX but not Linux where it throws a UnsatisfiedLinkError.
After some trial and error, I found that the only to get this to work under linux was by using
export LD_LIBRARY_PATH=A
prior to execution and despite the JNA documentation, none of these worked in JVM settings:
-Djava.library.path=A
-Djna.library.path=A
-Djna.platform.library.path=A
My problem with using LD_LIBRARY_PATH is that it is not something I can set at runtime (can I?) which I need to do. Does anyone know of a way to get around this?
I never found an ideal solution to this myself, but this is what I found during my trials with my own vlcj projects.
If you build VLC yourself on Linux you will see these warnings:
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
None of those things it suggests can you do from within your JVM, at least not without calling native code with privilege escalation.
So, in general what you are left with is: -Djna.library.path=LIBDIR should work; alternatively in code System.setProperty("jna.library.path", "LIBDIR"); should also work.
In fact I just tested that with my own native library that I happen to use in my own vlcj projects and both of those approaches worked just fine.
However, it seems it is not so easy with VLC itself, probably because of the way VLC loads its plugins.
In theory, if you structure your directories correctly, the plugins should get discovered automatically so you only need to point jna.library.path to the directory that contains the libvlc and libvlccore shared objects. In my build of VLC, the directory structure looks like this:
VLCDIR
VLCDIR/libvlc.so
VLCDIR/libvlc.so.5
VLCDIR/libvlc.so.5.4.0
VLCDIR/libvlccore.so
VLCDIR/libvlccore.so.7.0.0
VLCDIR/vlc/plugins
If this still fails then, again in theory, you can set the VLC_PLUGIN_PATH environment variable to point to the directory containing the VLC plugins. The problem is that this must be set for the native process, it will not work if you set it as a system property from inside your Java application.
I can only really suggest you generate a shell-script file that sets up the environment correctly when you install your application, or if you want to do it programmatically inside the JVM you could maybe have a bootstrap application that prepares the native environment and then kicks off a new Java process for your actual application - but it's messy to do things that way.
What I have also seen on Linux is that the library paths seem "baked in" to the ".so" files, and you can't just copy those files anywhere and still expect it to work. That is why you must use e.g. LD_LIBRARY_PATH or libtool or one of the other proposed solutions.
And this does not even touch on what you do with all the other libraries that VLC and its plugins may depend on at run-time - are you going to ship all those too?
My recommendation really is just to have the user install VLC first, or have your installer application install VLC first, by using the OS native package installation commands. Not ideal, but it works.

Program uses outdated (not current) env variable value

I've got a C++ program that internally uses java (via my C++ dll that wrapps the WebLogic jsmc.dll that internally uses jvm.dll).
When I set CLASSPATH before running my program, all JAR libraries are found and the program works properly.
When I do not set the CLASSPATH before running my program, the JARs are not found, which of course is expected.
Now, when I set the CLASSPATH before running my program, but clear this CLASSPATH environment variable inside the program code before loading my dll that uses java, a strange thing happens: all JARs are still found and the program works as if everything was OK. I have verified by several ways that the CLASSPATH is really deleted from the env variables (e.g. by using ProcessExplorer or by printing its value).
QUESTION:
Can you explain this behaviour to me? I'm not wondering why java ignores the CLASSPATH I set, but how is it possible that java sees the old CLASSPATH value, not the current one? I emphasize that it isn't possible for java to store the old CLASSPATH value somehow because java was not loaded at the the time the old value was available.
How can I make the java to respect the changes in the process env variables?
DETAILS:
The problem above is just a simplification I've made to explore my real problem. I'm trying to set the CLASSPATH from within the program and avoid to have it set externally. But the java uses the externally set CLASSPATH, not the one I set inside the program.
I read and set the env variables values using the Windows API (GetEnvironmentVariableA, SetEnvironmentVariableA). I have verified that the program process environment variables really change after setting them this way. I even printed the CLASSPATH value from the dll that uses java, before calling any java method. I checked using the ProcessMonitor that jvm.dll is really loaded after the CLASSPATH is deleted. I also tried to exclude the possibility that the CLASSPATH is read from the parent process. Now I'm pretty sure that at the time jvm.dll is being loaded, the CLASSPATH is already deleted from the process environment.
I have tried both a Visual C++ 2010 testing program and the HP LoadRunner C-compiler (mmdrv.exe) vuser script, with the same result. LoadRunner is the main reason why I need to solve this problem.
The problem was caused by that the C-runtime somehow caches the environment variables. While I was trying to modify the CLASSPATH using the system function SetEnvironmentVariableA(), jmsc.dll read CLASSPATH from the C-runtime cache. The C-runtime tries to synchronize its cache with the real values in the process environment, but evidently not very successfully. It was necessary for me to replace the system call to SetEnvironmentVariableA() with the call to _putenv() from the C-runtime in order to change the CLASSPATH.
But there was another problem. There were various versions of C-runtime used by my code, each having its own environment cache. My VC code was linked against msvcr100.dll, while jmsc.dll (that instantiates the Java VM) uses msvcrt.dll. The solution was to link my code to msvcrt.dll too, so that my code sets CLASSPATH using _putenv() from the same C-runtime that jmsc.dll reads.
Thanks to Harry Johnston for the crucial hint, and Peter Cetinski for valuable information.
You should not rely upon the CLASSPATH environment variable when invoking a new JVM process from C++. The JNI interface provides a mechanism to specify the classpath of the JVM upon startup.
See http://java.sun.com/docs/books/jni/html/invoke.html#28719

Java RMI Netbeans Packages

When using Netbeans I am able to run RMI applications if I don't put the source files in a package, however when I try and split it up into packages.
I start to get class not found exceptions any help would be greatly appreciated.
Post some code. Class not found exceptions usually mean that your classpath isn't set properly. I don't mean a CLASSPATH environment variable, either. NetBeans (and all IDEs) ignore environment variables and ask that you tell them where to find .class files.
Find out what NetBeans thinks your classpath is and make sure it's set properly.
RMI server returns the output with the package name and interface name. So, when the interface moved to another package, the server can't identify that. That is the problem you have.

How to debug a java system.loadlibrary error in linux?

I have a Java program that is calling C code through JNI that I'm attempting to run on Linux. The external code consists of two .so files: one for the JNI bindings (built with swig) and the other with the actual functions. I have the two libraries in the same directory and LD_LIBRARY_PATH is set correctly. ldd reports no problems when running from the command line, but when I set the LD_LIBRARY_PATH to the same value in the "run configurations" dialog in the Eclipse editor and attempt to execute the program, it gets the following error:
java.lang.UnsatisfiedLinkError: [path to libraries]/[JNI binding library].so: [actual code library].so: cannot open shared object file: No such file or directory
This leads me to believe that the JNI wrapper library is loaded successfully, but there is a failure when that library attempts to load the library containing the actual code. Is there any way to debug this further?
I will further note that this problem is happening in the eclipse editor itself and that I haven't attempted to package the code into a jar and run it within a free-standing jvm instance.
I think the issue is with the call to System.loadLibrary(String) and using LD_LIBRARY_PATH. Using loadLibrary("foo") will look in your java.library.path for something named libfoo.so. If nothing named libfoo.so is found you will get this error.
Now if you just set up the LD_LIBRARY_PATH, the native symbols you want will automatically be picked up by the linker, so you don't need to set up -Djava.library.path.
In my experience with swig in the gdal project, this error is actually harmless and since the LD_LIBRARY_PATH is set up, this will work fine.
I would recommend using -Djava.library.path and calling loadLibrary explitly, the reason being that if you ever decide to deploy your app with webstart, you will explicitly need to call loadLibrary to get your native libs picked up.
When I use eclipse I follow the instructions that Daff gave where you edit the native library under the jar in the Libraries tab in the Build Path. Just to mention again, this just sets java.library.path under the covers.
It may be that you just have to find the right place on the run config dialog to put the -Djava.library.path=... option. Offhand I think you want -D defines in the "vm arguments" on the arguments tab, whereas if you want to define LD_LIBRARY_PATH that goes on the environment tab. Eclipse will merrily let you put things in places where they won't mean what you think they mean. Anyway, I've used libraries this way before and if I get a chance I will look up what I did and edit my answer here.
Another thing to try is to play with LD_DEBUG. You can set the environment variable LD_DEBUG to various things (try ALL), and then the linux loader will divulge all sorts of useful information about what an application is trying to load, where it's looking for things, etc. Of course, this pre-supposes you launch eclipse from a command line, so you can both set the env vars and see the loader diagnostics; but as far as the system is concerned, when you run your app from inside eclipse, your app is just something eclipse is doing, so any library loading behavior can be seen in this way.
You could try -Djava.library.path=actual.so in command line parameters perhaps?
On windows, I had similar problems with a 3rd party library, which used a JNI wrapper DLL for its DLLs. My project had the DLL in the lib directory so I added lib to the PATH (e.g. PATH=%PATH%;./lib environment variable and everything started working.
As far as I know the Eclipse doesn't use the LD_LIBRARY_PATH.
The easiest way to set up the right native library path is to go to
Project properties -> Java Build Path -> Libraries
Then expand either the JRE System Library entry or (if available) the
Jar File that uses you native Library,
choose "Native Library Location" then click "Edit..." and choose the folder your libraries are in. Actually it does set the -Djava.library.path variable so you have to include this in your command line if you start your program from outside eclipse.
Are there any other libraries that your two libraries depend on? If so, you need to make sure they are also accessible to the JVM.
Be aware, manually setting "-Djava.library.path" seems to erase the default library path.
So with the following code:
public class LibTest {
public static void main(String[] args) {
String property = System.getProperty("java.library.path");
StringTokenizer parser = new StringTokenizer(property, ":");
while (parser.hasMoreTokens()) {
System.err.println(parser.nextToken());
}
}
}
Launched from eclipse with Java 1.6.0_14 outputs:
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/opt/java/jre/../lib/i386
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/usr/lib/xulrunner-devel-1.9.0.11
/usr/lib/xulrunner-devel-1.9.0.11
/usr/java/packages/lib/i386
/lib
/usr/lib
But when I set the JVM arg "-Djava.library.path=/tmp/" I only get:
/tmp/
If you are manually setting java.library.path this may explain why ldd works from the command line but your .so does not from eclipse/java.
You can try not setting java.library.path and use System.load with the absolute path to your library instead of calling System.loadLibrary. This may allow the JVM to find your .so and still use the default path when searching for its dependencies.
Of course, if this is no use then you can also try turning on jni debug output with "-verbose:jni" on the command line. This may give you some clues to the problem.
Yes the LD_LIBRARY_PATH worked for me
Adding this answer may be it can be useful In AIX Machines we need to setup LIBPATH environment variable instead of LD_LIBRARY_PATH.

Categories

Resources