From 41d519f8a8da497d1c716fe7820282d77b1ddcac Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Tue, 31 Mar 2015 17:05:47 -0400 Subject: [PATCH] Use the context class loader in FileConfiguration Avoid loading problems of file configurations in servlet containers when packaging the hornetq libs not in the war file (e.g. in tomcat/lib/) This was done with some refactoring from Clebert. cherry-picking this from https://github.com/hornetq/hornetq/pull/1999 --- .../core/config/FileDeploymentManager.java | 26 +++--- .../config/impl/FileConfigurationTest.java | 79 ++++++++++++++++++- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/activemq-server/src/main/java/org/apache/activemq/core/config/FileDeploymentManager.java b/activemq-server/src/main/java/org/apache/activemq/core/config/FileDeploymentManager.java index 66384bfcfa..8e8f901a62 100644 --- a/activemq-server/src/main/java/org/apache/activemq/core/config/FileDeploymentManager.java +++ b/activemq-server/src/main/java/org/apache/activemq/core/config/FileDeploymentManager.java @@ -16,14 +16,6 @@ */ package org.apache.activemq.core.config; -import org.apache.activemq.core.deployers.Deployable; -import org.apache.activemq.core.server.ActiveMQComponent; -import org.apache.activemq.spi.core.security.ActiveMQSecurityManager; -import org.apache.activemq.utils.XMLUtil; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - import javax.management.MBeanServer; import java.io.InputStreamReader; import java.io.Reader; @@ -32,6 +24,14 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import org.apache.activemq.core.deployers.Deployable; +import org.apache.activemq.core.server.ActiveMQComponent; +import org.apache.activemq.spi.core.security.ActiveMQSecurityManager; +import org.apache.activemq.utils.XMLUtil; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + /** * ised to build a set of ActiveMQComponents from a set of Deployables pulled out of the configuration file */ @@ -58,7 +58,15 @@ public class FileDeploymentManager */ public void readConfiguration() throws Exception { - URL url = getClass().getClassLoader().getResource(configurationUrl); + URL url; + + url = Thread.currentThread().getContextClassLoader().getResource(configurationUrl); + + if (url == null) + { + // trying a different classloader now + url = getClass().getClassLoader().getResource(configurationUrl); + } if (url == null) { diff --git a/activemq-server/src/test/java/org/apache/activemq/core/config/impl/FileConfigurationTest.java b/activemq-server/src/test/java/org/apache/activemq/core/config/impl/FileConfigurationTest.java index 2375fc1b7d..6f2a689196 100644 --- a/activemq-server/src/test/java/org/apache/activemq/core/config/impl/FileConfigurationTest.java +++ b/activemq-server/src/test/java/org/apache/activemq/core/config/impl/FileConfigurationTest.java @@ -16,6 +16,12 @@ */ package org.apache.activemq.core.config.impl; +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Collections; import org.apache.activemq.api.core.BroadcastGroupConfiguration; @@ -38,6 +44,9 @@ import org.junit.Test; public class FileConfigurationTest extends ConfigurationImplTest { + + private final String fullConfigurationName = "ConfigurationTest-full-config.xml"; + @Override @Test public void testDefaults() @@ -347,12 +356,80 @@ public class FileConfigurationTest extends ConfigurationImplTest } + @Test + public void testContextClassLoaderUsage() throws Exception + { + + final File customConfiguration = File.createTempFile("hornetq-unittest", ".xml"); + + try + { + + // copy working configuration to a location where the standard classloader cannot find it + final Path workingConfiguration = new File(getClass().getResource(File.separator + fullConfigurationName).toURI()).toPath(); + final Path targetFile = customConfiguration.toPath(); + + Files.copy(workingConfiguration, targetFile, StandardCopyOption.REPLACE_EXISTING); + + // build a custom classloader knowing the location of the config created above (used as context class loader) + final URL customConfigurationDirUrl = new URL("file://" + customConfiguration.getParentFile().getAbsolutePath() + File.separator); + final ClassLoader testWebappClassLoader = new URLClassLoader(new URL[]{customConfigurationDirUrl}); + + /* + run this in an own thread, avoid polluting the class loader of the thread context of the unit test engine, + expect no exception in this thread when the class loading works as expected + */ + + final class ThrowableHolder + { + public Exception t = null; + } + + final ThrowableHolder holder = new ThrowableHolder(); + + final Thread webappContextThread = new Thread(new Runnable() + { + @Override + public void run() + { + FileConfiguration fileConfiguration = new FileConfiguration(); + + try + { + FileDeploymentManager deploymentManager = new FileDeploymentManager(customConfiguration.getName()); + deploymentManager.addDeployable(fileConfiguration); + deploymentManager.readConfiguration(); + } + catch (Exception e) + { + holder.t = e; + } + } + }); + + webappContextThread.setContextClassLoader(testWebappClassLoader); + + webappContextThread.start(); + webappContextThread.join(); + + if (holder.t != null) + { + fail("Exception caught while loading configuration with the context class loader: " + holder.t.getMessage()); + } + + } + finally + { + customConfiguration.delete(); + } + } + @Override protected Configuration createConfiguration() throws Exception { FileConfiguration fc = new FileConfiguration(); - FileDeploymentManager deploymentManager = new FileDeploymentManager("ConfigurationTest-full-config.xml"); + FileDeploymentManager deploymentManager = new FileDeploymentManager(fullConfigurationName); deploymentManager.addDeployable(fc); deploymentManager.readConfiguration(); return fc;