Our Craft

Making it better

Posts Tagged ‘JNDI’

XA, JNDI and Bitronix, part 1

Posted by danielmeyer on August 15, 2008

For the past couple few days I’ve been working to update my XA example to use Bitronix Transaction Manager to do the JNDI lookup and transaction management so that my beans files can remain the same (or as much so as possible) for integration testing outside the app server.

The Process

Initial Steps

I followed the instructions for using pre-release versions of BTM with Maven and then went over to the Spring integration instructions:

  • Step 1, copying the jars, is taken care of by Maven;
  • For Step 2, I’m using an Apache Commons BasicDatasource;
  • For steps 3 and 4 I copied the bean definitions from the instructions (but taking out the depends-on attribute since that is supposed to have been fixed).

Trying it out

Let’s run the project as a JUnit test in Eclipse (at first I chuckled in disbelief that that the keyboard shortcut for this is Shift+Alt+X, t, but now it doesn’t seem so bad… ;)

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘queueConnectionFactory’: Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial Related cause: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.apache.commons.dbcp.BasicDataSource] for bean with name ‘jdbcDataSource’ defined in class path resource [applicationContextBitronix.xml]; nested exception is java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource     …

So for starters, I don’t have a JNDI InitialContext, and we can’t find the org.apache.commons.dbcp.BasicDataSource class.

Fixing the DataSource

We’ll start with the BasicDataSource since that’s easy: I need to add that to the pom file:

		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.2</version>
			<scope>test</scope>
		</dependency>

Fixing the JNDI part

Ok, now when I run the project as a JUnit test again, that error went away, but I still get the JNDI NoInitialContextException.  To resolve this one, I’ll need to see how to use Bitronix’s new JNDI support.

Looking around on the Bitronix front page, The JndiXaConnectionFactory documentation is the only JNDI thing I see, and that doesn’t seem to be what I need… but a Google search (poor ask.com — the same search yielded almost no results there) points me to BTM’s Hibernate documentation.  In the section titled Resource Loader way: Creating the datasources, it has this nugget:

Resource Loader JNDI binding
When you configure the Resource Loader to bind datasources to JNDI (by setting the bitronix.tm.resource.bind property to true) it will bind them using the unique name as the JNDI location.

I think this is what we need.  Using the examples from the ResourceLoader page as a starting point, here is my jndi-bitronix.properties file, which I have, not knowing any better, placed in the root of my classpath in src/main/resources in my project:

bitronix.tm.resource.bind=true

resource.ds1.className = oracle.jdbc.xa.client.OracleXADataSource
resource.ds1.uniqueName = java:XAOracleDS
resource.ds1.maxPoolSize = 3
resource.ds1.driverProperties.url = jdbc:oracle:thin:@localhost:1521:XE
resource.ds1.driverProperties.user = myUserName
resource.ds1.driverProperties.password = myPassword

resource.mq1.className = org.activemq.ActiveMQXAConnectionFactory
resource.mq1.uniqueName = java:activemq/QueueConnectionFactory
resource.mq1.maxPoolSize = 2
#resource.mq1.driverProperties.userName = defaultUser
#resource.mq1.driverProperties.password = defaultPassword
resource.mq1.driverProperties.brokerURL = vm://localhost

And here is my new spring-beans-bitronix.xml Spring bean file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
<property name="resourceConfigurationFilename" value="jndi-bitronix.properties" />
	</bean>

	<bean id="BitronixTransactionManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices"
		destroy-method="shutdown" />

	<bean id="JtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
	</bean>
</beans>

Notice on line 9 that we’re pointing the configuration manager to the properties file.

We Fire Up the Test And…

Still a NoInitialContextException.  Come to think of it, I wonder if the order of initialization of these beanfiles is significant.  The <jee:jndi-lookup/> beans in my spring-beans-main.xml and spring-beans-hibernate-SimplePersonDAO.xml beans files would need the JNDI server to be up at the time they’re instantiated… let’s try putting the bitronix beans first in the load-em array and see if that makes a difference:


private static final String[] beanFiles = { "spring-beans-bitronix.xml", "spring-beans-main.xml", "com/example/db/spring-beans-hibernate-SimplePersonDAO.xml" };

//...

new ClassPathXmlApplicationContext(beanFiles);

A Different Error

Now we get this error:

Error creating bean with name ‘btmConfig’ defined in class path resource [spring-beans-bitronix.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder

I thought I had checked our project’s Referenced Libraries and seen the slf4j library in there (from some transitive dependency — I had not added slf4j to our project’s pom file).  Taking another look, I see that I only have slf4j-api.

Hmm, shouldn’t BTM be responsible for its own dependencies?  Looking at the BTM new user guide, I see that the jar is actually slf4j-jdk14-1.4.3.jar, and looking in BTM 1.3-RC2′s pom file, I see that the slf4j-jdk14 artifact is set to optional there:

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.4.3</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

From Maven’s POM Reference, if an artifact is marked optional in a Maven project X, that means that if my project depends on project X, I don’t need that dependency.  In this case, though, it seems that I do need the dependency — so I’ll add it to my pom file thusly:

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.4.3</version>
            <scope>runtime</scope>
        </dependency>

This seems like a bug in BTM’s pom file — seems like slf4j-jdk14 should not be marked optional if it’s actually needed by dependent projects (like mine).

Update 8/15/2008: It’s not a bug.

A First Peep from the BitronixTransactionManager

Hey, hey — this time when I run my project as a JUnit test, I get this in the console:

log4j:WARN No appenders could be found for logger (com.example.startup.StartupSvc).
log4j:WARN Please initialize the log4j system properly.
Aug 14, 2008 10:02:31 AM bitronix.tm.BitronixTransactionManager logVersion
INFO: Bitronix Transaction Manager version 1.3-RC2
Aug 14, 2008 10:02:31 AM bitronix.tm.Configuration buildServerIdArray
INFO: JVM unique ID:

I’ve been getting the log4j warnings since I haven’t made a log4j.properties… but look, BTM says hello!

We’re getting a new error, too:

Error creating bean with name ‘BitronixTransactionManager’ defined in class path resource [spring-beans-bitronix.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public static synchronized bitronix.tm.BitronixTransactionManager bitronix.tm.TransactionManagerServices.getTransactionManager()] threw exception; nested exception is java.lang.NullPointerException

Now, what could getTransactionManager need, that it’s getting a NullPointerException?

[Time passes, and when we rejoin our beleaguered hero...]

Since last time, I set up the log4j properties like this:

log4j.rootLogger=DEBUG, A1
log4j.logger.bitronix.tm=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

I didn’t really see anything that helped though.  Looking at the bitronix.tm.Configuration documentation, I’m not sure that my attempt at setting the resourceConfigurationFilename is working.  Specifically, maybe line 3 of this bean definition is not working as I expect:

    <bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
<property name="resourceConfigurationFilename" value="/jndi-bitronix.properties" />
    </bean>

How else do we tell the Configuration singleton about the properties file, though?

Telling the Configuration singleton about the properties file

The properties file section of the documentation for bitronix.tm.Configuration says that if the properties file is named bitronix-default-config.properties at the root of the classpath, bitronix.tm.Configuration will magically find it.  Let’s try that:

Hey, the error goes away, and for the first time, the BitronixTransactionManager bean and the JtaTransactionManager beans initialize without errors!  Notice especially lines 12 and 13:

0    [main] INFO  com.example.startup.StartupSvc  - Starting up
79   [main] INFO  org.springframework.context.support.ClassPathXmlApplicationContext  - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@480457: display name [org.springframework.context.support.ClassPathXmlApplicationContext@480457]; startup date [Thu Aug 14 12:35:05 EDT 2008]; root of context hierarchy
188  [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader  - Loading XML bean definitions from class path resource [spring-beans-bitronix.xml]
439  [main] INFO  org.springframework.context.support.ClassPathXmlApplicationContext  - Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@480457]: org.springframework.beans.factory.support.DefaultListableBeanFactory@d19bc8
486  [main] INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory  - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@d19bc8: defining beans [btmConfig,BitronixTransactionManager,JtaTransactionManager]; root of factory hierarchy
Aug 14, 2008 12:35:05 PM bitronix.tm.BitronixTransactionManager logVersion
INFO: Bitronix Transaction Manager version 1.3-RC2
Aug 14, 2008 12:35:05 PM bitronix.tm.Configuration buildServerIdArray
INFO: JVM unique ID: <spring-btm>
Aug 14, 2008 12:35:05 PM bitronix.tm.recovery.Recoverer run
INFO: recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 0 resource(s) []
752  [main] INFO  org.springframework.transaction.jta.JtaTransactionManager  - Using JTA UserTransaction: a BitronixTransactionManager with 0 in-flight transaction(s)
768  [main] INFO  org.springframework.transaction.jta.JtaTransactionManager  - Using JTA TransactionManager: a BitronixTransactionManager with 0 in-flight transaction(s)
768  [main] INFO  com.example.startup.StartupSvc  - Shutting down
768  [main] INFO  org.springframework.context.support.ClassPathXmlApplicationContext  - Closing org.springframework.context.support.ClassPathXmlApplicationContext@480457: display name [org.springframework.context.support.ClassPathXmlApplicationContext@480457]; startup date [Thu Aug 14 12:35:05 EDT 2008]; root of context hierarchy
799  [main] INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory  - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@d19bc8: defining beans [btmConfig,BitronixTransactionManager,JtaTransactionManager]; root of factory hierarchy
Aug 14, 2008 12:35:05 PM bitronix.tm.BitronixTransactionManager shutdown
INFO: shutting down Bitronix Transaction Manager

I had commented out the main beans file and the hibernate beans files while I got the BTM beans going… now let’s uncomment those and see what we get…

Still a NoInitialContextException

Hmm, we’re still getting a NoInitialContextException when we try to create the queueConnectionFactory bean based on the JNDI lookup:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘queueConnectionFactory’: Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial

[More time passes...]

Googling this error turned up a chapter called Using JNDI Outside J2EE from the book Teach Yourself J2EE in 21 Days, 2nd Edition, published by Sams.  Says here you need a jndi.properties file in your classpath, and in that file you need a java.naming.factory.initial property set to the name of your initial context factory class.  Hmm, I haven’t been able to find a jndi package in the BTM Javadoc… how ’bout if I check the BTM 1.3-RC2 source code I checked out?  Sure enough, there is a bitronix.tm.jndi package with a BitronixInitialContextFactory class in there.  I was looking at the wrong Javadoc! I was using the “current” BTM javadoc, which doesn’t have the jndi package.  I needed the 1.3 Javadoc.  The explanation at the top of the BitronixInitialContextFactory class assures me that this is all we need in jndi.properties:

<pre>java.naming.factory.initial = bitronix.tm.jndi.BitronixInitialContextFactory</pre>

(Good, because I wasn’t sure what to put for the java.naming.provider.url property mentioned in the book chapter!)

Name Not Found

Ok, now we’ve gotten past the NoInitialContextException to a NameNotFoundException:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘queueConnectionFactory’: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: JNDI object with [java:activemq/QueueConnectionFactory] not found: JNDI implementation returned null

I posted my question to the BTM user forum.  We’ll see how it turns out!

Posted in Technical Stuff | Tagged: , , , | Leave a Comment »

JNDI without an app server? part 2

Posted by danielmeyer on August 11, 2008

In our last episode, I was trying to find a way to do JNDI without an app server, so that we could run our integration tests locally — not in an app server environment — without having to change our production Spring bean files.

The mock JNDI blurb in the Spring 2.5 manual’s Testing chapter led me to the ExpectedLookupTemplate class.  I decided to see if ExpectedLookupTemplate could help us with integration testing.  What I found was…

We can do it…

We can indeed inject an ExpectedLookupTemplate into our JndiObjectFactoryBean and have it return the bean of our choice when that JNDI name is used.  First, the bean file showing the wiring:

The Spring Bean File

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean id="pooledJmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
        <constructor-arg index="0" value="vm://localhost" />
    </bean>

    <bean id="queueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:activemq/QueueConnectionFactory" />
<property name="jndiTemplate">
            <bean class="org.springframework.mock.jndi.ExpectedLookupTemplate">
                <constructor-arg index="0" value="java:activemq/QueueConnectionFactory" />
                <constructor-arg index="1" ref="pooledJmsConnectionFactory" />
            </bean>
        </property>
    </bean>
</beans>

Notice that in our JndiObjectFactoryBean (line 12) we override the jndiTemplate property, specifying an ExpectedLookupTemplate (line 15) that returns our pooledConnectionFactory bean instance.  So we would replace the line:

<jee:jndi-lookup id="queueConnectionFactory" jndi-name="java:activemq/QueueConnectionFactory" />

with code like the above for integration testing.

…But does it buy us anything?

So we have a fake JNDI lookup working… but we could have gotten the same result without the JNDI shenanigans by dispensing with the JndiObjectFactoryBean bean and renaming our pooledConnectionFactory bean to just be the queueConnectionFactory directly (replacing lines 8-20 in the original beans file):

	<bean id="queueConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
		<constructor-arg index="0" value="vm://localhost" />
	</bean>

About the only thing the fake JNDI lookup buys us here is that in real life the queue name would be a variable, e.g. ${com.example.research.queue.name} — and by using the fake JNDI lookup we’d be making use of that variable name, and if it wasn’t in the properties file we’d see the error at integration test time.  It doesn’t seem like that’s a good enough reason though.  Without an outside-the-app-server JNDI server, it looks like we probably would replace our JNDI lookups with a bean for what would have been looked up.

Note: I’m not saying the ExpectedLookupTemplate doesn’t work as intended –  I think its purpose is really to make code that uses Spring’s JndiTemplate class directly, unit-testable  (as this post on the Spring forums also suggests).

Next: What about Bitronix Transaction Manager as a fake JNDI server and outside-the-app-server transaction manager?

Other Files for the Test

Other files needed to run this test are the pom.xml file and the unit test:

The POM file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.research.jndi</groupId>
    <artifactId>fake-jndi</artifactId>
    <name>Fake JNDI example</name>
    <version>1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-mock</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>2.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>2.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-core</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

The Unit Test

package com.example.research.jndi;

import static org.junit.Assert.assertSame;

import org.apache.activemq.pool.PooledConnectionFactory;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FakeJndiTest {
    @Test
    public void TestFakeJndi() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/example/research/jndi/spring-beans.xml");
        Object bean = context.getBean("queueConnectionFactory");
        PooledConnectionFactory connectionFactory = (PooledConnectionFactory)context.getBean("pooledJmsConnectionFactory");
        assertSame(bean,connectionFactory);
    }
}


Posted in Technical Stuff | Tagged: , | 3 Comments »

JNDI without an app server? part 1

Posted by danielmeyer on August 5, 2008

We want to be able to run integration tests against our production code without always having to deploy to an app server.  Once the production code uses JNDI to get the JTA TransactionManager* and JMS and maybe Hibernate connection factories, how are we going to do those lookups without running on the app server?

*or is it UserTransaction — I haven’t read the JTA spec, so I’m not sure what magic Spring is doing to connect to the application server’s XA transaction manager.

Bypassing JNDI

There’s a paragraph in the Spring 2.5 Manual’s Testing chapter that talks about exactly the issue we’re discussing:

As far as possible, you should have exactly the same Spring configuration files in your integration tests as in the deployed environment. One likely point of difference concerns database connection pooling and transaction infrastructure. If you are deploying to a full-blown application server, you will probably use its connection pool (available through JNDI) and JTA implementation. Thus in production you will use a JndiObjectFactoryBean for the DataSource and JtaTransactionManager. JNDI and JTA will not be available in out-of-container integration tests, so you should use a combination like the Commons DBCP BasicDataSource and DataSourceTransactionManager or HibernateTransactionManager for them. You can factor out this variant behavior into a single XML file, having the choice between application server and ‘local’ configuration separated from all other configuration, which will not vary between the test and production environments. In addition, it is advisable to use properties files for connection settings: see the PetClinic application for an example.

That’s pretty on-point there!

Mocking JNDI

Another alternative is to have a bare-bones JNDI provider that gives your integration test the objects it needs.  Earlier in the Testing chapter, the Spring manual points us to the org.springframework.mock.jndi package, which provides an ExpectedLookupTemplate for this purpose.  ExpectedLookupTemplate extends JndiTemplate and lets you pass to the constructor a JNDI name and an object to return.  It appears that you could use an ExpectedLookupTemplate in your Spring bean file so that instead of just this:

	<jee:jndi-lookup id="queueConnectionFactory" jndi-name="java:activemq/QueueConnectionFactory" />

you’d add this:

    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
        <constructor-arg index="0" value="vm://localhost" />
    </bean>

    <bean id="fakeJndiServer" class="org.springframework.mock.jndi.ExpectedLookupTemplate">
        <constructor-arg index="0" value="java:activemq/QueueConnectionFactory" />
        <constructor-arg index="1" ref="pooledConnectionFactory" />
    </bean>

And then users of the queueConnectionFactory bean could go on their merry way, not needing to know where the queueConnectionFactory came from.

You’d also need to add this to your pom.xml file:

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-mock</artifactId>
			<version>2.0.8</version>
		</dependency>

And then all the rest of your Java code and configuration files could be the same.

Update 8/11/2008: The above example is not quite right.  See Part 2 for a working example of mocking JNDI.

Posted in Technical Stuff | Tagged: , | 3 Comments »

Getting the Oracle XA datasource in place

Posted by danielmeyer on July 24, 2008

Last time, we seemed to see a successful rollback of one resource (the JMS message receive).  Today we want to try to get the JDBC datasource to participate in the transaction, to set up for demonstrating a rollback during a full two-phase commit.


I had an Oracle datasource configuration file sitting around waiting for when I was ready to test the Hibernate portion of my XA transaction, but yesterday I took a look at it and it looks like a non-XA datasource.  For one thing, the bulk of the content is within a  <local-tx-datasource> element.  For another, there is this comment near the top:

<!--| This datasource connects to oracle.  It is a LOCAL TRANSACTION data source (as opposed to
| an XA transaction datasource
|-->

I’ll need an XA datasource, though, not a local one…

An example to work from

I found Section 8.3.2. Installing the JDBC Driver and Deploying the DataSource in JBoss’s Getting Started with JBoss 4.0 guide, which has an example Oracle XA datasource.  I started with that example and made the following changes:

  • For the URL, I used jdbc:oracle:thin:@localhost:1521:XE
  • Different username/password — I followed the instructions (also in Section 8.3.2.) for creating a user via the Oracle SQL command line
  • Commented out the mbean element

(When I first deployed this datasource, I got a stacktrace containing the following error:

Caused by: java.lang.ClassNotFoundException: No ClassLoaders found for: org.jboss.resource.adapter.jdbc.xa.oracle.OracleXAExceptionFormatter

)

[Update 8/21/2008: I found instructions for fixing the missing ExceptionFormatter class so that this mbean no longer needs to be commented out: the class name in the code attribute needed to be corrected from org.jboss.resource.adapter.jdbc.xa.oracle.OracleXAExceptionFormatter to org.jboss.resource.adapter.jdbc.vendor.OracleXAExceptionFormatter.]

Now when I deploy I see:

09:29:09,112 INFO  [ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=XAOracleDS' to JNDI name 'java:
XAOracleDS'

Added JNDI lookup to Spring bean file

I went to the Spring beans file for the Hibernate stuff and put this JNDI lookup there:

<jee:jndi-lookup id="myDataSource" jndi-name="java:XAOracleDS" />

So, now that will be there when I’m ready to try it out.

Update: Oracle JDBC driver

I was looking through some notes I had and another part of the setup, which I had done previously (besides installing Oracle Database 10g Express Edition), was to go in our Maven repository to the following location:

  • group id:  com.oracle
  • artifact id: ojdbc5
  • version: 11.1.0.6.0

and put the ojdbc5-11.1.0.6.0.jar from there in JBoss’s server\default\lib directory.

Next time we’ll configure the Hibernate session factory…

Posted in Technical Stuff | Tagged: , , , , , | Leave a Comment »

Something works!

Posted by danielmeyer on July 17, 2008

After days of untested theories, head-scratching, dead ends, and rabbit trails, I’m happy to report that something now works.

The Beginning of Unstuckitude

First thing was, Keith got back, took a look at the class cast errors in the stack trace and said something along the lines of, “That looks like a dependency issue.”

And that is what it was: my .war project was including javax.jms.ConnectionFactory more than once. (There is also a Spring forum question and answer for this problem.)

Step 1: activemq-all to activemq-core

We browsed through the .jar files in the activemq-all .jar file (manually, by opening each enclosing .jar in WinZip — anyone have a better way of doing this?) and indeed it did have javax.jms.* classes in it.  Keith knew that having the same classes multiple times in your .war can cause problems as the app server may load the wrong ones, so in my project’s pom.xml we replaced the dependency on activemq-all with a dependency on activemq-core instead:


<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-core</artifactId>
    <version>5.0.0</version>
</dependency>

When we tried to do a Maven Install of this, though, we got:


Missing:
----------
1) org.apache.activemq:activeio-core:jar:3.1-SNAPSHOT
...
2) org.apache.activemq:activeio-core:test-jar:tests:3.1-SNAPSHOT
...
----------
2 required artifacts are missing.

Step 2: Exclude activeio-core dependency

We don’t need the activeio-core tests anyway, so we put in an exclusion for this:


<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-core</artifactId>
    <version>5.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activeio-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

This time Maven Install ran cleanly.

Step 3: Scope = Provided

When we deployed, though, we got errors like this:

10:12:59,417 WARN  [JBossManagedConnectionPool] Throwable while attempting to get a new connection: null
javax.resource.ResourceException: Could not create connection.
...
Caused by: javax.jms.JMSException: Could not create Transport. Reason: java.io.IOException: Transport scheme NOT recognized: [tcp]
...
08:35:36,453 INFO  [DefaultMessageListenerContainer] Could not refresh JMS Connection - retrying in 5000 ms
javax.jms.JMSException: Could not create Transport. Reason: java.io.IOException: Transport scheme NOT recognized: [tcp]
...

The DefaultMessageListenerContainer, finding itself unable to make a JMS connection, kept trying every five seconds –  boom, bang, bang, boom, zowie!  (I’m still getting acclimated to the spectacular errors you can get when deploying to an app server. :)

At first I didn’t notice one of the Caused Bys farther down, which said:

Caused by: java.lang.ClassCastException: org.apache.activemq.transport.tcp.TcpTransportFactory

But sure enough, it turns out that this error was caused by double-deployed classes.  This time, it was the activemq-core jar that is already contained inside the activemq-ra.rar file. Our project already depends on that .rar file being there, and we don’t want two copies of the jar, so we updated our pom file’s activemq-core dependency definition by setting scope to provided (line 5), as follows:

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-core</artifactId>
    <version>5.0.0</version>
    <scope>provided</scope>
    <exclusions>
        <exclusion>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activeio-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Success

This time, our .war file deploys without stack traces (woohoo!),  and when I point my browser to the ActiveMQ Console I see that my “gloriousTest.Queue” queue shows up.  I use the ActiveMQ Console to send a message to the queue and… my MessageListener gets the message and prints its debug output to the JBoss console!

The Files That Worked

applicationContext.xml, the Spring bean file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:amq="http://activemq.org/config/1.0"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://activemq.org/config/1.0 http://activemq.apache.org/schema/core/activemq-core-5.0.0.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

    <jee:jndi-lookup id="queueConnectionFactory" jndi-name="java:activemq/QueueConnectionFactory" />

    <amq:queue id="queue" physicalName="gloriousTest.Queue" />

    <bean id="messageListener" class="com.something.dmn.MessageListener" />

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="queueConnectionFactory" />
<property name="destination" ref="queue" />
<property name="messageListener" ref="messageListener" />
<property name="transactionManager" ref="transactionManager" />
    </bean>
</beans>

pom.xml (relevant portions)

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${springFramework.version}</version>
        </dependency>
        ...
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-jms_1.1_spec</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-core</artifactId>
        <version>5.0.0</version>
        <scope>provided</scope>
        <exclusions>
            <exclusion>
                <groupId>org.apache.activemq</groupId>
                <artifactId>activeio-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
    </dependency>
    ...
</dependencies>
<properties>
    ...
    <springFramework.version>2.5.4</springFramework.version>
</properties>

activemq-jms-ds.xml

This file I was able to use without modification from the example on the ActiveMQ site.  I noticed, though, that the <ServerUrl> elements under connection-factories -> tx-connection-factory seem to be ignored.  (Maybe that is because in our case the ServerUrl is already being pre-specified in the activemq-ra.rar’s ra.xml file.)

ra.xml (in activemq-ra.rar)

I think the only change I had to make to this resource adapter archive was to the connector -> resourceadapter -> config-property-value element for the ServerUrl config-property-name, to change it from vm://localhost to tcp://localhost:61616.  (Or maybe it was already tcp… I don’t remember now.)

Next

Now that we have the JCA/JMS/JNDI/JBoss/Spring/ActiveMQ stuff playing nicely together, we can try to actually do some XA stuff!

Posted in Technical Stuff | Tagged: , , , , , | Leave a Comment »

Trying out XA, part 6: jndi.properties rabbit trail

Posted by danielmeyer on July 9, 2008

In part 5, we were thinking the problem might be having the wrong class specified in the resource adapter configuration file.

So, based on the ActiveMQ JNDI Support page, looks like we need to put a jndi.properties file with our project…

Tried that and my new queue connection factory doesn’t show up in JNDIView in the JBoss JMX console.  Hmm.  Moved jndi.properties into the same package as my java classes to see if JBoss would see it there… same result.

Hey, jndi.properties exists in JBoss’s conf directory (in my case, server/default/conf/jndi.properties).  How ’bout I first try adding the settings there and bouncing JBoss, and see if the entries show up in the JMX console.  Then I can do it a better way once it’s working, huh?

I’m adding these settings to jndi.properties:

java.naming.provider.url = tcp://localhost:61616
connectionFactoryNames = DapperQueueConnectionFactory
queue.DapperQueue = XATry.DapperQueue

JBoss doesn’t seem to immediately notice the change (no output on the console anyway) so let’s bounce JBoss…

Boom!

javax.naming.CommunicationException: Could not obtain connection to any of these urls: tcp://localhost:61616 and discovery failed with error: javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out] [Root exception is javax.naming.CommunicationException: Failed to connect to server tcp:1099 [Root exception is javax.naming.ServiceUnavailableException: Failed to connect to server tcp:1099 [Root exception is java.net.UnknownHostException: tcp: tcp]]]

Maybe I should have ActiveMQ running at the time I start JBoss…

Hmm, same error even with ActiveMQ running.

You know, at the top of JBoss’s jndi.properties file there is this comment:

# DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING

I guess they were right!  :)

I removed the things I had added to the jndi.properties file, and JBoss starts clean again.

Properties in the Spring beans?

I seem to remember <properties> entries you can put within your Spring bean definitions.  Perhaps I should put the settings there instead of in jndi.properties.  Let’s see…ah yes, it was in the Spring manual Appendix A, the part about the jee:jndi-lookup tag.

So instead of

<jee:jndi-lookup id="connectionFactory" jndi-name="java:activemq/ConnectionFactory" />

let’s try this:

<jee:jndi-lookup id="connectionFactory" jndi-name="DapperQueueConnectionFactory">
    <jee:environment>
        java.naming.provider.url=tcp://localhost:61616
        connectionFactoryNames=DapperQueueConnectionFactory
        queue.DapperQueue=XATry.DapperQueue
    </jee:environment>
</jee:jndi-lookup>

Deploying this blows up because again I don’t have ActiveMQ running at port 61616.  Let’s start up ActiveMQ and try again…

Hmm, no new messages in the console, but I think I read somewhere that ActiveMQ doesn’t read the jndi.properties file until the queue (or whatever) is actually going to be used.  So let’s try enabling the DefaultMessageListenerContainer, pointing to the beans which have been revised this way:

    <bean id="messageListener" class="com.example.service.QueueConsumer" />

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

    <jee:jndi-lookup id="connectionFactory" jndi-name="DapperQueueConnectionFactory">
        <jee:environment>
            java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory
            java.naming.provider.url=tcp://localhost:61616
            connectionFactoryNames=DapperQueueConnectionFactory
            queue.DapperQueue=XATry.DapperQueue
        </jee:environment>
    </jee:jndi-lookup>

    <jee:jndi-lookup id="dapperQueue" jndi-name="DapperQueue">
        <jee:environment>
            java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory
            java.naming.provider.url=tcp://localhost:61616
            connectionFactoryNames=DapperQueueConnectionFactory
            queue.DapperQueue=XATry.DapperQueue
        </jee:environment>
    </jee:jndi-lookup>

    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="messageListener" ref="messageListener" />
        <property name="transactionManager" ref="transactionManager" />
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="dapperQueue" />
    </bean>

Result:

13:59:51,947 ERROR [ContextLoader] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘connectionFactory’: Invocation of init method failed; nested exception is javax.naming.NamingException: Invalid broker URL

Guess we still don’t have it!

Update: See the Something Works! post for the stunning near-conclusion of the example…

Posted in Technical Stuff | Tagged: | 3 Comments »

Trying out XA, part 5: a resource adapter rabbit trail

Posted by danielmeyer on July 8, 2008

In Part 4, we ended up stuck and wanting to post a question somewhere.  As often happens, as part of pulling together data to ask a question, I do more research…

Part of a thread from the ActiveMQ Users list says:

> Are the connection factories/queues/topics just exposed by the RAR for use
> within the J2EE server only.

Yes – as they are not using the regular JMS client API – they are
using J2EE RA stuff

You’ll need to setup a regular JMS connection and any destination
objects you want in JNDI somewhere. Using JBoss’s JNDI provider could
well work fine though – just make sure its actually normal JMS client
objects (ConnectionFactory & destinations) – and not RA stuff.  Also
make sure the J2EE server and your stand alone client are using the
exact same ActiveMQ jars since its gonna be using Java serialization
to transmit the Java objects in JNDI

(Emphasis mine.)  Ok, so looks like the classes I’m JNDI-lookuping aren’t intended for outside-the-app-server use.  But there is a way… the rest of the thread discusses an alternative, but I’m not sure that it would work with XA transactions.

But……… ActiveMQ’s JNDI Support page shows how to use a jndi.properties file to specify, among other things, a connection factory.  Let’s try that tomorrow!

Update 7/23/2008: See the Something works! post for what was actually the cause of the ClassCastExceptions…

Posted in Technical Stuff | Tagged: , , , | 4 Comments »

Trying out XA, part 2: transaction manager and JNDIView

Posted by danielmeyer on July 7, 2008

Last Thursday I tried out the configuration from last time, and… fireworks!  (A big stack trace — appropriate for the day, no?)

So, I commented out the three bean IDs in the Spring bean file and tried again.  No big stack trace in JBoss (mind you, I’m not actually trying to do anything with the beans yet, just deploy the .war file and not see a big failure stack trace on the JBoss console).  That deployed ok.  And I’m able to uncomment the transactionManager bean — when I do, I get this new output on the JBoss console:

7d56b: defining beans [transactionManager]; root of factory hierarchy
08:09:27,205 INFO  [JtaTransactionManager] Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@1906773
08:09:27,221 INFO  [JtaTransactionManager] Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@1d008ff

So that looks promising.  The DefaultMessageListenerContainer depends on both the transactionManager and the JNDI-looked-up queueConnectionFactory, and when I uncomment the queueConnectionFactory-JNDI-looked-up bean I get this big stack trace on the JBoss console.

The first error is:

08:26:12,253 ERROR [ContextLoader] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘queueConnectionFactory’: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: QueueConnectionFactory not bound

This NameNotFoundException on QueueConnectionFactory keeps coming up in the “Caused by” lines farther down in the stack trace.

Spring is not finding something JNDI-registered as QueueConnectionFactory.  This seemed intractable Thursday, but today I’m wondering:

Did I mix up the jndi-name with the ID?

Perhaps I got the jndi-name and the id mixed up in the Spring bean file.  In the bean file I have:

<jee:jndi-lookup id="queueConnectionFactory" jndi-name="activemq/QueueConnectionFactory"/>

and in the deployed activemq-jms-ds.xml there is

<jndi-name>activemq/QueueConnectionFactory</jndi-name>

Those seem to match.

Let’s see if I can examine JBoss’s JNDI directory somehow to see how it has the queue registered.

Searching for JBoss’s JNDI Directory

I pointed my browser to http://localhost:8080 , where my local JBoss instance is listening.  After poking around in the Administration Console and looking a bit at Sun’s JNDI Tutorial, I thought I’d look in the JMX Console to see if I could find how activemq/QueueConnectionFactory was listed… or any other JNDI thing, for that matter.

Under the jboss heading I see a JNDIView link that looks promising:

Following that link, I get to a page about the JNDIView service that has this:

I press Invoke and find myself on an Operation Results page that has interesting JNDI stuff listed out.

Examining JBoss’s JNDI directory

On this page, I search for queue and find this under a heading titled java: Namespace:

  +- activemq (class: org.jnp.interfaces.NamingContext)
  |   +- QueueConnectionFactory (class: org.apache.activemq.ra.ActiveMQConnectionFactory)
  |   +- TopicConnectionFactory (class: org.apache.activemq.ra.ActiveMQConnectionFactory)

Ok, continuing to search for queue, I find this under the heading Global JNDI Namespace:

  +- queue (class: org.jnp.interfaces.NamingContext)
  |   +- A (class: org.jboss.mq.SpyQueue)
  |   +- testQueue (class: org.jboss.mq.SpyQueue)
  |   +- ex (class: org.jboss.mq.SpyQueue)
  |   +- DLQ (class: org.jboss.mq.SpyQueue)
  |   +- D (class: org.jboss.mq.SpyQueue)
  |   +- C (class: org.jboss.mq.SpyQueue)
  |   +- B (class: org.jboss.mq.SpyQueue)

And, just as interesting, farther down under the same heading:

+- QueueConnectionFactory (class: org.jboss.naming.LinkRefPair)

To my untrained eye, it looks like in the global JNDI namespace, we have queue/A, queue/B, etc… but then just plain QueueConnectionFactory without the activemq/ before it. I even remember seeing entries like queue/A, queue/B, etc. in the JBoss console when it started up:

08:09:07,645 INFO  [A] Bound to JNDI name: queue/A
08:09:07,645 INFO  [B] Bound to JNDI name: queue/B
08:09:07,645 INFO  [C] Bound to JNDI name: queue/C
08:09:07,661 INFO  [D] Bound to JNDI name: queue/D
08:09:07,661 INFO  [ex] Bound to JNDI name: queue/ex
08:09:07,692 INFO  [testTopic] Bound to JNDI name: topic/testTopic
08:09:07,692 INFO  [securedTopic] Bound to JNDI name: topic/securedTopic
08:09:07,707 INFO  [testDurableTopic] Bound to JNDI name: topic/testDurableTopic
08:09:07,707 INFO  [testQueue] Bound to JNDI name: queue/testQueue
08:09:07,754 INFO  [UILServerILService] JBossMQ UIL service available at : /127.0.0.1:8093
08:09:07,785 INFO  [DLQ] Bound to JNDI name: queue/DLQ

I bet if one of our Spring beans referred to a queue/A jndi-name, it would be found.

So if the global JNDI namespace holds the JNDI names to which a Spring bean file might refer, perhaps in my Spring bean file I should put plain QueueConnectionFactory as the jndi-name, instead of activemq/QueueConnectionFactory.

Reluctance to Use the Short JNDI-name

Let’s sit on that thought for a minute, because I’d rather use the more descriptive (?) activemq/QueueConnectionFactory as the jndi-name in the Spring bean file if possible. Looking at the java: Namespace, it would appear that the QueueConnectionFactory would be specified as activemq/QueueConnectionFactory there, if the tree is built the same as the queue/A under the Global JNDI Namespace heading.  To access the java: JNDI namespace, do we just prepend java: to the JNDI-name?

Accessing the java: JNDI Namespace

That would make our bean definition look like this:

<jee:jndi-lookup id=”queueConnectionFactory” jndi-name=”java:activemq/QueueConnectionFactory”/>

I rebuilt and redeployed, and I don’t get a stack trace this time.  No positive log messages about Spring finding the queueConnectionFactory, but at least no stack trace.  I guess I was hoping for a little more positive feedback before I went on…

The Droids We Are Looking For

But while searching through the JBoss console messages for the queue/A, queue/B… messages, I found this!

08:09:06,367 INFO  [ConnectionFactoryBindingService] Bound ConnectionManager ‘jboss.jca:service=ConnectionFactoryBinding,name=activemq/QueueConnection
Factory’ to JNDI name ‘java:activemq/QueueConnectionFactory’

Aha!  It looks like that is the right name syntax.

Now that we have defined the JtaTransactionManager and QueueConnectionFactory beans, we can go on to define the DefaultMessageListenerContainer bean, which depends on both of them.  But we’ll save that for Part 3

Posted in Technical Stuff | Tagged: , , , | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.