Moved Maven multiproject setup

This commit is contained in:
Nanne Baars
2015-08-11 21:57:12 +02:00
parent 28a2d01ba3
commit 42f373d66a
578 changed files with 455 additions and 435 deletions

View File

@ -0,0 +1,26 @@
package org.owasp.webgoat.plugins;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
public final class GlobalProperties {
private final Path pluginDirectory;
public GlobalProperties(Path pluginDirectory) {
this.pluginDirectory = Objects.requireNonNull(pluginDirectory, "pluginDirectory cannot be null");
}
public void loadProperties(Path globalPropertiesPath) {
try {
PluginFileUtils.createDirsIfNotExists(pluginDirectory);
List<Path> filesInDirectory = PluginFileUtils.getFilesInDirectory(globalPropertiesPath);
new Plugin(pluginDirectory).loadFiles(filesInDirectory, true);
} catch (IOException e) {
throw new IllegalStateException("Unable to load global properties, check your installation for the directory i18n: " + globalPropertiesPath.toString(), e);
}
}
}

View File

@ -0,0 +1,256 @@
package org.owasp.webgoat.plugins;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.WebgoatContext;
import org.owasp.webgoat.session.WebgoatProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import java.io.File;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* *************************************************************************************************
* <p/>
* <p/>
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
* <p/>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p/>
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p/>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* <p/>
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
* <p/>
* Getting Source ==============
* <p/>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
* <p/>
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
public class LegacyLoader {
final Logger logger = LoggerFactory.getLogger(LegacyLoader.class);
private final List<String> files = new LinkedList<String>();
public LegacyLoader() {
}
/**
* Take an absolute file and return the filename.
* <p/>
* Ex. /etc/password becomes password
*
* @param s
* @return the file name
*/
private static String getFileName(String s) {
String fileName = new File(s).getName();
if (fileName.contains("/")) {
fileName = fileName.substring(fileName.lastIndexOf("/"), fileName.length());
}
if (fileName.contains(".")) {
fileName = fileName.substring(0, fileName.indexOf("."));
}
return fileName;
}
/**
* Take a class name and return the equivalent file name
* <p/>
* Ex. org.owasp.webgoat becomes org/owasp/webgoat.java
*
* @param className
* @return
*/
private static String getSourceFile(String className) {
StringBuilder sb = new StringBuilder();
sb.append(className.replace(".", "/"));
sb.append(".java");
return sb.toString();
}
/**
* Takes a file name and builds the class file name
*
* @param fileName Description of the Parameter
* @param path Description of the Parameter
* @return Description of the Return Value
*/
private static String getClassFile(String fileName, String path) {
String ext = ".class";
fileName = fileName.trim();
/**
* We do not handle directories. We do not handle files with different
* extensions
*/
if (fileName.endsWith("/") || !fileName.endsWith(ext)) {
return null;
}
// skip over plugins and/or extracted plugins
if ( fileName.indexOf("lessons/plugin") >= 0 || fileName.indexOf("plugin_extracted") >= 0) {
return null;
}
// if the file is in /WEB-INF/classes strip the dir info off
int index = fileName.indexOf("/WEB-INF/classes/");
if (index != -1) {
fileName = fileName.substring(index + "/WEB-INF/classes/".length(), fileName.length() - ext.length());
fileName = fileName.replace('/', '.');
fileName = fileName.replace('\\', '.');
} else {
// Strip off the leading path info
fileName = fileName.substring(path.length(), fileName.length() - ext.length());
}
return fileName;
}
/**
* Load all of the filenames into a temporary cache
*
* @param context
* @param path
*/
public void loadFiles(ServletContext context, String path) {
logger.debug("Loading files into cache, path: " + path);
Set resourcePaths = context.getResourcePaths(path);
if (resourcePaths == null) {
logger.error("Unable to load file cache for courses, this is probably a bug or configuration issue");
return;
}
Iterator itr = resourcePaths.iterator();
while (itr.hasNext()) {
String file = (String) itr.next();
if (file.length() != 1 && file.endsWith("/")) {
loadFiles(context, file);
} else {
files.add(file);
}
}
}
/**
* Instantiate all the lesson objects into a cache
*
* @param path
* @param context
*/
public List<AbstractLesson> loadLessons(WebgoatContext webgoatContext, ServletContext context, String path, WebgoatProperties properties ) {
loadFiles(context, path);
List<AbstractLesson> lessons = new LinkedList<AbstractLesson>();
for (String file : files) {
String className = getClassFile(file, path);
if (className != null && !className.endsWith("_i") && className.startsWith("org.owasp.webgoat.lessons.admin")) {
try {
Class c = Class.forName(className);
Object o = c.newInstance();
if (o instanceof AbstractLesson) {
AbstractLesson lesson = (AbstractLesson) o;
lesson.setWebgoatContext(webgoatContext);
lesson.update(properties);
if (lesson.getHidden() == false) {
lessons.add(lesson);
}
}
} catch (Exception e) {
// Bruce says:
// I don't think we want to log the exception here. We could
// be potentially showing a lot of exceptions that don't matter.
// We would only care if the lesson extended AbstractLesson and we
// can't tell that because it threw the exception. Catch 22
// logger.error("Error in loadLessons: ", e);
}
}
}
loadResources(lessons);
return lessons;
}
private String getLanguageFromFileName(String first, String absoluteFile) {
int p1 = absoluteFile.indexOf("/", absoluteFile.indexOf(first) + 1);
int p2 = absoluteFile.indexOf("/", p1 + 1);
String langStr = absoluteFile.substring(p1 + 1, p2);
return langStr;
}
/**
* For each lesson, set the source file and lesson file
* @param lessons
*/
public void loadResources(List<AbstractLesson> lessons ) {
for (AbstractLesson lesson : lessons) {
logger.info("Loading resources for lesson -> " + lesson.getName());
String className = lesson.getClass().getName();
String classFile = getSourceFile(className);
logger.info("Lesson classname: " + className);
logger.info("Lesson java file: " + classFile);
for (String absoluteFile : files) {
String fileName = getFileName(absoluteFile);
//logger.debug("Course: looking at file: " + absoluteFile);
if (absoluteFile.endsWith(classFile)) {
logger.info("Set source file for " + classFile);
lesson.setSourceFileName(absoluteFile);
}
if (absoluteFile.startsWith("/lesson_plans") && absoluteFile.endsWith(".html")
&& className.endsWith(fileName)) {
logger.info("setting lesson plan file " + absoluteFile + " for lesson "
+ lesson.getClass().getName());
logger.info("fileName: " + fileName + " == className: " + className);
String language = getLanguageFromFileName("/lesson_plans", absoluteFile);
lesson.setLessonPlanFileName(language, absoluteFile);
}
if (absoluteFile.startsWith("/lesson_solutions") && absoluteFile.endsWith(".html")
&& className.endsWith(fileName)) {
logger.info("setting lesson solution file " + absoluteFile + " for lesson "
+ lesson.getClass().getName());
logger.info("fileName: " + fileName + " == className: " + className);
lesson.setLessonSolutionFileName(absoluteFile);
}
}
}
}
}

View File

@ -0,0 +1,178 @@
package org.owasp.webgoat.plugins;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.owasp.webgoat.classloader.PluginClassLoader;
import org.owasp.webgoat.lessons.AbstractLesson;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.nio.file.StandardOpenOption.APPEND;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith;
import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithName;
import static org.owasp.webgoat.plugins.PluginFileUtils.replaceInFiles;
public class Plugin {
private static final String NAME_LESSON_SOLUTION_DIRECTORY = "lessonSolutions";
private static final String NAME_LESSON_PLANS_DIRECTORY = "lessonPlans";
private static final String NAME_LESSON_I18N_DIRECTORY = "i18n";
private final Path pluginDirectory;
private Class<AbstractLesson> lesson;
private Map<String, File> solutionLanguageFiles = new HashMap<>();
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
private List<File> pluginFiles = Lists.newArrayList();
private File lessonSourceFile;
public Plugin(Path pluginDirectory) {
Preconditions.checkNotNull(pluginDirectory, "plugin directory cannot be null");
Preconditions.checkArgument(Files.exists(pluginDirectory), "directory %s does not exists", pluginDirectory);
this.pluginDirectory = pluginDirectory;
}
public Plugin(Path pluginDirectory, List<String> classes) {
this(pluginDirectory);
findLesson(classes);
}
private void findLesson(List<String> classes) {
for (String clazzName : classes) {
findLesson(clazzName);
}
}
private void findLesson(String name) {
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
PluginClassLoader cl = (PluginClassLoader) Thread.currentThread().getContextClassLoader();
try {
Class clazz = cl.loadClass(realClassName, true);
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
}
} catch (ClassNotFoundException ce) {
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
}
}
public void loadFiles(List<Path> files, boolean reload) {
for (Path file : files) {
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_SOLUTION_DIRECTORY)) {
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_PLANS_DIRECTORY)) {
lessonPlansLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (fileEndsWith(file, ".java")) {
lessonSourceFile = file.toFile();
}
if (fileEndsWith(file, ".properties") && hasParentDirectoryWithName(file, NAME_LESSON_I18N_DIRECTORY)) {
copyProperties(reload, file);
}
if (fileEndsWith(file, ".css", ".jsp", ".js")) {
pluginFiles.add(file.toFile());
}
}
}
private void copyProperties(boolean reload, Path file) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Files.copy(file, bos);
Path propertiesPath = createPropertiesDirectory();
ResourceBundleClassLoader.setPropertiesPath(propertiesPath);
PluginFileUtils.createDirsIfNotExists(file.getParent());
if (reload) {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, APPEND);
} else {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, TRUNCATE_EXISTING);
}
} catch (IOException io) {
throw new PluginLoadingFailure("Property file detected, but unable to copy the properties", io);
}
}
private Path createPropertiesDirectory() throws IOException {
if (Files.exists(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY))) {
return pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY);
} else {
return Files.createDirectory(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY));
}
}
public void rewritePaths(Path pluginTarget) {
try {
replaceInFiles(this.lesson.getSimpleName() + "_files",
pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonSolutions/en/" + this.lesson.getSimpleName() + "_files",
solutionLanguageFiles.values());
replaceInFiles(this.lesson.getSimpleName() + "_files",
pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files",
lessonPlansLanguageFiles.values());
String[] replacements = {"jsp", "js"};
for ( String replacement : replacements ) {
String s = String.format("plugin/%s/%s/", this.lesson.getSimpleName(), replacement);
String r = String.format("%s/plugin/%s/%s/", pluginTarget.getFileName().toString(),
this.lesson.getSimpleName(), replacement);
replaceInFiles(s,r, pluginFiles);
replaceInFiles(s,r, Arrays.asList(lessonSourceFile));
}
//CSS with url('/plugin/images') should not begin with / otherwise image cannot be found
String s = String.format("/plugin/%s/images/", this.lesson.getSimpleName());
String r = String.format("%s/plugin/%s/images/", pluginTarget.getFileName().toString(), this.lesson.getSimpleName());
replaceInFiles(s,r, pluginFiles);
replaceInFiles(s,r, Arrays.asList(lessonSourceFile));
} catch (IOException e) {
throw new PluginLoadingFailure("Unable to rewrite the paths in the solutions", e);
}
}
/**
* Lesson is optional, it is also possible that the supplied jar contains only helper classes.
*/
public Optional<AbstractLesson> getLesson() {
try {
if (lesson != null) {
return Optional.of(lesson.newInstance());
}
} catch (IllegalAccessException | InstantiationException e) {
throw new PluginLoadingFailure("Unable to instantiate the lesson " + lesson.getName(), e);
}
return Optional.absent();
}
public Optional<File> getLessonSolution(String language) {
return Optional.fromNullable(this.solutionLanguageFiles.get(language));
}
public Map<String, File> getLessonSolutions() {
return this.solutionLanguageFiles;
}
public Optional<File> getLessonSource() {
return Optional.fromNullable(lessonSourceFile);
}
public Map<String, File> getLessonPlans() {
return this.lessonPlansLanguageFiles;
}
}

View File

@ -0,0 +1,29 @@
package org.owasp.webgoat.plugins;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.nio.file.Paths;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@WebListener
public class PluginBackgroundLoader implements ServletContextListener {
private ScheduledExecutorService scheduler;
@Override
public void contextInitialized(ServletContextEvent event) {
String pluginPath = event.getServletContext().getRealPath("plugin_lessons");
String targetPath = event.getServletContext().getRealPath("plugin_extracted");
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)), 0, 5, TimeUnit.MINUTES);
}
@Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}

View File

@ -0,0 +1,69 @@
package org.owasp.webgoat.plugins;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static java.lang.String.format;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.owasp.webgoat.plugins.PluginFileUtils.createDirsIfNotExists;
/**
* Extract the jar file and place them in the system temp directory in the folder webgoat and collect the files
* and classes.
*/
public class PluginExtractor {
private final Path pluginArchive;
private final List<String> classes = Lists.newArrayList();
private final List<Path> files = new ArrayList<>();
public PluginExtractor(Path pluginArchive) {
this.pluginArchive = pluginArchive;
}
public void extract(final Path target) {
try (FileSystem zip = createZipFileSystem()) {
final Path root = zip.getPath("/");
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (file.toString().endsWith(".class")) {
classes.add(file.toString());
}
files.add(Files.copy(file, createDirsIfNotExists(Paths.get(target.toString(), file.toString())), REPLACE_EXISTING));
return FileVisitResult.CONTINUE;
}
});
} catch (Exception e) {
new PluginLoadingFailure(format("Unable to extract: %s", pluginArchive.getFileName()), e);
}
}
public List<String> getClasses() {
return this.classes;
}
public List<Path> getFiles() {
return this.files;
}
private FileSystem createZipFileSystem() throws Exception {
final URI uri = URI.create("jar:file:" + pluginArchive.toUri().getPath());
return FileSystems.newFileSystem(uri, new HashMap<String, Object>());
}
}

View File

@ -0,0 +1,90 @@
package org.owasp.webgoat.plugins;
import com.google.common.base.Preconditions;
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class PluginFileUtils {
public static boolean fileEndsWith(Path p, String s) {
return p.getFileName().toString().endsWith(s);
}
public static boolean fileEndsWith(Path p, String... suffixes) {
for (String suffix : suffixes) {
if (fileEndsWith(p, suffix)) {
return true;
}
}
return false;
}
public static boolean hasParentDirectoryWithName(Path p, String s) {
if (p == null || p.getParent() == null || p.getParent().equals(p.getRoot())) {
return false;
}
if (p.getParent().getFileName().toString().equals(s)) {
return true;
}
return hasParentDirectoryWithName(p.getParent(), s);
}
public static Path createDirsIfNotExists(Path p) throws IOException {
if (Files.notExists(p)) {
Files.createDirectories(p);
}
return p;
}
public static List<Path> getFilesInDirectory(Path directory) throws IOException {
List<Path> files = new ArrayList<>();
DirectoryStream<Path> dirStream;
dirStream = Files.newDirectoryStream(directory);
for (Path entry : dirStream) {
files.add(entry);
}
dirStream.close();
return files;
}
public static void replaceInFiles(String replace, String with, Collection<File> files) throws IOException {
Preconditions.checkNotNull(replace);
Preconditions.checkNotNull(with);
Preconditions.checkNotNull(files);
for (File file : files) {
replaceInFile(replace, with, Paths.get(file.toURI()));
}
}
public static void replaceInFile(String replace, String with, Path file) throws IOException {
Preconditions.checkNotNull(replace);
Preconditions.checkNotNull(with);
Preconditions.checkNotNull(file);
byte[] fileAsBytes = Files.readAllBytes(file);
String fileAsString = new String(fileAsBytes);
fileAsString = fileAsString.replaceAll(replace, with);
Files.write(file, fileAsString.getBytes(), StandardOpenOption.TRUNCATE_EXISTING);
}
public static void writeFile(Path targetFile, byte[] bytes, OpenOption... options) throws IOException {
createDirsIfNotExists(targetFile.getParent());
if (!Files.exists(targetFile)) {
Files.createFile(targetFile);
}
Files.write(targetFile, bytes, options);
}
}

View File

@ -0,0 +1,8 @@
package org.owasp.webgoat.plugins;
public class PluginLoadingFailure extends RuntimeException {
public PluginLoadingFailure(String message, Exception e) {
super(message, e);
}
}

View File

@ -0,0 +1,88 @@
package org.owasp.webgoat.plugins;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.owasp.webgoat.classloader.PluginClassLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
public class PluginsLoader implements Runnable {
protected static final String WEBGOAT_PLUGIN_EXTENSION = "jar";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Path pluginSource;
private Path pluginTarget;
public PluginsLoader(Path pluginSource, Path pluginTarget) {
Preconditions.checkNotNull(pluginSource, "plugin source cannot be null");
Preconditions.checkNotNull(pluginTarget, "plugin target cannot be null");
this.pluginSource = pluginSource;
this.pluginTarget = pluginTarget;
}
public List<Plugin> loadPlugins(final boolean reload) {
final PluginClassLoader cl = (PluginClassLoader)Thread.currentThread().getContextClassLoader();
List<Plugin> plugins = Lists.newArrayList();
try {
PluginFileUtils.createDirsIfNotExists(pluginTarget);
List<URL> jars = listJars();
cl.addURL(jars);
plugins = processPlugins(jars, reload);
} catch (IOException | URISyntaxException e) {
logger.error("Loading plugins failed", e);
}
return plugins;
}
private List<URL> listJars() throws IOException {
final List<URL> jars = Lists.newArrayList();
Files.walkFileTree(pluginSource, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (PluginFileUtils.fileEndsWith(file, WEBGOAT_PLUGIN_EXTENSION)) {
jars.add(file.toUri().toURL());
}
return FileVisitResult.CONTINUE;
}
});
return jars;
}
private List<Plugin> processPlugins(List<URL> jars, boolean reload) throws URISyntaxException, IOException {
final List<Plugin> plugins = Lists.newArrayList();
for (URL jar : jars) {
PluginExtractor extractor = new PluginExtractor(Paths.get(jar.toURI()));
extractor.extract(pluginTarget);
Plugin plugin = new Plugin(pluginTarget, extractor.getClasses());
if (plugin.getLesson().isPresent()) {
PluginFileUtils.createDirsIfNotExists(pluginTarget);
plugin.loadFiles(extractor.getFiles(), reload);
plugin.rewritePaths(pluginTarget);
plugins.add(plugin);
}
}
return plugins;
}
@Override
public void run() {
loadPlugins(true);
}
}

View File

@ -0,0 +1,33 @@
package org.owasp.webgoat.plugins;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class ResourceBundleClassLoader {
private final static ResourceBundleClassLoader classLoader = new ResourceBundleClassLoader();
private Path propertiesPath;
private ResourceBundleClassLoader() {
}
public static void setPropertiesPath(Path path) {
classLoader.propertiesPath = path;
}
public static ClassLoader createPropertyFilesClassLoader() {
final List<URL> urls = new ArrayList<>();
try {
urls.add(classLoader.propertiesPath.toUri().toURL());
} catch (IOException e) {
throw new PluginLoadingFailure("Unable to load the properties for the classloader", e);
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]), Thread.currentThread().getContextClassLoader());
}
}