【问题标题】:Location of currently running class or JAR file当前运行的类或 JAR 文件的位置
【发布时间】:2011-10-04 07:54:14
【问题描述】:

我有一个Lotus Notes 数据库,它正在与远程Web 服务进行一些交互。我编写了一个自定义 Java 类来执行交互。

根据用户的设置,可以从三个位置之一执行类方法:

  1. 在通过 Lotus Notes Java 代理调用的 Java 脚本库中
  2. 在位于用户“jvm/lib/ext”目录的 JAR 文件中
  3. 在位于用户“jvm/lib”目录(例如,“jvm/lib/custom_dir”)内的自定义目录中的 JAR 文件中。 Lotus Notes JVM 通过使用“JavaUserClassesExt”本地 notes.ini 变量了解自定义目录。

在我的班级中,我只是希望能够返回当前班级正在执行的位置。因此,如果它从选项 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 始终为空。

ClassLoader.getResource 方法

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

结果: myResourceURL2 始终为空。

a) 我在上面哪里出错了?

b) 如何使用不同的方法获取当前正在执行的类的位置?

【问题讨论】:

    标签: java jar lotus-notes


    【解决方案1】:

    我已经设法通过将我的代码包装在“AccessController.doPrivileged”块中来克服这个问题,即:

    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 脚本库中执行代码时运行相同的代码时,会引发以下异常:

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

    这很好,因为至少在 1 和 (2 & 3) 之间存在差异,然后我可以正确处理。

    来自 lekkimworld.com(推特:@lekkim)的优秀 Mikkel 向我指出了这个解决方案,非常感谢他。

    【讨论】:

      【解决方案2】:

      我不确定这是否有帮助,但我们“切换”user.dir(系统属性)以确保我们的应用程序“超出”某个目录。在我们的例子中,我们有一个通过 Lotus Notes 启动的 Web 启动应用程序(它调用一个 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 属性或询问它在哪里。这可能使您可以访问所需的内容(?)或者至少顶级代码可能会有所帮助。

      【讨论】:

      • 感谢您的回复,克里斯,但我设法通过将我的代码包装在 AccessController.doPrivileged 调用中来获得我需要的东西。有关详细信息,请参阅下面的答案。
      • 您可能应该将其标记为您问题的答案。它可以帮助其他人知道您需要做什么。
      • 感谢您的提醒。 StackOverflow 仍然很新,所以不知道适当的礼仪。我已经标记了答案,以后会记住的!
      【解决方案3】:

      你的最后一行代码有myCL.getResouce(myName),它应该使用myName2。这可能会导致问题。如果它使用带有前导“/”的名称版本,那么您将不会从 ClassLoader.getResource() 调用中获得任何信息。它必须没有前导斜杠。如果这没有帮助,您也可以尝试:

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

      如果这仍然不起作用,则可能是安全问题。根据ClassLoader.getResource() docs,如果“调用者没有足够的权限来获取资源”,它可以返回 null。我只知道Java,不知道Lotus,所以我不知道它运行代码的安全环境是什么。

      【讨论】:

      • 感谢您的评论瑞恩,很好。 myName vs myName2 的使用只是我原始描述中的一个错字,即当使用正确的变量名而不使用前面的斜杠时,我得到了相同的行为。
      猜你喜欢
      • 2013-07-18
      • 1970-01-01
      • 2013-01-12
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2013-09-12
      相关资源
      最近更新 更多