I've got most of our demos ported across to use Arquillian, but came across a problem
when running the ds example embedded:
org.jboss.util.NestedSQLException: Error checking for a transaction.; - nested throwable:
(java.lang.reflect.UndeclaredThrowableException); - nested throwable:
(org.jboss.jca.common.JBossResourceException: Error checking for a transaction.; - nested
throwable: (java.lang.reflect.UndeclaredThrowableException))
at
org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:115)
at org.jboss.as.test.demos.ds.DsTestCase.testDatasource(DsTestCase.java:61)
Arquillian in container
...
Caused by: org.jboss.jca.common.JBossResourceException: Error checking for a transaction.;
- nested throwable: (java.lang.reflect.UndeclaredThrowableException)
at
org.jboss.jca.common.JBossResourceException.rethrowAsResourceException(JBossResourceException.java:60)
at
org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl.getManagedConnection(TxConnectionManagerImpl.java:363)
at
org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:428)
at
org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:109)
... 81 more
Caused by: java.lang.reflect.UndeclaredThrowableException
at org.jboss.jca.common.JBossResourceException.process(JBossResourceException.java:216)
at
org.jboss.jca.common.JBossResourceException.<init>(JBossResourceException.java:112)
... 85 more
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of
org/jboss/modules/ModuleClassLoader) previously initiated loading for a different type
with name "javax/transaction/TransactionManager"
at
org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl.getManagedConnection(TxConnectionManagerImpl.java:350)
... 83 more
This does not occur when running it normally using demos against a normal standalone
instance.
In embedded on startup javax.transaction.TransactionManager gets loaded twice on startup
1) module:org.jboss.jts:main
2) org.jboss.jts.integration:main
In both these cases the defining classloader is the system classloader.
Then when running the deployed example it gets loaded using
module:org.jboss.ironjacamar.impl:main which in turn gets the class from
module:javax.transaction.api:main which has its own resource loader.
When starting up a normal standalone instance, in all cases the defining classloader is
the javax.transaction.api module classloader. In both embedded and standalone scenarios,
loading this class from the javax.transaction.api module gets two resource loaders. The
SystemLocalLoader, and a module local loader for javax.transaction.api. The
javax/transaction path is added to SystemLocalLoader since the JDK includes a few classes
there (InvalidTransactionException, TransactionRequiredException,
TransactionRolledbackException), so it is added from -Dsun.boot.class.path.
-In the standalone case the SystemLocalLoader is not able to load the TM class since it
was never on the system classpath, so it loads it from the module loader.
-In the embedded case the SystemLocalLoader is able to load the TM class since it is on
the app classpath, so the module loader never gets hit.
Before initializing modules -Djava.class.path is set to null, and org.jboss.modules and
org.jboss.logging is added to Module.systemPackages.
I have patched jboss-modules to create a filter for this case here:
https://github.com/kabir/jboss-modules/tree/Beta11-patch-filter but David might have a
better idea?
If I start the embedded server with this snapshot and the following system properties, the
ds testcase works fine
SecurityActions.setSystemProperty("module.include.path",
"javax/transaction/InvalidTransactionException,javax/transaction/TransactionRequiredException,javax/transaction/TransactionRolledbackException");
SecurityActions.setSystemProperty("module.exclude.path",
"javax/transaction/**");
This fix is only required for embedded, and will not have any effect during runtime of the
standalone server (apart from an extra == null check).
A simpler way to configure this might be to just specify the names of filtered packages,
e.g.
-Dmodule.filtered.paths=javax.transaction,javax.transaction.xa
and then let the SystemLocalLoader intialization internally build up the excludes/includes
depending on what it finds on
the bootstrap path, so the module.filtered.paths becomes the following filter
{
excludes={javax/transaction,javax/transaction/},
includes={javax/transaction/InvalidTransactionException,javax/transaction/TransactionRequiredException,javax/transaction/TransactionRolledbackException}
}
Apart from these packages split between sun.boot.class.path and the modules classpath,
embedded modules is exactly the same as standalone modules.
Cheers,
Kabir