Commits

md_5 authored c29791a82d9
Backport some PluginClassLoader changes for soak testing.
No tags

src/main/java/org/bukkit/plugin/java/PluginClassLoader.java

Modified
1 1 package org.bukkit.plugin.java;
2 2
3 +import com.google.common.io.ByteStreams;
3 4 import java.io.File;
5 +import java.io.IOException;
6 +import java.io.InputStream;
4 7 import java.net.MalformedURLException;
5 8 import java.net.URL;
6 9 import java.net.URLClassLoader;
10 +import java.security.CodeSigner;
11 +import java.security.CodeSource;
7 12 import java.util.HashMap;
8 13 import java.util.Map;
9 14 import java.util.Set;
15 +import java.util.jar.JarEntry;
16 +import java.util.jar.JarFile;
17 +import java.util.jar.Manifest;
10 18
11 19 import org.apache.commons.lang.Validate;
12 20 import org.bukkit.plugin.InvalidPluginException;
13 21 import org.bukkit.plugin.PluginDescriptionFile;
14 22
15 23 /**
16 24 * A ClassLoader for plugins, to allow shared classes across multiple plugins
17 25 */
18 26 final class PluginClassLoader extends URLClassLoader {
19 27 private final JavaPluginLoader loader;
20 28 private final Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
21 29 private final PluginDescriptionFile description;
22 30 private final File dataFolder;
23 31 private final File file;
32 + private final JarFile jar;
33 + private final Manifest manifest;
34 + private final URL url;
24 35 final JavaPlugin plugin;
25 36 private JavaPlugin pluginInit;
26 37 private IllegalStateException pluginState;
27 38
28 - PluginClassLoader(final JavaPluginLoader loader, final ClassLoader parent, final PluginDescriptionFile description, final File dataFolder, final File file) throws InvalidPluginException, MalformedURLException {
39 + PluginClassLoader(final JavaPluginLoader loader, final ClassLoader parent, final PluginDescriptionFile description, final File dataFolder, final File file) throws IOException, InvalidPluginException, MalformedURLException {
29 40 super(new URL[] {file.toURI().toURL()}, parent);
30 41 Validate.notNull(loader, "Loader cannot be null");
31 42
32 43 this.loader = loader;
33 44 this.description = description;
34 45 this.dataFolder = dataFolder;
35 46 this.file = file;
47 + this.jar = new JarFile(file, true);
48 + this.manifest = jar.getManifest();
49 + this.url = file.toURI().toURL();
36 50
37 51 try {
38 52 Class<?> jarClass;
39 53 try {
40 54 jarClass = Class.forName(description.getMain(), true, this);
41 55 } catch (ClassNotFoundException ex) {
42 56 throw new InvalidPluginException("Cannot find main class `" + description.getMain() + "'", ex);
43 57 }
44 58
45 59 Class<? extends JavaPlugin> pluginClass;
67 81 throw new ClassNotFoundException(name);
68 82 }
69 83 Class<?> result = classes.get(name);
70 84
71 85 if (result == null) {
72 86 if (checkGlobal) {
73 87 result = loader.getClassByName(name);
74 88 }
75 89
76 90 if (result == null) {
77 - result = super.findClass(name);
91 + String path = name.replace('.', '/').concat(".class");
92 + JarEntry entry = jar.getJarEntry(path);
93 +
94 + if (entry != null) {
95 + byte[] classBytes;
96 +
97 + try (InputStream is = jar.getInputStream(entry)) {
98 + classBytes = ByteStreams.toByteArray(is);
99 + } catch (IOException ex) {
100 + throw new ClassNotFoundException(name, ex);
101 + }
102 +
103 + int dot = name.lastIndexOf('.');
104 + if (dot != -1) {
105 + String pkgName = name.substring(0, dot);
106 + if (getPackage(pkgName) == null) {
107 + definePackage(pkgName, manifest, url);
108 + }
109 + }
110 +
111 + CodeSigner[] signers = entry.getCodeSigners();
112 + CodeSource source = new CodeSource(url, signers);
113 +
114 + result = defineClass(name, classBytes, 0, classBytes.length, source);
115 + }
116 +
117 + if (result == null) {
118 + result = super.findClass(name);
119 + }
78 120
79 121 if (result != null) {
80 122 loader.setClass(name, result);
81 123 }
82 124 }
83 125
84 126 classes.put(name, result);
85 127 }
86 128
87 129 return result;
88 130 }
89 131
132 + @Override
133 + public void close() throws IOException {
134 + try {
135 + super.close();
136 + } finally {
137 + jar.close();
138 + }
139 + }
140 +
90 141 Set<String> getClasses() {
91 142 return classes.keySet();
92 143 }
93 144
94 145 synchronized void initialize(JavaPlugin javaPlugin) {
95 146 Validate.notNull(javaPlugin, "Initializing plugin cannot be null");
96 147 Validate.isTrue(javaPlugin.getClass().getClassLoader() == this, "Cannot initialize plugin outside of this class loader");
97 148 if (this.plugin != null || this.pluginInit != null) {
98 149 throw new IllegalArgumentException("Plugin already initialized!", pluginState);
99 150 }

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut