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
This commit is contained in:
Felix Becker 2015-03-31 17:05:47 -04:00 committed by Clebert Suconic
parent dea60ed3b6
commit 41d519f8a8
2 changed files with 95 additions and 10 deletions

View File

@ -16,14 +16,6 @@
*/ */
package org.apache.activemq.core.config; 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 javax.management.MBeanServer;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
@ -32,6 +24,14 @@ import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; 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 * 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 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) if (url == null)
{ {

View File

@ -16,6 +16,12 @@
*/ */
package org.apache.activemq.core.config.impl; 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 java.util.Collections;
import org.apache.activemq.api.core.BroadcastGroupConfiguration; import org.apache.activemq.api.core.BroadcastGroupConfiguration;
@ -38,6 +44,9 @@ import org.junit.Test;
public class FileConfigurationTest extends ConfigurationImplTest public class FileConfigurationTest extends ConfigurationImplTest
{ {
private final String fullConfigurationName = "ConfigurationTest-full-config.xml";
@Override @Override
@Test @Test
public void testDefaults() 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 @Override
protected Configuration createConfiguration() throws Exception protected Configuration createConfiguration() throws Exception
{ {
FileConfiguration fc = new FileConfiguration(); FileConfiguration fc = new FileConfiguration();
FileDeploymentManager deploymentManager = new FileDeploymentManager("ConfigurationTest-full-config.xml"); FileDeploymentManager deploymentManager = new FileDeploymentManager(fullConfigurationName);
deploymentManager.addDeployable(fc); deploymentManager.addDeployable(fc);
deploymentManager.readConfiguration(); deploymentManager.readConfiguration();
return fc; return fc;