简体   繁体   English

从类路径中不包含的外部jar中读取xml

[英]Read xml from an external jar not included in classpath

I created a javafx project using Netbeans, the project itself works just fine. 我使用Netbeans创建了一个javafx项目,该项目本身工作正常。

I'm now trying to implement a custom light-weight plugin system, the plugins are external JARs located inside the plugins/ directory of the main project. 我现在正在尝试实现一个自定义的轻量级插件系统,这些插件是位于主项目的plugins/目录内的外部JAR。 I'm using javax.security package to sandbox the plugins. 我正在使用javax.security软件包对插件进行沙箱测试。

Here's the main project's structure: 这是主要项目的结构:

MainProject
  |
  |---plugins/
  |   |---MyPlugin.jar
  |
  |---src/
  |   |---main.app.plugin
  |       |---Plugin.java
  |       |---PluginSecurityPolicy.java
  |       |---PluginClassLoader.java
  |       |---PluginContainer.java
  ....

And the plugin's one: 插件的一个:

Plugin
  |
  |---src/
  |   |---my.plugin
  |   |   |---MyPlugin.java
  |   |--settings.xml
  |
  |---dist/
      |---MyPlugin.jar
          |---META-INF/
          |   |---MANIFEST.MF
          |---my.plugin
          |   |---MyPlugin.class
          |---settings.xml

To load the plugins into the program i've made a PluginContainer class that gets all the jar files from the plugins directory, lists all file inside the jar and lookup for the plugin file and the settings file. 要将插件加载到程序中,我创建了一个PluginContainer类,该类从plugins目录中获取所有jar文件,列出jar中的所有文件,并查找插件文件和设置文件。

I can load and make an instance of the plugin class, but when it comes to the XML there's no way i can even list it among the jar contents. 我可以加载并创建插件类的实例,但是当涉及到XML时,我什至无法在jar内容中列出它。

Here's the code, maybe someone can see where i did it wrong. 这是代码,也许有人可以看到我在哪里做错了。

PluginSecurityPolicy.java PluginSecurityPolicy.java

import java.security.AllPermission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;

public class PluginSecurityPolicy extends Policy {

    @Override
    public PermissionCollection getPermissions(ProtectionDomain domain) {
        if (isPlugin(domain)) {
            return pluginPermissions();
        } else {
            return applicationPermissions();
        }        
    }

    private boolean isPlugin(ProtectionDomain domain) {
        return domain.getClassLoader() instanceof PluginClassLoader;
    }

    private PermissionCollection pluginPermissions() {
        Permissions permissions = new Permissions();
        //
        return permissions;
    }

    private PermissionCollection applicationPermissions() {
        Permissions permissions = new Permissions();
        permissions.add(new AllPermission());
        return permissions;
    }
}

PluginClassLoader.java PluginClassLoader.java

import java.net.URL;
import java.net.URLClassLoader;

public class PluginClassLoader extends URLClassLoader {

    public PluginClassLoader(URL jarFileUrl) {
        super(new URL[] {jarFileUrl});
    }
}

PluginContainer.java, the #load method is the one PluginContainer.java, #load方法是一种

import main.app.plugin.PluginClassLoader;
import main.app.plugin.PluginSecurityPolicy;
import java.io.File;
import java.net.URL;
import java.security.Policy;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class PluginContainer {
    private ArrayList<Plugin> plugins;
    private ManifestParser parser;

    public PluginContainer() {
        Policy.setPolicy(new PluginSecurityPolicy());
        System.setSecurityManager(new SecurityManager());
        plugins = new ArrayList<>();
        parser = new ManifestParser();
    }

    public void init() {
        File[] dir = new File(System.getProperty("user.dir") + "/plugins").listFiles();
        for (File pluginJarFile : dir) {
            try {
                Plugin plugin = load(pluginJarFile.getCanonicalPath());
                plugins.add(plugin);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    public <T extends Plugin> T getPlugin(Class<T> plugin) {
        for (Plugin p : plugins) {
            if (p.getClass().equals(plugin)) {
                return (T)p;
            }
        }
        return null;
    }

    private Plugin load(String pluginJarFile) throws Exception { 
        PluginManifest manifest = null;
        Plugin plugin = null;

        // Load the jar file
        ZipFile jarFile = new ZipFile(pluginJarFile);            

        // Get all jar entries
        Enumeration allEntries = jarFile.entries();
        String pluginClassName = null;

        while (allEntries.hasMoreElements()) {

            // Get single file
            ZipEntry entry = (ZipEntry) allEntries.nextElement();
            String file = entry.getName();

            // Look for classfiles
            if (file.endsWith(".class")) {

                // Set class name
                String classname = file.replace('/', '.').substring(0, file.length() - 6);

                // Look for plugin class
                if (classname.endsWith("Plugin")) {

                    // Set the class name and exit loop
                    pluginClassName = classname;
                    break;
                }
            }
        }

        // Load the class
        ClassLoader pluginLoader = new PluginClassLoader(new URL("file:///" + pluginJarFile));
        Class<?> pluginClass = pluginLoader.loadClass(pluginClassName);

        // Edit as suggested by KDM, still null
        URL settingsUrl = pluginClass.getResource("/settings.xml");
        manifest = parser.load(settingsUrl);

        // Check if manifest has been created
        if (null == manifest) {
            throw new RuntimeException("Manifest file not found in " + pluginJarFile);
        }

        // Create the plugin
        plugin = (Plugin) pluginClass.newInstance();
        plugin.load(manifest);

        return plugin;
    }
}

And the autogenerated MANIFEST.MF 和自动生成的MANIFEST.MF

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.4
Created-By: 1.8.0_25-b18 (Oracle Corporation)

The Class-Path directive is missing, but if i force it to . Class-Path指令丢失,但是如果我强制将其设置为. or ./settings.xml or settings.xml (by manually editing the MANIFEST.MF file) it won't work either. ./settings.xmlsettings.xml (通过手动编辑MANIFEST.MF文件)也不起作用。

This is all I can think of, Thanks in advance for any help 这就是我能想到的,在此先感谢您的帮助

[ EDIT ] I've created an images/monitor-16.png into the plugin jar root, added the #load2 method into the PluginContainer . [ 编辑 ]我已经创建了一个images/monitor-16.png到插件罐子根,加入#load2方法进PluginContainer

Since the method is called within a loop I left the Policy.setPolicy(new PluginSecurityPolicy()); 由于该方法是在循环内调用的,因此我离开了Policy.setPolicy(new PluginSecurityPolicy()); and System.setSecurityManager(new SecurityManager()); System.setSecurityManager(new SecurityManager()); inside the constructor. 在构造函数中。

Here's the new plugn jar structure: 这是新的插件jar结构:

TestPlugin.jar
    |
    |---META-INF/
    |   |---MANIFEST.MF
    |
    |---dev.jimbo
    |   |---TestPlugin.class
    |
    |---images
    |   |---monitor-16.png
    |
    |---settings.xml

The new method code: 新方法代码:

private Plugin load2(String pluginJarFile) throws MalformedURLException, ClassNotFoundException {        
    PluginClassLoader urlCL = new PluginClassLoader(new File(pluginJarFile).toURL());
    Class<?> loadClass = urlCL.loadClass("dev.jimbo.TestPlugin");

    System.out.println(loadClass);
    System.out.println("Loading the class using the class loader object. Resource = " + urlCL.getResource("images/monitor-16.png"));
    System.out.println("Loading the class using the class loader object with absolute path. Resource = " + urlCL.getResource("/images/monitor-16.png"));
    System.out.println("Loading the class using the class object. Resource = " + loadClass.getResource("images/monitor-16.png"));
    System.out.println();

    return null;
}

Here's the output 这是输出

class dev.jimbo.TestPlugin
Loading the class using the class loader object. Resource = null
Loading the class using the class loader object with absolute path. Resource = null
Loading the class using the class object. Resource = null

The following program: 以下程序:

public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
    Policy.setPolicy(new PluginSecurityPolicy());
    System.setSecurityManager(new SecurityManager());
    PluginClassLoader urlCL = new PluginClassLoader(new File(
            "A Jar containing images/load.gif and SampleApp class").toURL());
    Class<?> loadClass = urlCL.loadClass("net.sourceforge.marathon.examples.SampleApp");
    System.out.println(loadClass);
    System.out.println("Loading the class using the class loader object. Resource = " + urlCL.getResource("images/load.gif"));
    System.out.println("Loading the class using the class loader object with absolute path. Resource = " + urlCL.getResource("/images/load.gif"));
    System.out.println("Loading the class using the class object. Resource = " + loadClass.getResource("images/load.gif"));
}

Produces the following output: 产生以下输出:

class net.sourceforge.marathon.examples.SampleApp
Loading the class using the class loader object. Resource = jar:file:/Users/dakshinamurthykarra/Projects/install/marathon/sampleapp.jar!/images/load.gif
Loading the class using the class loader object with absolute path. Resource = null
Loading the class using the class object. Resource = null

So I do not think any problem with your class loader. 因此,我认为您的类加载器没有任何问题。 Putting this as an answer so that the code can be formatted properly. 将其作为答案,以便可以正确格式化代码。

Nailed it! 搞定了! Seems that my previous Netbeans (8.0) was deleting the plugin directory from the added Jar/Folder Libraries references on Clean and Build action. 似乎我以前的Netbeans(8.0)正在从Clean and Build操作上添加的Jar / Folder Libraries参考中删除plugin目录。 I've downloaded and installed Netbeans 8.0.2 and the problem was solved. 我已经下载并安装了Netbeans 8.0.2,问题已解决。 Couldn't find any related bug for that version on their tracker though.. 不过,在其跟踪器上找不到该版本的任何相关错误。

Anyways Thanks for the help :) 无论如何,谢谢您的帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM