From c9f934fccc9f28e31e0a0a8a6c67c145612de7c5 Mon Sep 17 00:00:00 2001 From: Kabir Khan Date: Tue, 8 Nov 2016 17:05:27 +0000 Subject: [PATCH] [WFCORE-1941] Make it possible to add single child first classes from jars --- .../test/ChildFirstClassLoaderBuilder.java | 32 +++++++++++++---- .../test/ChildFirstClassLoadingTest.java | 35 ++++++++++++++++++- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/model-test/src/main/java/org/jboss/as/model/test/ChildFirstClassLoaderBuilder.java b/model-test/src/main/java/org/jboss/as/model/test/ChildFirstClassLoaderBuilder.java index 9ac45163943..106053d80cc 100644 --- a/model-test/src/main/java/org/jboss/as/model/test/ChildFirstClassLoaderBuilder.java +++ b/model-test/src/main/java/org/jboss/as/model/test/ChildFirstClassLoaderBuilder.java @@ -39,6 +39,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.jar.JarFile; import java.util.regex.Pattern; import org.eclipse.aether.collection.DependencyCollectionException; @@ -283,34 +284,53 @@ public URLClassLoader build() { try { File file = new File(entry.getKey().toURI()); if (file.isDirectory()) { - addParentFirstPatternsFromDirectory(file, "", childFirstNames); + addParentFirstPatternsFromDirectory(file, ""); + } else if (file.getName().endsWith(".jar")){ + addParentFirstPatternsFromJar(file); } else { //TODO - implement something like addParentFirstPatternsFromJar if that becomes needed throw new IllegalStateException("Single class exclusions from jar files is not working: " + entry); } } catch (URISyntaxException e) { throw new IllegalStateException(e); + } catch (IOException e) { + throw new IllegalStateException(e); } } ClassLoader parent = this.getClass().getClassLoader() != null ? this.getClass().getClassLoader() : null; return new ChildFirstClassLoader(parent, parentFirst, childFirst, parentExclusionFilter, classloaderURLs.toArray(new URL[classloaderURLs.size()])); } - private void addParentFirstPatternsFromDirectory(File directory, String prefix, Set childFirstClassNames) { + private void addParentFirstPatternsFromDirectory(File directory, String prefix) { for (File file : directory.listFiles()) { if (file.isDirectory()) { - addParentFirstPatternsFromDirectory(file, prefix +file.getName() + ".", childFirstClassNames); + addParentFirstPatternsFromDirectory(file, prefix + file.getName() + "."); } else { final String fileName = file.getName(); if (fileName.endsWith(".class")) { - //TODO we can optimize this by adding parentFirst patterns for the whole package as long as - String className = prefix + file.getName().substring(0, fileName.length() - ".class".length()); - parentFirst.add(compilePattern(className)); + parentFirst.add(compilePattern(trimDotClass(prefix + fileName))); } } } } + private void addParentFirstPatternsFromJar(File jar) throws IOException { + JarFile jarFile = new JarFile(jar); + + jarFile.stream() + .filter(jarEntry -> !jarEntry.isDirectory() && jarEntry.getName().endsWith(".class")) + .map(jarEntry -> compileJarEntryPattern(trimDotClass(jarEntry.getName()))) + .forEach(pattern -> parentFirst.add(pattern)); + } + + private String trimDotClass(String fileName) { + return fileName.substring(0, fileName.length() - ".class".length()); + } + + private Pattern compileJarEntryPattern(String pattern) { + return compilePattern(pattern.replace("/", ".")); + } + private Pattern compilePattern(String pattern) { return Pattern.compile(pattern.replace(".", "\\.").replace("*", ".*")); } diff --git a/model-test/src/test/java/org/jboss/as/model/test/ChildFirstClassLoadingTest.java b/model-test/src/test/java/org/jboss/as/model/test/ChildFirstClassLoadingTest.java index 64349419c04..277a139f82f 100644 --- a/model-test/src/test/java/org/jboss/as/model/test/ChildFirstClassLoadingTest.java +++ b/model-test/src/test/java/org/jboss/as/model/test/ChildFirstClassLoadingTest.java @@ -20,6 +20,7 @@ */ package org.jboss.as.model.test; +import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.HashSet; @@ -29,6 +30,9 @@ import org.jboss.as.model.test.api.SingleChildFirst2; import org.jboss.as.model.test.api.SingleParentFirst; import org.jboss.as.model.test.api.Welcome; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.impl.base.exporter.zip.ZipExporterImpl; import org.junit.Assert; import org.junit.Test; @@ -65,7 +69,7 @@ public void testWithExclusion() throws Exception { } @Test - public void testSingleClassFromTests() throws Exception { + public void testSingleClassFromDirectory() throws Exception { ChildFirstClassLoaderBuilder builder = new ChildFirstClassLoaderBuilder(false); builder.addSingleChildFirstClass(SingleChildFirst1.class, SingleChildFirst2.class); ClassLoader loader = builder.build(); @@ -78,4 +82,33 @@ public void testSingleClassFromTests() throws Exception { clazz = loader.loadClass(ChildFirstClassLoadingTest.class.getName()); Assert.assertNotSame(loader, clazz.getClassLoader()); } + + @Test + public void testSingleClassFromJar() throws Exception { + JavaArchive jar = ShrinkWrap.create(JavaArchive.class, "single-class-from-jar-test.jar") + .addClasses(SingleChildFirst1.class, SingleChildFirst2.class, SingleParentFirst.class); + String tempDir = System.getProperty("java.io.tmpdir"); + + File file = new File(tempDir + File.separator + jar.getName()); + try { + new ZipExporterImpl(jar).exportTo(file, true); + URLClassLoader tmp = new ChildFirstClassLoaderBuilder(false) + .addURL(file.toURI().toURL()) + .build(); + Class scf1 = tmp.loadClass(SingleChildFirst1.class.getName()); + Assert.assertSame(tmp, scf1.getClassLoader()); + Class scf2 = tmp.loadClass(SingleChildFirst2.class.getName()); + Assert.assertSame(tmp, scf2.getClassLoader()); + + URLClassLoader loader = new ChildFirstClassLoaderBuilder(false) + .addSingleChildFirstClass(scf1, scf2) + .build(); + Assert.assertSame(loader, loader.loadClass(SingleChildFirst1.class.getName()).getClassLoader()); + Assert.assertSame(loader, loader.loadClass(SingleChildFirst2.class.getName()).getClassLoader()); + Assert.assertNotSame(loader, loader.loadClass(SingleParentFirst.class.getName()).getClassLoader()); + loader.close(); + } finally { + file.delete(); + } + } }