diff --git a/scm-core/src/main/java/sonia/scm/plugin/Plugin.java b/scm-core/src/main/java/sonia/scm/plugin/Plugin.java index 50b08c800a..7c52d47f19 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/Plugin.java +++ b/scm-core/src/main/java/sonia/scm/plugin/Plugin.java @@ -70,14 +70,17 @@ public final class Plugin extends ScmModule * @param information * @param resources * @param condition + * @param childFirstClassLoader * @param dependencies */ public Plugin(PluginInformation information, PluginResources resources, - PluginCondition condition, Set dependencies) + PluginCondition condition, boolean childFirstClassLoader, + Set dependencies) { this.information = information; this.resources = resources; this.condition = condition; + this.childFirstClassLoader = childFirstClassLoader; this.dependencies = dependencies; } @@ -109,6 +112,7 @@ public final class Plugin extends ScmModule return Objects.equal(condition, other.condition) && Objects.equal(information, other.information) && Objects.equal(resources, other.resources) + && Objects.equal(childFirstClassLoader, other.childFirstClassLoader) && Objects.equal(dependencies, other.dependencies); } @@ -121,7 +125,8 @@ public final class Plugin extends ScmModule @Override public int hashCode() { - return Objects.hashCode(condition, information, resources, dependencies); + return Objects.hashCode(condition, information, resources, + childFirstClassLoader, dependencies); } /** @@ -138,6 +143,7 @@ public final class Plugin extends ScmModule .add("condition", condition) .add("information", information) .add("resources", resources) + .add("childFirstClassLoader", childFirstClassLoader) .add("dependencies", dependencies) .toString(); //J+ @@ -196,8 +202,23 @@ public final class Plugin extends ScmModule return resources; } + /** + * Method description + * + * + * @return + */ + public boolean isChildFirstClassLoader() + { + return childFirstClassLoader; + } + //~--- fields --------------------------------------------------------------- + /** Field description */ + @XmlElement(name = "child-first-classloader") + private boolean childFirstClassLoader; + /** Field description */ @XmlElement(name = "conditions") private PluginCondition condition; diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java index 506c39201e..ee2d143165 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java @@ -135,77 +135,6 @@ public final class PluginProcessor //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @param parentClassLoader - * @param directory - * - * @return - * - * @throws IOException - */ - private DefaultPluginClassLoader createClassLoader( - ClassLoader parentClassLoader, Path directory) - throws IOException - { - List urls = new ArrayList<>(); - - Path metaDir = directory.resolve(DIRECTORY_METAINF); - - if (!Files.exists(metaDir)) - { - throw new FileNotFoundException("could not find META-INF directory"); - } - - Path linkDir = directory.resolve(DIRECTORY_LINK); - - if (!Files.exists(linkDir)) - { - Files.createDirectory(linkDir); - } - - Path linkMetaDir = linkDir.resolve(DIRECTORY_METAINF); - - if (!Files.exists(linkMetaDir)) - { - Files.deleteIfExists(linkMetaDir); - Files.createSymbolicLink(linkMetaDir, linkMetaDir.relativize(metaDir)); - } - - urls.add(linkDir.toUri().toURL()); - - Path webinfDir = directory.resolve(DIRECTORY_WEBINF); - - if (Files.exists(webinfDir)) - { - Path classesDir = webinfDir.resolve(DIRECTORY_CLASSES); - - if (Files.exists(classesDir)) - { - urls.add(classesDir.toUri().toURL()); - } - - Path libDir = webinfDir.resolve(DIRECTORY_DEPENDENCIES); - - if (Files.exists(libDir)) - { - for (Path f : Files.newDirectoryStream(libDir, GLOB_JAR)) - { - urls.add(f.toUri().toURL()); - } - } - } - - //J- - return new DefaultPluginClassLoader( - urls.toArray(new URL[urls.size()]), - parentClassLoader - ); - //J+ - } - /** * Method description * @@ -313,7 +242,7 @@ public final class PluginProcessor PluginWrapper plugin = createPluginWrapper(createParentPluginClassLoader(classLoader, parents), - smp.getPath()); + smp); if (plugin != null) { @@ -335,7 +264,7 @@ public final class PluginProcessor ClassLoader classLoader, List nodes) throws IOException { - + // TODO fix plugin loading order for (PluginNode node : nodes) { @@ -402,6 +331,91 @@ public final class PluginProcessor return paths.build(); } + /** + * Method description + * + * + * @param parentClassLoader + * @param directory + * @param smp + * + * @return + * + * @throws IOException + */ + private ClassLoader createClassLoader(ClassLoader parentClassLoader, + ExplodedSmp smp) + throws IOException + { + List urls = new ArrayList<>(); + + Path metaDir = smp.getPath().resolve(DIRECTORY_METAINF); + + if (!Files.exists(metaDir)) + { + throw new FileNotFoundException("could not find META-INF directory"); + } + + Path linkDir = smp.getPath().resolve(DIRECTORY_LINK); + + if (!Files.exists(linkDir)) + { + Files.createDirectory(linkDir); + } + + Path linkMetaDir = linkDir.resolve(DIRECTORY_METAINF); + + if (!Files.exists(linkMetaDir)) + { + Files.deleteIfExists(linkMetaDir); + Files.createSymbolicLink(linkMetaDir, linkMetaDir.relativize(metaDir)); + } + + urls.add(linkDir.toUri().toURL()); + + Path webinfDir = smp.getPath().resolve(DIRECTORY_WEBINF); + + if (Files.exists(webinfDir)) + { + Path classesDir = webinfDir.resolve(DIRECTORY_CLASSES); + + if (Files.exists(classesDir)) + { + urls.add(classesDir.toUri().toURL()); + } + + Path libDir = webinfDir.resolve(DIRECTORY_DEPENDENCIES); + + if (Files.exists(libDir)) + { + for (Path f : Files.newDirectoryStream(libDir, GLOB_JAR)) + { + urls.add(f.toUri().toURL()); + } + } + } + + ClassLoader classLoader; + URL[] urlArray = urls.toArray(new URL[urls.size()]); + Plugin plugin = smp.getPlugin(); + + if (smp.getPlugin().isChildFirstClassLoader()) + { + logger.debug("create child fist classloader for plugin {}", + plugin.getInformation().getId()); + classLoader = new ChildFirstPluginClassLoader(urlArray, + parentClassLoader); + } + else + { + logger.debug("create parent fist classloader for plugin {}", + plugin.getInformation().getId()); + classLoader = new DefaultPluginClassLoader(urlArray, parentClassLoader); + } + + return classLoader; + } + /** * Method description * @@ -413,6 +427,37 @@ public final class PluginProcessor return new SimpleDateFormat(FORMAT_DATE).format(new Date()); } + /** + * Method description + * + * + * @param root + * @param parents + * + * @return + */ + private ClassLoader createParentPluginClassLoader(ClassLoader root, + List parents) + { + ClassLoader result; + int size = parents.size(); + + if (size == 0) + { + result = root; + } + else if (size == 1) + { + result = parents.get(0); + } + else + { + result = new MultiParentClassLoader(parents); + } + + return result; + } + /** * Method description * @@ -445,62 +490,32 @@ public final class PluginProcessor } } - /** - * Method description - * - * - * @param root - * @param parents - * - * @return - */ - private ClassLoader createParentPluginClassLoader(ClassLoader root, - List parents) - { - ClassLoader result; - int size = parents.size(); - - if (size == 0) - { - result = root; - } - else if (size == 1) - { - result = parents.get(0); - } - else - { - result = new MultiParentClassLoader(parents); - } - - return result; - } - /** * Method description * * * @param classLoader * @param directory + * @param smp * * @return * * @throws IOException */ private PluginWrapper createPluginWrapper(ClassLoader classLoader, - Path directory) + ExplodedSmp smp) throws IOException { PluginWrapper wrapper = null; - Path descriptor = directory.resolve(PluginConstants.FILE_DESCRIPTOR); + Path descriptor = smp.getPath().resolve(PluginConstants.FILE_DESCRIPTOR); if (Files.exists(descriptor)) { - ClassLoader cl = createClassLoader(classLoader, directory); + ClassLoader cl = createClassLoader(classLoader, smp); Plugin plugin = createPlugin(cl, descriptor); - wrapper = new PluginWrapper(plugin, cl, directory); + wrapper = new PluginWrapper(plugin, cl, smp.getPath()); } else { diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java index a0a17ac9ad..952f7c7195 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java @@ -135,7 +135,7 @@ public class ExplodedSmpTest info.setArtifactId(artifactId); info.setVersion(version); - Plugin plugin = new Plugin(info, null, null, Sets.newSet(dependencies)); + Plugin plugin = new Plugin(info, null, null, false, Sets.newSet(dependencies)); return new ExplodedSmp(null, plugin); } diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/PluginTreeTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/PluginTreeTest.java index 0c32791813..a94a41a10e 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/PluginTreeTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/PluginTreeTest.java @@ -72,7 +72,7 @@ public class PluginTreeTest PluginCondition condition = new PluginCondition("999", new ArrayList(), "hit"); Plugin plugin = new Plugin(createInfo("a", "b", "1"), null, condition, - null); + false, null); ExplodedSmp smp = createSmp(plugin); new PluginTree(smp).getRootNodes(); @@ -186,7 +186,7 @@ public class PluginTreeTest private ExplodedSmp createSmp(String name) throws IOException { return createSmp(new Plugin(createInfo(name, name, "1.0.0"), null, null, - null)); + false, null)); } /** @@ -212,7 +212,7 @@ public class PluginTreeTest } Plugin plugin = new Plugin(createInfo(name, name, "1"), null, null, - dependencySet); + false, dependencySet); return createSmp(plugin); }