View Full Version : Jackrabbit, JDO, JCA with Jencks, and Tomcat
markds75
Mar 22nd, 2006, 04:34 AM
So I've got Jackrabbit and JDO configured and working in my project. Everything works great, except that Jackrabbit didn't participate in the transactions with JDO. This may be a problem for data integrity in my app, so I've decided to move to JCA. Since I'd like to stay with Tomcat - this seems to be the only "heavy duty" J2EE feature I need - I've been trying to get Jencks configured inside my app. And that has worked well also, except that I'm getting an explosion of database connections. Each time a file of unit tests executes, I see two more database connections pop up, and they don't close until maven exits. This means that by the end of my unit tests, I'm using over 56 database connections, and have only a handful of them left. (In fact, my site target, which uses cobertura for coverage analysis, deadlocks when trying to run its instrumented versions of the unit tests because there are no database connections left.) I've tried changing the pooling options to use only one connection (I'd been using 2), but that had no affect. Any ideas as to what might cause this?
I'm also confused as to why JNDI isn't used to access the repository with Jencks, or if it can be, how that's done.
Costin, you've previously expressed a preference for Jencks over JOTM; can you tell me why? I ask because I found Matt Raible's recent post that details how to set JOTM up so that it works in Tomcat and in Unit tests. I haven't seen any such articles for Jencks.
The other question I have to ask is, should I just bite the bullet and move from Tomcat to a full J2EE app server like JBoss or Geronimo? Would that be a less painful approach?
Thanks,
Mark
Costin Leau
Mar 22nd, 2006, 05:33 AM
I'm not sure why you get such a spike in the db connections - it might be jackrabbit but also jencks. jencks is not a transaction manager like JOTM - you can use it with JOTM or with Geronimo TM though the latter has real XA recovery capabilities. You can also read the comments on Matt Raible's blog from Colin Sampaleanu - using a XA transaction manager doesn't mean you have XA support.
You can move to JBoss or Geronimo but you will find that is it's easier working with Tomcat. My advice is to spend more time on tunning your custom made stack and see where the problem lies. I plan to do an tweak the JCR support for the release (including making the samples work) and I will keep an eye out on your problem - it would be good to know what exactly causes the issue.
Have you used the jackrabbit mailing list?
markds75
Mar 22nd, 2006, 06:15 AM
Yeah, after reading more details from Matt and Colin's exchange, it definitely appears that JOTM isn't where I should be going. As for having XA support, it is my understanding that Jencks supports it, JDO (Kodo's 4.0 Early Access 4 currently) supports it, Jackrabbit's JCA package supports it, and the database I'm using (PostgreSQL 8.1, with JDBC driver 8.1-405) supports it. So I think that means the whole stack is covered.
I did post this question to the Jackrabbit group and someone said they got Jackrabbit and JCA to work with Glassfish, but didn't know anything about Jencks.
My biggest problem is that I have no idea where to even begin tracking this down. If you have any advice, I sure could use it.
Costin Leau
Mar 22nd, 2006, 07:55 AM
Turn on logging and see who is creating the connections and why aren't they reused. Search for advice on Jencks lists also.
markds75
Mar 22nd, 2006, 08:14 PM
Well the Jencks mailing lists seem to be dead; the archives show nothing for months (but that includes my post from yesterday, so maybe the archives are just broken). I've posted to the user forum I found, but got no response yet.
Interestingly, this appears to be an issue specific to jencks. I configured some tests, one set that used only JDO, and the other that used only Jackrabbit. The same behavior occurs in both cases, with expanding database connections that don't get released until maven exits.
I posted my configuration on the Jencks forum (http://forums.activemq.org/posts/list/0/584.page). If you have any familiarity with it and have the time, I'd appreciate it if you could check it over.
Thanks again Costin.
markds75
Mar 22nd, 2006, 08:32 PM
Wow, so I just tried something else... I tried changing my JDO tests from the JtaTransactionManager and Jencks, back to Spring's built-in JdoTransactionManager. And I got the same behavior. I'm going to go post a question over on the Data Access forum to see if anyone has ideas about this. It may have nothing to do with Jencks after all.
Costin Leau
Mar 23rd, 2006, 02:24 AM
That's good to hear - what is your configuration? what datasource are you using and how do you delimit transactions? what is your JDO test? you might have a problem with not closing connections/transactions.
markds75
Mar 23rd, 2006, 03:18 AM
This is my entire configuration for the tests that are failing (they're JDO only, no JCR/Jackrabbit at all).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Define the DAO Utility class. -->
<bean id="daoUtil" class="edu.ucsc.whisper.core.dao.JdoDaoUtil" />
<!-- DAO Transaction beans ================================================== ====================-->
<!-- The global transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory">
<ref local="persistenceManagerFactory" />
</property>
</bean>
<!-- DAO JCA Configuration beans ================================================== ==============-->
<bean id="persistenceManagerFactory"
class="org.springframework.orm.jdo.LocalPersistenceManage rFactoryBean">
<property name="configLocation">
<value>classpath:jdo.properties</value>
</property>
</bean>
<!-- The generic DAO Transaction Proxy bean. All DAO instances are children of this bean. -->
<bean id="daoTransactionProxy"
class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean"
abstract="true">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="store*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="aclDao" parent="daoTransactionProxy">
<property name="target" ref="aclDaoTarget" />
</bean>
<bean id="aclDaoTarget" class="edu.ucsc.whisper.core.dao.JdoAclDao">
<property name="persistenceManagerFactory">
<ref local="persistenceManagerFactory"/>
</property>
</bean>
</beans>
The only transactions are in the setup and tear down. The actual test functions just sleep so I have time to watch the database connections in top.
public class JdoTransactionTest
extends AbstractDependencyInjectionSpringContextTests
{
protected PlatformTransactionManager transactionManager;
...
protected final void onSetUp() throws Exception {
this.complete = !this.defaultRollback;
onSetUpBeforeTransaction();
if (this.transactionManager != null) {
// start a transaction
this.transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
if (logger.isInfoEnabled()) {
logger.info("Began transaction: transaction manager [" + this.transactionManager + "]; defaultRollback "
+ this.defaultRollback);
}
}
else {
logger.info("No transaction manager set: tests will NOT run within a transaction");
}
onSetUpInTransaction();
}
protected void onSetUpBeforeTransaction() throws Exception {
Authority[] grantedAuthorities = {
new DefaultAuthority( Authority.USER_ROLE_AUTHORITY ),
new DefaultAuthority( Authority.ADMIN_ROLE_AUTHORITY ) };
Authentication fakeAuth = new UsernamePasswordAuthenticationToken(
"fake_admin", "fake_password", grantedAuthorities );
SecurityContextHolder.getContext().setAuthenticati on( fakeAuth );
if( transactionManager != null )
{
// The Kodo JDO implementation requires a static function to return the transaction manager
// when not running in a full J2EE app server. Set the transaction manager for that will
// be provided to Kodo JDO now, before any calls that might trigger JDO occur.
try
{
JtaTransactionManager jtaTransactionManager =
(JtaTransactionManager) transactionManager;
KodoTransactionAccess.setTransactionManager(
jtaTransactionManager.getTransactionManager() );
}
catch( ClassCastException e )
{
}
logger.info( "Starting transaction for setUpRequiredAuthorities." );
this.transactionStatus =
transactionManager.getTransaction( new DefaultTransactionDefinition() );
if( transactionStatus != null )
{
logger.info( "Transaction for setUpRequiredAuthorities has been created." );
AclDao aclDao = (AclDao) applicationContext.getBean( "aclDao" );
if( aclDao == null )
{
throw( new IllegalStateException(
"Could not get AclDao instance required for setUpRequiredAuthorities." ) );
}
for( int i = 0; i < Authority.REQUIRED_AUTHORITIES.length; i++ )
{
if( aclDao.getAuthorityWithName( Authority.REQUIRED_AUTHORITIES[ i ] ) != null )
{
logger.warn(
"The required Authority " + Authority.REQUIRED_AUTHORITIES[ i ]
+ " is already present in the database. This suggests that a"
+ " previous test did not clean up properly. All "
+ " Authority.REQUIRED_AUTHORITIES must be deleted at the end of"
+ " a test case." );
}
else
{
DefaultAuthority auth =
new DefaultAuthority( Authority.REQUIRED_AUTHORITIES[ i ] );
aclDao.storeAuthority( auth );
}
}
try
{
transactionManager.commit( transactionStatus );
}
finally
{
transactionStatus = null;
}
}
else
{
}
logger.info( "Finished transaction for setUpRequiredAuthorities." );
}
else
{
logger.info( "Could not create transaction for setUpRequiredAuthorities."
+ " Superclass' transactionManager is null." );
}
SecurityContextHolder.getContext().setAuthenticati on( null );
}
protected void onTearDownAfterTransaction() throws Exception {
if( transactionManager != null )
{
logger.info( "Starting transaction for tearDownRequiredAuthorities." );
TransactionStatus status =
transactionManager.getTransaction( new DefaultTransactionDefinition() );
if( status != null )
{
logger.info( "Transaction for tearDownRequiredAuthorities has been created." );
AclDao aclDao = (AclDao) applicationContext.getBean( "aclDao" );
if( aclDao == null )
{
throw( new IllegalStateException( "Could not get AclDao instance "
+ "required for tearDownRequiredAuthorities." ) );
}
for( int i = 0; i < Authority.REQUIRED_AUTHORITIES.length; i++ )
{
Authority auth =
aclDao.getAuthorityWithName( Authority.REQUIRED_AUTHORITIES[ i ] );
if( auth == null )
{
throw( new IllegalStateException(
"The required Authority " + Authority.REQUIRED_AUTHORITIES[ i ]
+ " is not present in the database. This suggests that a unit test"
+ " deleted it prematurely. All Authority.REQUIRED_AUTHORITIES must"
+ " not be deleted until the end of a test case." ) );
}
aclDao.deleteAuthority( auth );
}
try
{
transactionManager.commit( status );
}
finally
{
status = null;
}
}
else
{
}
logger.info( "Finished transaction for tearDownRequiredAuthorities." );
}
else
{
logger.info( "Could not create transaction for tearDownRequiredAuthorities."
+ " Superclass' transactionManager is null." );
}
}
If it looks familiar, its because I based this class on AbstractTransactionalSpringContextTests. I followed the same pattern in my setup and teardown for creating and committing transactions as they use to create transactions for the tests themselves. I've been looking at the code and the docs to see if I might have made a mistake, but I'm not seeing anything jump out at me. Do you?
Thanks Costin!
markds75
Mar 23rd, 2006, 03:53 AM
I just discovered the TransactionTemplate and changed my setup and tear down code to use it, but the results are the same... connections still growing. And now all transaction demarcation is done within spring, either through the method interceptors wired into the JDO-based AclDao object, or programatically in setup and tear down with the TransactionTemplate.
markds75
Mar 23rd, 2006, 06:00 AM
And the answer seems to have nothing to do with transactions or database connections. It seems it was all about memory, and me running out of it with so many running database processes. I posted the details in another forum (http://forum.springframework.org/showpost.php?p=55598&postcount=2) for anyone interested.
robvarga
Sep 4th, 2006, 07:18 PM
Yeah, after reading more details from Matt and Colin's exchange, it definitely appears that JOTM isn't where I should be going. As for having XA support, it is my understanding that Jencks supports it, JDO (Kodo's 4.0 Early Access 4 currently) supports it, Jackrabbit's JCA package supports it, and the database I'm using (PostgreSQL 8.1, with JDBC driver 8.1-405) supports it. So I think that means the whole stack is covered.
I did post this question to the Jackrabbit group and someone said they got Jackrabbit and JCA to work with Glassfish, but didn't know anything about Jencks.
My biggest problem is that I have no idea where to even begin tracking this down. If you have any advice, I sure could use it.
Hi Mark,
Just for the record: Postgresql does NOT support XA. It gives you 2PC but that is not yet XA. It is a long way from XA, yet.
Best regards,
Robert
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.