Fixed classloading issues when a lesson contains an inner class. The plugin classloader only expected the lesson to be loaded, now we keep track of all the classes loaded for each plugin. For each class found in the plugin a plugin classloader was created we need one classloader per plugin

Also needed to rewrite the findClass method to lookup the class in the list instead of loading the class from the byte array.
This commit is contained in:
Nanne Baars 2015-05-04 15:25:28 +02:00
parent 6e8d8562d6
commit 264824eb14
2 changed files with 47 additions and 24 deletions

View File

@ -50,8 +50,10 @@ public class Plugin {
}
public void loadClasses(Map<String, byte[]> classes) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader);
for (Map.Entry<String, byte[]> clazz : classes.entrySet()) {
loadClass(clazz.getKey(), clazz.getValue());
loadClass(pluginClassLoader, clazz.getKey(), clazz.getValue());
}
if (lesson == null) {
throw new PluginLoadingFailure(String
@ -60,18 +62,13 @@ public class Plugin {
}
}
private void loadClass(String name, byte[] classFile) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, name, classFile);
try {
private void loadClass(PluginClassLoader pluginClassLoader, String name, byte[] classFile) {
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
Class clazz = pluginClassLoader.loadClass(realClassName);
Class clazz = pluginClassLoader.loadClass(realClassName, classFile);
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
}
} catch (ClassNotFoundException e) {
logger.error("Unable to load class {}", name, e);
}
}
public void loadFiles(List<Path> files, boolean reload) {
@ -97,7 +94,7 @@ public class Plugin {
Files.copy(file, bos);
Path propertiesPath = createPropertiesDirectory();
ResourceBundleClassLoader.setPropertiesPath(propertiesPath);
if ( reload ) {
if (reload) {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, APPEND);
} else {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, TRUNCATE_EXISTING);
@ -117,8 +114,14 @@ public class Plugin {
public void rewritePaths(Path pluginTarget) {
try {
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files", pluginTarget.getFileName().toString() + "/plugin/" + this.lesson.getSimpleName() + "/lessonSolutions/en/" + this.lesson.getSimpleName() + "_files", solutionLanguageFiles.values());
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files", pluginTarget.getFileName().toString() + "/plugin/" + this.lesson.getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files", lessonPlansLanguageFiles.values());
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files",
pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonSolutions/en/" + this.lesson.getSimpleName() + "_files",
solutionLanguageFiles.values());
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files",
pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files",
lessonPlansLanguageFiles.values());
} catch (IOException e) {
throw new PluginLoadingFailure("Unable to rewrite the paths in the solutions", e);
}

View File

@ -1,22 +1,42 @@
package org.owasp.webgoat.plugins;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class PluginClassLoader extends ClassLoader {
private final List<Class<?>> classes = new ArrayList<>();
private final Logger logger = LoggerFactory.getLogger(Plugin.class);
private final byte[] classFile;
public PluginClassLoader(ClassLoader parent, String nameOfClass, byte[] classFile) {
super(parent);
logger.debug("Creating class loader for {}", nameOfClass);
this.classFile = classFile;
public Class<?> loadClass(String nameOfClass, byte[] classFile) {
Class<?> clazz = defineClass(nameOfClass, classFile, 0, classFile.length);
classes.add(clazz);
return clazz;
}
public Class findClass(String name) {
public PluginClassLoader(ClassLoader contextClassLoader) {
super(contextClassLoader);
}
public Class findClass(final String name) throws ClassNotFoundException {
logger.debug("Finding class " + name);
return defineClass(name, classFile, 0, classFile.length);
Optional<Class<?>> foundClass = FluentIterable.from(classes)
.firstMatch(new Predicate<Class<?>>() {
@Override
public boolean apply(Class<?> clazz) {
return clazz.getName().equals(name);
}
});
if (foundClass.isPresent()) {
return foundClass.get();
}
throw new ClassNotFoundException("Class " + name + " not found");
}
}