I'm trying to figure out how a system works. When I do a 'ps -A' I see several java processes. Is there a way to run a command that will examine a java instance and let me know what all jars or classes are loaded from that instance (preferably without stopping the instance)?
You can use jconsole or visualvm to get the details of the running JVM. These require xwindows if you are using linux.
Further, jps -v will let you know what was the command line argument used to start the JVM. From there you should be able to see what jars where used for the classpath.
You will need to use some Java specific tool such as VisualVM to do what you are inquiring about.
ps -Af
Will show you the exact command used to launch the process. It can not, however, tell you exactly which libraries that the invoked JAR file has loaded (although you do presumably get the classpath so you can make inferences).
For more detail you'll need a tool that interrogates the JVM.
In case of Java application server running web or enterprise (EAR) application, you cannot deduce all used jars from command line. But you can use e.g. lsof command to list all files that given java process is using. And filter jars from them.
Related
I was reading some documentation for db2jcc4.jar when something caught my attention in the following (emphasis added):
The following command will retrieve the JCC driver version if executed from the command line:
java com.ibm.db2.jcc.DB2Jcc -version
Or for drivers that are not yet installed:
java -cp ./db2jcc.jar com.ibm.db2.jcc.DB2Jcc -version
All I have is the db2jcc4.jar file - it didn't come with an installer or anything. I can run the second command and it works fine, but the first gives me this stack trace:
Exception in thread "main" java.lang.NoClassDefFoundError: com.ibm.db2.jcc.DB2Jcc
Caused by: java.lang.ClassNotFoundException: com.ibm.db2.jcc.DB2Jcc
at java.net.URLClassLoader.findClass(URLClassLoader.java:434)
at java.lang.ClassLoader.loadClassHelper(ClassLoader.java:665)
at java.lang.ClassLoader.loadClass(ClassLoader.java:644)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:358)
at java.lang.ClassLoader.loadClass(ClassLoader.java:627)
Could not find the main class: com.ibm.db2.jcc.DB2Jcc. Program will exit.
This tells me that the jar is not yet installed. In all the time I've worked with Java, I've never heard of installing a jar. How can I make it so that the first command works instead of having this issue and printing a stack trace? How can I install a jar?
It looks to me like the second command includes a flag, -cp, which modifies the classpath. I'm guessing that means that all I need to do is move my jar file into a specific directory. I tried putting it in /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.33.x86_64/jre/lib but that didn't make it so the second command would work. I'm stumped and would appreciate any suggestions for where exactly I need to move this jar for it to be considered installed.
There is no such thing as "installing" a jar. To be used by a Java application, jars have to be accessible in the classpath. Take a look at this link:
http://docs.oracle.com/javase/tutorial/essential/environment/paths.html
By installing the java jar they meant that the jar is available to your program (physically present and found in your class path). If the Path to the jar was not setup then you have to options:
+ copy the jar file to your existing path
+ include the jar file in the command line
java -cp <path_to>/db2jcc.jar com.ibm.db2.jcc.DB2Jcc -version
It looks to me like the second command includes a flag, -cp, which modifies the classpath. I'm guessing that means that all I need to do is move my jar file into a specific directory.
I would say that you need to explicitly include the jar file itself on the classpath. Personally, I generally do not attempt to "install" a jar as you describe, but rather create some sort of script or executable jar file that will facilitate the establishment of the correct classpath.
EDIT: In the context of deploying code to an application server, then "installing" the jar would make sense--typically there's a shared lib folder available on an application server where you can simply drop the jar and the code will become available to all the applications running on the server--this can become a bit of a management headache, however and I often will prefer to have a completely self-contained deployment over sharing jar files between applications--YMMV, however.
You commented thus:
Your link has this comment - (Classes that are part of the JRE, JDK platform, and extensions should be defined through other means, such as the bootstrap class path or the extensions directory.) - How would I go about adding the jar through that?
That is a bad idea, for (at least) the following reasons:
Putting stuff into the extensions directory is going to potentially affect every Java application that you execute. Not just the application that you are trying to "install". In some cases, this may to lead to unexpected breakages due to conflicting versions, etcetera.
When you update the Java installation, the standard installer, RPM or whatever is going to create a new installation tree. But it won't copy anything from the existing installation. So a Java update is likely to break any application that depends on stuff in "extensions".
If you try to solve the above problems by "embedding" a Java installation, you risk losing track of where your Java installations are. This makes applying Java security patches problematic. And of course, embedded JREs take up a lot of disc space ... at ~100Mb a time.
I suspect that "Installing a JAR" is a poorly chosen terminology that likely means placing the jar on the JVM classpath" - i.e. in order to make it available to an application. The recommended ways of doing so vary depending on the Java platform (whether it is a server platform or a client side platform).
For example, on a Java EE server, you could package the jar file within the application, or define it as a shared library, and attach it to the server's classloader or the application's classloader to make it available to that application. Third party applications, such as various IBM products, will come with their own instructions as to how to 'install' a db2jcc4 driver.
I have a project with a million jars (well, a lot). They came to me by maven, and I only use a small set of functionality. For cleanness sake, I was wondering with jars I could do without.
My first thought was to run the program with a code-coverage tool, and then find the classes that are touched.
Has anyone done this before? Or are there smarter tricks to achieve the same?
You can run the project using the -verbose:class VM option. This will print for all loaded classes where they are loaded from. Using some smart parsing app/grep/regexp will allow you to filter the jar names into a set of unique entries and tell you which are used.
I think this would be easier because it will automatically tell you if a class is used and if so in which jar.
Of course the problem with this and code coverage is that it will be possible that you delete a jar that is only used in some exceptional case, but your compiler will complain if you deleted one or two too many, leaving you with the (mostly not too complicated) task of finding which jar the class is in.
Possible suggestion when using linux:
java -verbose:class <your startup command here> | grep "\[Loaded" | grep -o "from .*\]" | cut -c 6- | sort | uniq
If you aren't using linux, then save to a file, get a linux machine and run on linux (or use something to run bash commands on windows)
Consider using a tool that already exists, like Dependency Finder or JDepend.
As with all static analysis tools, the use of reflection or DI frameworks can throw this off; I've resorted to custom tools that use this and other inputs to figure things out, although it's still static.
For full runtime usage info you can use Thirler's solution, although whether or not it's complete may depend on which code paths are followed.
You can use Maven Dependency Plugin for analysing your dependency tree. It will also suggest you the dependecies which are downloaded/added to your project because they are dependent to any other jars.
Do run a mvn dependency:tree and see if you are using few unrequired jars.
I'm new to Java and aren't sure where to place the Java Dependencies which are required to run crawler4j. Do I put them in the same folder, or do I put them where Java is located on my machine, or what? Please help me.
Putting the dependent JARs in the same folder as your application JAR / bytecode files is a reasonable approach. As others mention, you need to ensure that the actual folder containing the JARs is on the classpath when the JVM is launched to run the application. The -cp argument is the recommended way to do this, and it is common practice to create a little shell script / batch file to launch the app with the appropriate JVM parameters.
Putting them into the Java installation is not a good idea for a couple of reasons.
It might have unforeseen side-effects on other applications run using that installation. This includes applications run by other users.
It will make upgrading your Java installation to the next patch level more difficult.
You need to put them on the CLASSPATH. If you're running your/the application from the command line you can specify your classpath using the -cp argument for java
You put them in your classpath. The classpath can be specified with the -cp argument when you run the java program.
java -cp depend1.jar;depend2.jar;etc... Class2Run
In this post, using -jar option ignores all the -cp and $CLASSPATH.
In this post, using -cp option also ignores the $CLASSPATH.
Is there any good reason for them?
It's to avoid clashes in the classpath whenever you distribute your application to run on different environments. In most of the cases you'd like your application to be independent from the platform specific configuration. If the $CLASSPATH contains references to classes with (either unawarely or awarely) the same package and classname, it would get precedence in classloading before the classes which you included in your application's classpath. This may lead to unexpected application behaviour or potential security holes.
jar is supposed to be a standalone program with self-contained libraries. If you want to include other classpaths, you may need to do something like
java -cp jar1:jar2:$CLASSPATH some.class.with.main
BalusC answered the other question.
In both cases, the reason for the restrictions it to avoid1 accidental or wanton / ill-considered overriding of the effective classpath.
If you really want an application to be launchable using "-jar" and to also pick up classes via the user's $CLASSPATH environment variable, you should be able to do this by having the application create its own classloader, or using a custom launcher. (You could even make your application look for a "-cp" argument after the "-jar" argument.)
Likewise, you could modify the behavior in the first case.
However, I think it would be bad idea to do that. The main point of executable JAR files is to isolate the application from the vagaries of the environment in which the user happens to launch the application.
If you want to do hacky things with your application classpath, a simpler approach is to create a wrapper script that assembles the effective classpath however you want to, then launches the application with a "-cp" option. You could even pull the "Class-path" out of various JAR files' manifests and incorporate that ...
1 - Clearly, it doesn't stop someone changing the classpath entirely. But stopping that would be a bad idea, and probably isn't technically possible if we assume that the user can get local admin privilege, etcetera.
There are several reasons why the environment variable CLASSPATH is (and should be) ignored:
A global CLASSPATH for all projects makes no sense at all. It can't be the same for all projects, and you don't want one massive one that's reapplied to all projects.
You can't count on it being set, so depending on it is a bad idea. Code that works on one machine suddenly doesn't work when it's moved. How do you communicate the necessary environment settings? Better not to use them.
Java EE app servers all have their own conventions (e.g., all JARs in WEB-INF/lib and all .class files in WEB-INF/classes are automatically in the CLASSPATH for a web app).
Java EE app servers all ignore global CLASSPATH. They don't count on it.
Java IDEs all have their own conventions for setting a project CLASSPATH. Learn them.
All Java IDEs ignore global CLASSPATH. They don't count on it.
I don't have a global CLASSPATH on any machine that I use. It's not necessary. I'd recommend learning how CLASSPATH works and stop relying on environment variables.
Correct or not, I long for a -jar-cp flag. That would be obvious and direct enough to not be a security risk or break current behavior.
With APIs like java.util.ServiceLoader, it is entirely reasonable to wish to add/remove services from the classpath. You shouldn't have to loose that functionality because you used Main-Class in your manifest.
There is no sane enough reason to explain this apparent "absurdity", in my words. From one of the bugs in the Sun bug database, one can only infer that a developer did not account for the fact that the classpath could be specified via the CLASSPATH environment variable, or via the -cp option. By the time the issue was found, the release was more or less public, with the effect that the fix would cause backward compatibility issues.
I have a Java application which is using a certain Java Runtime Environment. The application uses it's own launcher to startup the java virtual machine. No use of the java.exe, javaw.exe, javaws.exe binaries is being made -- as the application seems to have it's own launcher which is a different executable. This custom launcher is using the rest of the JRE files, such as bin/client/jvm.dll and rt.jar package etc.
Now, the problem is that I want to set a boot class path for this custom launcher. The custom launcher does not support the -Xbootclasspath command line parameter, like the default java.exe does.
Is there any way for me to set the boot class path now for this java runtime environment?
Thanks in advance.
Some things to keep in mind:
I do not have the source of this application
This is meant for self and personal debugging use only, not for distribution
Update: not getting a lot of replies, so let me rephrase my question. Books like http://my.safaribooksonline.com/0672326388/ch15lev1sec5 tell you to set the -Xbootclasspath, however how does one set such path when the application has it's own JRE launcher directly loading the java libraries without usage of the default java.exe etc. executables?
If I understand you correctly, the custom launcher is some native code app that starts the JVM to run the Java app; i.e. java.exe etc, ... but different.
A couple of things that might work are:
adding your JAR to the Java installation's "endorsed" directory, or
inserting your stuff inside the installation's "rt.jar" file, or some other standard JAR.
But in both cases, you could be changing the behavior of the Java installation for every application (and person) that uses it.