Расположение текущего запущенного класса или файла JAR

У меня есть база данных Lotus Notes, которая выполняет некоторое взаимодействие с удаленным веб-сервисом. Я написал специальный класс Java для взаимодействия.

Методы класса могут быть выполнены из одного из трех местоположений в зависимости от пользовательской настройки:

  • В библиотеке Java script, вызванной с помощью агента Java Lotus Notes
  • В файле JAR, расположенном в каталоге пользователя "jvm/lib/ext"
  • В файле JAR, расположенном в пользовательском каталоге в каталоге пользователя "jvm/lib" (например, "jvm/lib/custom_dir" ). JVM Lotus Notes знает о настраиваемом каталоге с использованием локальной переменной notes.ini "JavaUserClassesExt".

В моем классе я просто хотел бы вернуть место, из которого выполняется текущий класс. Поэтому, если он выполняется либо из варианта 2, либо из 3-го варианта, а затем возвращает путь к файлу JAR. Если он выполнит из опции 1, верните что-то еще, что я могу обработать.

Я пробовал следующее.

метод getProtectionDomain()

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

Результат:

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

Невозможно изменить какие-либо параметры безопасности для любых клиентов, выполняющих это.

Метод Class.getResource

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

Результат: myResourceURL ВСЕГДА null.

Метод ClassLoader.getResource

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

Результат: myResourceURL2 ВСЕГДА пусто.

a) Где я ошибаюсь выше?

и

b) Как получить местоположение текущего исполняемого класса с помощью другого метода?

Ответ 1

Мне удалось преодолеть это, завернув мой код в блок "AccessController.doPrivileged" 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;
    }
});

Интересно, что этот подход работает точно так, как я хочу, когда JAR файл находится в каталоге JVM клиента, то есть в пунктах 2 и 3 из моего исходного сообщения. Однако, когда тот же код запускается, когда код выполняется из библиотеки Java script, генерируется следующее исключение:

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

Это нормально, потому что, по крайней мере, существует дифференциация между 1 и (2 и 3), которую я могу правильно обрабатывать.

Это решение было указано мне превосходным Mikkel от lekkimworld.com(Twitter: @lekkim), так что большое спасибо ему.

Ответ 2

Я не уверен, что это помогает, но мы "переключаем" наш user.dir (свойство System), чтобы убедиться, что мы запускаем "из" определенного каталога для нашего приложения. В нашем случае у нас есть приложение для веб-запуска, которое мы запускаем через Lotus Notes (который вызывает BAT файл, который вызывает Java Web Start (JAWS)...)

Но в любом случае мы делаем следующее.

//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);
}

Теперь вы можете получить доступ и изменить свойство user.dir или задать его там, где оно есть. Это может дать вам доступ к тому, что вы хотите (?) Или, по крайней мере, может помочь верхний код.

Ответ 3

В вашей последней строке кода есть myCL.getResouce(myName), где вместо этого следует использовать myName2. Это может вызвать проблемы. Если он использует версию имени с ведущим "/", то вы не получите ничего от вызова ClassLoader.getResource(). У него не должно быть ни одной косой черты. Если это не поможет, вы также можете попробовать:

ClassLoader.getSystemResource(myName2); // name without leading slash

Если это все еще не работает, это может быть проблема с безопасностью. Согласно ClassLoader.getResource() docs, он может вернуть значение null, если "у invoker нет достаточных прав для получения ресурса". Я просто знаю Java, а не Lotus, поэтому я не знаю, в какой среде безопасности он запускает код.