axis-java-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Thorsten Schöning (JIRA) <j...@apache.org>
Subject [jira] [Created] (AXIS2-5792) Add a more strict service first class loader?
Date Sat, 25 Jun 2016 06:32:16 GMT
Thorsten Schöning created AXIS2-5792:
----------------------------------------

             Summary: Add a more strict service first class loader?
                 Key: AXIS2-5792
                 URL: https://issues.apache.org/jira/browse/AXIS2-5792
             Project: Axis2
          Issue Type: Improvement
          Components: deployment
    Affects Versions: 1.7.3, 1.6.3
         Environment: Windows 8.1 x64 Prof., Tomcat 7.0.68, JDK 1.8.0_92 x64
            Reporter: Thorsten Schöning


I have a web service based on Axis2 1.6.3 currently and Axis2 provides httpcore-4.0. In my
service I want to use HttpCore 4.4.5 and HttpClient 4.5.2 and both core packages provide the
class BasicLineFormatter, but some classes new in HttpCore 4.4.5 need a newer version of that
class than HttpCore 4.0 can provide. This leads to exceptions like the following:

{CODE}
Caused by: java.lang.NoSuchFieldError: INSTANCE
	at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:53)
	at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:57)
	at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<clinit>(DefaultHttpRequestWriterFactory.java:47)
	at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:82)
	at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:95)
	at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:104)
	at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<clinit>(ManagedHttpClientConnectionFactory.java:62)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$InternalConnectionFactory.<init>(PoolingHttpClientConnectionManager.java:572)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:174)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:158)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:149)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:125)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:116)
{CODE}

{CODE}
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.impl.conn.ManagedHttpClientConnectionFactory
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$InternalConnectionFactory.<init>(PoolingHttpClientConnectionManager.java:572)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:174)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:158)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:149)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:125)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:116)
{CODE}

The problem is that when my service is about to be started, Axis2 used the BasicLineFormatter
(indirectly) on its own already, loaded it and DeploymentClassLoader.loadClass finds that
class in its own cache afterwards. This way the newer version of that class bundled with my
service will never be used by default. Because the class is in the cache, using "EnableChildFirstClassLoading"
doesn't change a thing here because the cache is always queried first.

I could work around that problem by changing the class loader of my service in ServiceLifeCycle.startUp:
The new class loader is just another instance of DeploymentClassLoader which I put all the
URLs needed for Jars and classes and such into, use "EnableChildFirstClassLoading" by default
and provide the already available class loader as the new parent:

{CODE}
class WsAxis2SvcCl extends DeploymentClassLoader
[...]
	private static boolean shouldWrap(AxisService service)
	{
		String	paramValue = (String) service.getParameterValue("EnableSvcFirstClassLoading");
				paramValue = StringUtils.defaultIfBlank(paramValue, "false");

		if (!JavaUtils.isTrueExplicitly(paramValue.trim()))
		{
			return false;
		}

		return true;
	}
[...]
	protected WsAxis2SvcCl(	Set<URL>	urls,
							ClassLoader	parent)
	{
		super(urls.toArray(new URL[urls.size()]), null, parent, true);
	}
[...]
	static void wrapIf(AxisService service)
	{
		if (!WsAxis2SvcCl.shouldWrap(service))
		{
			return;
		}

		ClassLoader	origCl	= service.getClassLoader();
		Path		svcDir	= Axis2ServiceConf.getSvcDir(service);
		Set<URL>	clUrls	= ClNdClassLoaderUrlsProv.getUrlsRe(svcDir.toFile());
		ClassLoader	newCl	= new WsAxis2SvcCl(clUrls, origCl);

		service.setClassLoader(newCl);
	}
{CODE}

This way the classes and jars of my service are always considered first and only things not
found in there are forwarded to the default Axis2 class loader used before. In the end, my
classes using HttpCore 4.4.5 get their BasicLineFormatter and Axis2 keeps using its own. The
"trick" is that DeploymentClassLoader.findLoadedClass only searches the current instance,
no parent or such, and by providing a new instance I get a clean start for loading the service
classes without interfering with the former already present Axis2 loader.

As I understand DeploymentClassLoader, such problems can't be addressed without another classloader
like mine, so I woudl like to suggest exactly such an approach like I implemented now to be
added. As I did already, one could configure the use of that class loader on a per service
level and would therefore don't introduce any problems with backwards compatibility. If interested,
I could provide more of my implementation.

Or is there any other approach I have missed to deal with same classes in incompatible versions
like in my case?




--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: java-dev-unsubscribe@axis.apache.org
For additional commands, e-mail: java-dev-help@axis.apache.org


Mime
View raw message