JCA and Class Loading on WildFly 8.2.0/9.0.0CR2
alashchuk Jun 26, 2015 4:16 PMHello,
I am working on migrating an enterprise application from GlassFish 3.1 to WildFly. The application makes use of a JCA resource adapter, the sole purpose of which is to call a method in a native library. This is mainly to stay in compliance with the Java EE spec, which forbids direct calls to native methods in EJBs. I can confirm that the adapter loads and works correctly on GlassFish and the connection factory exposed by it can be injected as an interface reference into a CDI named bean using the @Resource annotation with the mappedName attribute.
Now moving on to WildFly, the resource adapter deploys correctly and the native library packaged in its RAR is loaded into process space (verified on 64-bit Windows with Sysinternals Process Monitor) from the ephemeral vfs directory created by the container during deployment. However, two things appear broken:
1. Any attempt to inject the connection factory reference into a named bean via its interface results in the following message:
java.lang.IllegalArgumentException: Can not set net.buildinglogix.bdx.npi.api.INativePlatformInterfaceConnectionFactory field net.buildinglogix.test.RABean.factory to net.buildinglogix.bdx.npi.impl.NativePlatformInterfaceConnectionFactory
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:741)
at org.jboss.weld.injection.FieldResourceInjection.injectMember(FieldResourceInjection.java:62)
at org.jboss.weld.injection.AbstractResourceInjection.injectResourceReference(AbstractResourceInjection.java:53)
at org.jboss.weld.util.Beans.injectEEFields(Beans.java:348)
at org.jboss.weld.injection.producer.ResourceInjector$1.proceed(ResourceInjector.java:69)
at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:48)
at org.jboss.weld.injection.producer.ResourceInjector.inject(ResourceInjector.java:72)
at org.jboss.weld.injection.producer.BasicInjectionTarget.inject(BasicInjectionTarget.java:121)
at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:159)
at org.jboss.weld.util.bean.IsolatedForwardingBean.create(IsolatedForwardingBean.java:45)
at org.jboss.weld.context.AbstractContext.get(AbstractContext.java:96)
at org.jboss.weld.context.PassivatingContextWrapper$AbstractPassivatingContextWrapper.get(PassivatingContextWrapper.java:76)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:101)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.get(ContextualInstanceStrategy.java:178)
at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:761)
at org.jboss.weld.el.AbstractWeldELResolver.lookup(AbstractWeldELResolver.java:107)
at org.jboss.weld.el.AbstractWeldELResolver.getValue(AbstractWeldELResolver.java:90)
at org.jboss.as.jsf.injection.weld.ForwardingELResolver.getValue(ForwardingELResolver.java:46)
.
.
Given that NativePlatformInterfaceConnectionFactory implements the INativePlatformInterfaceConnectionFactory, it appears that there is a classloader mismatch between the loaded JCA adapter class and the application calling into it.
2. If the first problem is overcome with the use of dynamic JNDI lookups and reflection, any attempt at calling the native method from the resource adapter code fails with UnsatisfiedLinkError.
I have done some digging around with a debugger and can confirm that the classloader used to load the native library during deployment is NOT the same as the classloader that is used to load the resource adapter classes. Furthermore, when the RA is initialized, the BootstrapContext instance passed to it does indeed have the correct classloader and that classloader correctly references the loaded native library. However, the classloader, which is used to create the RA classes themselves is different, and it does not contain any references to the native library. I believe this to be the source of the issues I listed above.
My question is: does this appear to be a bug, or are there settings in WildFly that define the level of classloader isolation that I need to set somewhere to work around this problem? I verified that if the native library is placed directly on java.library.path and is explicitly loaded with System.loadLibrary in RA initialization code (from my local classloader), the adapter works correctly. However, this is contrary to how the native library loading behavior is defined in JCA spec and may fail in other containers. Looking at the source code of org.jboss.as.connector.deployers.ra.processors.RaNativeProcessor, line 85, all the right steps are being taken, but probably in the wrong classloader. I have tried this both on WildFly 8.2.0.Final and 9.0.0CR2, and the problem exists in both environments.
Any help or insight into these issues will be greatly appreciated.
Thanks in advance,
Alex