Расположение текущего запущенного класса или файла 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, поэтому я не знаю, в какой среде безопасности он запускает код.