I need to get names of all java packages loaded by the JVM. This is to display a package browser like the ones found in IDEs. I can get the package list of the current classloader and its ancestors by accessing protected "packages" field of the ClassLoader class. But i'm unable to get the packages loaded by other webapps as they have their own class loaders. I'm testing this on Weblogic server
You need to walk the tree of classloaders up by using getParent()
, find all classes which extend ClassLoader, find all current instances (the debug API should help here). But that probably won't work for Web Servers because of the security policy (web apps are not allowed to peek at each other).
For Tomcat, there is an option to log all classes as they are loaded. This slows down a server pretty much but it might be an option on the development server.
That said, I'm pretty curious why you would need that. The most simple solution would be to list all JAR files, which your app brings along, with jar tvf
and strip the last part of the path (the class file).
The expected behavior of the Weblogic security model is that you would not have access to the other web applications' class loaders. This is not really something that you will be able to get around - see this article for more information.
The only way I can think of doing this would be to modify each webapp so that you can send each a request for their loaded class information. You could then create a new webapp that combines the responses from the existing webapps for display.
If you don't need this information in some nice UI then the Sun JVM has number of -XX vm options that will show you what's going on with regards to class loading.
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
I'm not that familiar with JRockit but I'd be surprised if it didn't have similar options.
Ok I managed to get this working on Weblogic. Again my aim was to get java package names in all applications deployed on a given WebLogic server. Why? I had my reasons :)
First you have to get hold of the ear, war or jar file locations of all deployed apps. To do this we get the AppDeployment MBeans from WebLogic and iterate as shown below.
Set<ObjectName> set = utils.getConfigMBeansByType("AppDeployment");
for (ObjectName objectName : set) {
String name = objectName.getKeyProperty("Name");
if (!appCache.contains(name)) {
//System.out.println("Config bean: " + objectName);
Object path = utils.getPropertyValue(objectName,
"AbsoluteSourcePath");
//System.out.println("Path: " + path);
if(path != null){
PackageFinder finder = new PackageFinder();
packages.addAll(finder.findPackages(path.toString()));
}
appCache.add(name);
}
}
In the above code we get the path to the war, ear, jar or the exploded folder and passes it to the PackageFinder class's findPakages method which does all the work.
public Set<String> findPackages(String path){
File file = new File(path);
if(file.exists() && file.isFile()){
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
if(path.toLowerCase().endsWith(".war")){
processWar(in);
}else if(path.toLowerCase().endsWith(".ear")){
processEar(in);
}/*
Rest of the method body removed, I guess you get the idea
*/
return packageNames;
}
public void processJar(InputStream in){
ZipInputStream zin = null;
try {
zin = new ZipInputStream(in);
ZipEntry entry;
while((entry = zin.getNextEntry()) != null){
if(entry.getName().endsWith(".class")){
addPackage(entry.getName());
}
}
} catch (Exception e) {
}
}