From 7ef89abf0167779d5e940147bbea9a1730b33261 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Wed, 11 Nov 2015 13:36:43 -0500 Subject: [PATCH] Refactor the Layout class a bit, and add some tests. tcrawley. --- bootstrap/pom.xml | 57 ++++++++- .../org/wildfly/swarm/bootstrap/LayoutIT.java | 116 ++++++++++++++++++ .../org/wildfly/swarm/bootstrap/Main.java | 2 +- .../modules/ApplicationModuleFinder.java | 5 +- .../modules/BootstrapModuleFinder.java | 21 ++-- .../modules/ClasspathModuleFinder.java | 51 ++++---- .../wildfly/swarm/bootstrap/util/Layout.java | 108 ++++++++++------ .../swarm/bootstrap/util/LayoutTest.java | 38 ++++++ pom.xml | 6 + 9 files changed, 328 insertions(+), 76 deletions(-) create mode 100644 bootstrap/src/it/java/org/wildfly/swarm/bootstrap/LayoutIT.java create mode 100644 bootstrap/src/test/java/org/wildfly/swarm/bootstrap/util/LayoutTest.java diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index cef711849a..4e37450d78 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -59,19 +59,68 @@ + + org.codehaus.mojo + build-helper-maven-plugin + + + add-test-source + generate-test-sources + + add-test-source + + + + src/it/java + + + + + + + maven-failsafe-plugin + + + integration-test + integration-test + + integration-test + + + src/it/java + true + + + + - - org.jboss.modules - jboss-modules - + + org.jboss.modules + jboss-modules + org.jboss.spec.javax.sql jboss-javax-sql-api_7.0_spec ${version.org.jboss.spec.javax.sql.jboss-javax-sql-api_7.0_spec} + + org.jboss.shrinkwrap + shrinkwrap-api + test + + + org.jboss.shrinkwrap + shrinkwrap-spi + test + + + org.jboss.shrinkwrap + shrinkwrap-impl-base + test + diff --git a/bootstrap/src/it/java/org/wildfly/swarm/bootstrap/LayoutIT.java b/bootstrap/src/it/java/org/wildfly/swarm/bootstrap/LayoutIT.java new file mode 100644 index 0000000000..471becedca --- /dev/null +++ b/bootstrap/src/it/java/org/wildfly/swarm/bootstrap/LayoutIT.java @@ -0,0 +1,116 @@ +package org.wildfly.swarm.bootstrap; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.util.Arrays; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.ByteArrayAsset; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.exporter.ZipExporter; +import org.jboss.shrinkwrap.api.importer.ZipImporter; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Test; +import org.wildfly.swarm.bootstrap.util.Layout; + +import static org.fest.assertions.Assertions.assertThat; + +/** + * @author Bob McWhirter + */ +public class LayoutIT { + + @Test + public void testIsUberJar() throws Exception { + JavaArchive archive = createBootstrapArchive(); + + archive.addAsManifestResource(EmptyAsset.INSTANCE, "wildfly-swarm.properties"); + + ClassLoader cl = createClassLoader(archive); + Class layoutClass = cl.loadClass(Layout.class.getName()); + + Method getInstance = layoutClass.getMethod("getInstance"); + Object layout = getInstance.invoke(layoutClass); + + Method isUberJar = layoutClass.getMethod("isUberJar"); + Object result = isUberJar.invoke(layout); + + assertThat(result).isEqualTo(true); + } + + @Test + public void testGetManifest() throws Exception { + JavaArchive archive = createBootstrapArchive(); + + archive.addAsManifestResource(EmptyAsset.INSTANCE, "wildfly-swarm.properties"); + + Manifest manifest = new Manifest(); + + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + manifest.getMainAttributes().put(new Attributes.Name("Wildfly-Swarm-Main-Class"), "MyMainClass"); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + manifest.write(out); + out.close(); + archive.addAsManifestResource(new ByteArrayAsset(out.toByteArray()), "MANIFEST.MF"); + + ClassLoader cl = createClassLoader(archive); + Class layoutClass = cl.loadClass(Layout.class.getName()); + + Method getInstance = layoutClass.getMethod("getInstance"); + Object layout = getInstance.invoke(layoutClass); + + Method isUberJar = layoutClass.getMethod("isUberJar"); + Object result = isUberJar.invoke(layout); + + assertThat(result).isEqualTo(true); + + Method getManifest = layoutClass.getMethod("getManifest"); + Manifest fetchedManifest = (Manifest) getManifest.invoke(layout); + + assertThat(fetchedManifest).isNotNull(); + assertThat(fetchedManifest.getMainAttributes().get(new Attributes.Name("Wildfly-Swarm-Main-Class"))).isEqualTo("MyMainClass"); + } + + protected ClassLoader createClassLoader(JavaArchive archive) throws IOException { + File tmpFile = export(archive); + return new URLClassLoader(new URL[]{tmpFile.toURI().toURL()}, null); + } + + protected File export(JavaArchive archive) throws IOException { + File tmpFile = File.createTempFile("boostrap-archive", ".jar"); + tmpFile.deleteOnExit(); + tmpFile.delete(); + archive.as(ZipExporter.class).exportTo(tmpFile); + return tmpFile; + } + + protected JavaArchive createBootstrapArchive() throws IOException { + JavaArchive archive = ShrinkWrap.create(JavaArchive.class); + archive.as(ZipImporter.class).importFrom(new JarFile(findBootstrapJar())); + return archive; + } + + protected File findBootstrapJar() { + Path targetDir = Paths.get("target"); + + File[] children = targetDir.toFile().listFiles(); + for (File child : children) { + if (child.getName().startsWith("wildfly-swarm-bootstrap") && child.getName().endsWith(".jar") && !child.getName().endsWith("-sources.jar")) { + return child; + } + } + + return null; + } +} diff --git a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/Main.java b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/Main.java index af7a68ceaa..344fbe5301 100644 --- a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/Main.java +++ b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/Main.java @@ -34,7 +34,7 @@ public static void main(String[] args) throws Throwable { System.setProperty("boot.module.loader", BootModuleLoader.class.getName()); String mainClassName = null; - Manifest manifest = Layout.getManifest(); + Manifest manifest = Layout.getInstance().getManifest(); if (manifest != null) { mainClassName = (String) manifest.getMainAttributes().get(new Attributes.Name("Wildfly-Swarm-Main-Class")); diff --git a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ApplicationModuleFinder.java b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ApplicationModuleFinder.java index edc9185164..569c8d6c6b 100644 --- a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ApplicationModuleFinder.java +++ b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ApplicationModuleFinder.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -58,7 +59,7 @@ public ModuleSpec findModule(ModuleIdentifier identifier, ModuleLoader delegateL ModuleSpec.Builder builder = ModuleSpec.build(identifier); try { - if (Layout.isFatJar()) { + if (Layout.getInstance().isUberJar()) { gatherJarsFromJar(builder); } else { ClassLoader cl = ClassLoader.getSystemClassLoader(); @@ -88,6 +89,8 @@ public ModuleSpec findModule(ModuleIdentifier identifier, ModuleLoader delegateL } } catch (IOException e) { throw new ModuleLoadException(e); + } catch (URISyntaxException e) { + throw new ModuleLoadException(e); } builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.modules"))); diff --git a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/BootstrapModuleFinder.java b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/BootstrapModuleFinder.java index c0dab67edc..c44646fc88 100644 --- a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/BootstrapModuleFinder.java +++ b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/BootstrapModuleFinder.java @@ -19,6 +19,7 @@ import org.wildfly.swarm.bootstrap.util.Layout; import java.io.*; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -45,20 +46,22 @@ public ModuleSpec findModule(ModuleIdentifier identifier, ModuleLoader delegateL ModuleSpec.Builder builder = ModuleSpec.build(identifier); try { - if (Layout.isFatJar()) { + if (Layout.getInstance().isUberJar()) { gatherJarsFromJar(builder); } + + builder.addDependency(DependencySpec.createLocalDependencySpec()); + builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.modules"))); + builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.msc"))); + builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.shrinkwrap"))); + builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("javax.api"))); + + return builder.create(); } catch (IOException e) { throw new ModuleLoadException(e); + } catch (URISyntaxException e) { + throw new ModuleLoadException(e); } - - builder.addDependency(DependencySpec.createLocalDependencySpec()); - builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.modules"))); - builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.msc"))); - builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("org.jboss.shrinkwrap"))); - builder.addDependency(DependencySpec.createModuleDependencySpec(ModuleIdentifier.create("javax.api"))); - - return builder.create(); } protected void gatherJarsFromJar(ModuleSpec.Builder builder) throws IOException { diff --git a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ClasspathModuleFinder.java b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ClasspathModuleFinder.java index 0bf308b82e..654a90c9ff 100644 --- a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ClasspathModuleFinder.java +++ b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/modules/ClasspathModuleFinder.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import org.jboss.modules.Environment; import org.jboss.modules.ModuleFinder; @@ -37,36 +38,42 @@ public class ClasspathModuleFinder implements ModuleFinder { public ModuleSpec findModule(ModuleIdentifier identifier, ModuleLoader delegateLoader) throws ModuleLoadException { final String path = "modules/" + identifier.getName().replace('.', '/') + "/" + identifier.getSlot() + "/module.xml"; - ClassLoader cl = Layout.getBootstrapClassLoader(); - InputStream in = cl.getResourceAsStream(path); - - if (in == null && cl != ClasspathModuleFinder.class.getClassLoader()) { - in = ClasspathModuleFinder.class.getClassLoader().getResourceAsStream(path); - } + try { + ClassLoader cl = Layout.getInstance().getBootstrapClassLoader(); + InputStream in = cl.getResourceAsStream(path); - if (in == null) { - return null; - } + if (in == null && cl != ClasspathModuleFinder.class.getClassLoader()) { + in = ClasspathModuleFinder.class.getClassLoader().getResourceAsStream(path); + } - ModuleSpec moduleSpec = null; - try { - moduleSpec = ModuleXmlParserBridge.parseModuleXml(new ModuleXmlParserBridge.ResourceRootFactoryBridge() { - @Override - public ResourceLoader createResourceLoader(final String rootPath, final String loaderPath, final String loaderName) throws IOException { - return Environment.getModuleResourceLoader(rootPath, loaderPath, loaderName); - } - }, "/", in, path.toString(), delegateLoader, identifier); + if (in == null) { + return null; + } - } catch (IOException e) { - throw new ModuleLoadException(e); - } finally { + ModuleSpec moduleSpec = null; try { - in.close(); + moduleSpec = ModuleXmlParserBridge.parseModuleXml(new ModuleXmlParserBridge.ResourceRootFactoryBridge() { + @Override + public ResourceLoader createResourceLoader(final String rootPath, final String loaderPath, final String loaderName) throws IOException { + return Environment.getModuleResourceLoader(rootPath, loaderPath, loaderName); + } + }, "/", in, path.toString(), delegateLoader, identifier); + } catch (IOException e) { throw new ModuleLoadException(e); + } finally { + try { + in.close(); + } catch (IOException e) { + throw new ModuleLoadException(e); + } } + return moduleSpec; + } catch (IOException e) { + throw new ModuleLoadException(e); + } catch (URISyntaxException e) { + throw new ModuleLoadException(e); } - return moduleSpec; } } diff --git a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/util/Layout.java b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/util/Layout.java index 3e197e1808..0b61c53f45 100644 --- a/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/util/Layout.java +++ b/bootstrap/src/main/java/org/wildfly/swarm/bootstrap/util/Layout.java @@ -22,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.CodeSource; import java.util.Enumeration; import java.util.Properties; import java.util.jar.JarFile; @@ -37,9 +38,68 @@ */ public class Layout { - private static ClassLoader BOOTSTRAP_CLASSLOADER = null; + private static Layout INSTANCE; - public static boolean isFatJar() throws IOException { + + private final Path root; + + private final boolean uberJar; + + private ClassLoader bootstrapClassLoader; + + public static Layout getInstance() throws IOException, URISyntaxException { + if (INSTANCE == null) { + INSTANCE = new Layout(Layout.class.getProtectionDomain().getCodeSource()); + } + return INSTANCE; + } + + Layout(CodeSource codeSource) throws IOException, URISyntaxException { + this.root = determineRoot(codeSource); + this.uberJar = determineIfIsUberJar(); + } + + public Path getRoot() { + return this.root; + } + + public boolean isUberJar() { + return this.uberJar; + } + + public Manifest getManifest() throws IOException { + Path root = getRoot(); + if (isUberJar()) { + try (JarFile jar = new JarFile(root.toFile())) { + ZipEntry entry = jar.getEntry("META-INF/MANIFEST.MF"); + if (entry != null) { + InputStream in = jar.getInputStream(entry); + return new Manifest(in); + } + } + } + + return null; + } + + public synchronized ClassLoader getBootstrapClassLoader() throws ModuleLoadException { + if ( this.bootstrapClassLoader == null ) { + this.bootstrapClassLoader = determineBootstrapClassLoader(); + } + return this.bootstrapClassLoader; + } + + + private Path determineRoot(CodeSource codeSource) throws IOException, URISyntaxException { + URL location = codeSource.getLocation(); + if (location.getProtocol().equals("file")) { + return Paths.get(location.toURI()); + } + + throw new IOException("Unable to determine root"); + } + + private boolean determineIfIsUberJar() throws IOException { Path root = getRoot(); if (Files.isRegularFile(root)) { @@ -54,10 +114,10 @@ public static boolean isFatJar() throws IOException { } Enumeration names = (Enumeration) props.propertyNames(); - while ( names.hasMoreElements() ) { + while (names.hasMoreElements()) { String name = names.nextElement(); String value = props.getProperty(name); - if ( System.getProperty( name ) == null ) { + if (System.getProperty(name) == null) { System.setProperty(name, value); } } @@ -71,44 +131,14 @@ public static boolean isFatJar() throws IOException { } - public static Path getRoot() throws IOException { - URL location = Layout.class.getProtectionDomain().getCodeSource().getLocation(); - if (location.getProtocol().equals("file")) { - try { - return Paths.get(location.toURI()); - } catch (URISyntaxException e) { - throw new IOException(e); - } + private ClassLoader determineBootstrapClassLoader() throws ModuleLoadException { + try { + return Module.getBootModuleLoader().loadModule(ModuleIdentifier.create("org.wildfly.swarm.bootstrap")).getClassLoader(); + } catch (ModuleLoadException e) { + return Layout.class.getClassLoader(); } - - throw new IOException("Unable to determine root"); } - public static Manifest getManifest() throws IOException { - Path root = getRoot(); - if (isFatJar()) { - try (JarFile jar = new JarFile(root.toFile())) { - ZipEntry entry = jar.getEntry("META-INF/MANIFEST.MF"); - if (entry != null) { - InputStream in = jar.getInputStream(entry); - return new Manifest(in); - } - } - } - return null; - } - public synchronized static ClassLoader getBootstrapClassLoader() throws ModuleLoadException { - if (BOOTSTRAP_CLASSLOADER == null) { - try { - BOOTSTRAP_CLASSLOADER = Module.getBootModuleLoader().loadModule(ModuleIdentifier.create("org.wildfly.swarm.bootstrap")).getClassLoader(); - } catch (ModuleLoadException e) { - BOOTSTRAP_CLASSLOADER = Layout.class.getClassLoader(); - } catch (Throwable t) { - t.printStackTrace(); - } - } - return BOOTSTRAP_CLASSLOADER; - } } diff --git a/bootstrap/src/test/java/org/wildfly/swarm/bootstrap/util/LayoutTest.java b/bootstrap/src/test/java/org/wildfly/swarm/bootstrap/util/LayoutTest.java new file mode 100644 index 0000000000..6c0ad789c5 --- /dev/null +++ b/bootstrap/src/test/java/org/wildfly/swarm/bootstrap/util/LayoutTest.java @@ -0,0 +1,38 @@ +package org.wildfly.swarm.bootstrap.util; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.junit.Test; +import static org.fest.assertions.Assertions.assertThat; + +/** + * @author Bob McWhirter + */ +public class LayoutTest { + + @Test + public void testSingletoness() throws Exception { + assertThat( Layout.getInstance() ).isSameAs( Layout.getInstance() ); + } + + @Test + public void testNotUberJar() throws Exception { + Layout layout = Layout.getInstance(); + assertThat( layout.isUberJar() ).isFalse(); + } + + @Test + public void testBootstrapClassLoader() throws Exception { + Layout layout = Layout.getInstance(); + assertThat( layout.getBootstrapClassLoader() ).isSameAs( Layout.class.getClassLoader() ); + } + + @Test + public void testGetManifest() throws Exception { + Layout layout = Layout.getInstance(); + + System.err.println( layout.getManifest() ); + + } +} diff --git a/pom.xml b/pom.xml index a200d2cb3f..e55fe869fb 100644 --- a/pom.xml +++ b/pom.xml @@ -170,6 +170,12 @@ junit test + + org.easytesting + fest-assert + 1.4 + test +