Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Location of currently running class or JAR file

I have a Lotus Notes database which is performing some interaction with a remote web service. I've written a custom Java class to perform the interaction.

The class methods can be executed from one of three locations depending on the user's setup:

  1. Within a Java script library called via a Lotus Notes Java agent
  2. Within a JAR file located in the user's "jvm/lib/ext" directory
  3. Within a JAR file located in a custom directory within the user's "jvm/lib" directory (for example, "jvm/lib/custom_dir"). The Lotus Notes JVM is aware of the custom directory via usage of the "JavaUserClassesExt" local notes.ini variable.

Within my class I would simply like to be able to return the location the current class is executing from. So if it's executing from either option 2 or option 3, then return the JAR file path. If it's executing from option 1 then return something else which I can handle.

I've tried the following.

getProtectionDomain() method

getClass().getProtectionDomain().getCodeSource().getLocation()

Which results in:

java.security.AccessControlException: Access denied (java.lang.RuntimePermission getProtectionDomain)

There is no option to change any security settings on any clients running this.

Class.getResource method

String myName = "/" + getClass().getName().replace('.', '/') + ".class";
URL myResourceURL = getClass().getResource(myName);

Result: myResourceURL is ALWAYS null.

ClassLoader.getResource method

String myName2 = getClass().getName().replace('.', '/') + ".class";
ClassLoader myCL = getClass().getClassLoader();
URL myResourceURL2 = myCL.getResource(myName);

Result: myResourceURL2 is ALWAYS null.

a) Where am I going wrong above?

and

b) how do I get the location of the currently executing class using a different method?

like image 997
lee_mcmullen Avatar asked Jul 13 '11 09:07

lee_mcmullen


People also ask

Where are the JAR file located?

A JAR file may contain a manifest file, that is located at META-INF/MANIFEST. MF . The entries in the manifest file describe how to use the JAR file. For instance, a Classpath entry can be used to specify other JAR files to load with the JAR.


2 Answers

I have managed to overcome this by wrapping my code within a "AccessController.doPrivileged" block i.e:

final String[] myLocationViaProtectionDomain = {null};
AccessController.doPrivileged(new PrivilegedAction(){
    public Object run(){
        myLocationViaProtectionDomain[0] = getClass().getProtectionDomain().getCodeSource().getLocation().toString();
        debug("myLocationViaProtectionDomain: " + myLocationViaProtectionDomain[0]);
        return null;
    }
});

Interestingly this approach works exactly as I want when the JAR file is located within the client's JVM directory i.e. points 2 and 3 from my original post. However when the same code runs when the code is being executed from within a Java script library, the following exception is thrown:

java.security.AccessControlException: Access denied (java.lang.RuntimePermission getProtectionDomain)

Which is fine because at least there is a differentiation there between 1 and (2 & 3) which I can then handle properly.

This solution was pointed out to me by the excellent Mikkel from lekkimworld.com (Twitter: @lekkim) so big thanks go out to him.

like image 125
lee_mcmullen Avatar answered Oct 13 '22 01:10

lee_mcmullen


I am not sure if this helps, but we "switch" our user.dir (System property) to make sure we run "out of" a certain directory for our application. In our case we have a web start application that we kick off through Lotus Notes (which calls a BAT file, which invokes Java Web Start (JAWS) ...)

But anyway, what we do is the following.

//Normally you don't ever want to do this......
Class clazz = ClassLoader.class;
Field field = clazz.getDeclaredField("sys_paths");
field.setAccessible(true);
field.setClass(clazz, null);
try {
     //Basically we read in the path and then loop through and remove our current
     //directory which is where we tend to "kick off from" rather than where we want
     //to run from.
     String minusCurrentDir = removeCurrentDirectoryFromPath(System.getProperty("java.library.path");
     System.setProperty("java.library.path", minusCurrentDir);
}
finally {
     field.setAccessible(true);
}

Now later on you can access and modify the user.dir property or ask it where it is. This may give you access to what you want (?) Or at least maybe the top code can help.

like image 30
Chris Aldrich Avatar answered Oct 12 '22 23:10

Chris Aldrich