[英]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.xml
或settings.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.