Christian, I have that book and that is what I used for a lot of my reference. In fact, they only major difference between his source and mine is he is using Atomikos as the transaction manager and I'm using aries. I am referencing an existing PlatformTransactionManager instead of creating a JtaTransactionManager but PlatformTransactionManager implements JtaTransactionManager so it should be ok.
As for the datasource, I'm actually publishing it from another OSGI component as a service so it can be reused. I'm creating it in code right now as defined below. BasicManagedDataSource ds = new BasicManagedDataSource(); if(xaDataSourceClass != null && !xaDataSourceClass.isEmpty()) { try { XADataSource dsi = (XADataSource)Class.forName(xaDataSourceClass).newInstance(); Method setUrl = dsi.getClass().getMethod("setUrl", new Class[] {String.class}); setUrl.invoke(dsi, (String) config.get(CONNSTR_KEY)); ds.setXADataSource(xaDataSourceClass); ds.setXaDataSourceInstance(dsi); } catch (IllegalArgumentException ex) { throw new ConfigurationException("xaDataSourceClass", "Couldn't create instance", ex); } catch (InvocationTargetException ex) { throw new ConfigurationException("xaDataSourceClass", "Couldn't create instance", ex); } catch (NoSuchMethodException ex) { throw new ConfigurationException("xaDataSourceClass", "Couldn't create instance", ex); } catch (SecurityException ex) { throw new ConfigurationException("xaDataSourceClass", "Couldn't create instance", ex); } catch (InstantiationException ex) { throw new ConfigurationException("xaDataSourceClass", "Couldn't create instance", ex); } catch (IllegalAccessException ex) { throw new ConfigurationException("xaDataSourceClass", "Couldn't create instance", ex); } catch (ClassNotFoundException ex) { throw new ConfigurationException("xaDataSourceClass", "Class not found", ex); } } else { ds.setDriverClassName((String) config.get(DRIVER_KEY)); ds.setUrl((String) config.get(CONNSTR_KEY)); } BundleContext context = FrameworkUtil.getBundle(BedrockConnectionPoolFactory.class).getBundleContext(); ds.setTransactionManager(transMgr); Hashtable<String, String> sp = new Hashtable<String, String>(); sp.put(DSNAME_KEY, (String) config.get(DSNAME_KEY)); ServiceRegistration reg = context.registerService("javax.sql.XADataSource", ds.getXaDataSourceInstance(), sp); regMap.put(id, reg); The transMgr variable above is looking up the Aries transaction manager deployed in SMX (same one my JMS code is getting through the PlatformTransactionManager interface). The biggest challenge I've had is that every single camel transaction example I've seen starts the transaction INSIDE camel. They all resemble the diagram on page 300 of Claus' book. I haven't seen any example where camel is enlisted in an already existing transaction. I was hoping that was just because examples are traditionally simple but maybe it wasn't designed to do that? Chris On Thu, Apr 5, 2012 at 1:11 AM, Christian Müller < christian.muel...@gmail.com> wrote: > Chris, > may be the source code of Claus book "Camel in Action" is helpful for you > [1]. > > Could you als share your datasource configuration with us? It was not in > your post... > > [1] > > http://code.google.com/p/camelinaction/source/browse/trunk/chapter9/xa/src/test/resources/spring-context.xml > > Best, > Christian > > On Thu, Apr 5, 2012 at 7:13 AM, Chris Geer <ch...@cxtsoftware.com> wrote: > > > We are building an application using ServiceMix (CXF, Camel, Karaf...) > and > > we've run into an issue with transactions not propagating to camel routes > > as we'd like them to. We have several OSGI components that run under > > transactions using the Aries transaction management like the following: > > > > <bean id="serviceBean" class="<class>"> > > <property name="dataSource" ref="ds"/> > > <property name="camelContext" ref="camelCtx"/> > > <tx:transaction method="updateAddress, createAddress, > > deleteAddress" value="Required" /> > > <tx:transaction method="getAddress, findAddresses" > value="Supports" > > /> > > </bean> > > > > We have published a DataSource which is transaction aware for our > > components to use. It shows up in SMX as the following: > > > > aries.xa.aware = true > > dsName = ds > > objectClass = javax.sql.DataSource > > service.id = 298 > > > > In our components we are able to perform database transactions that > > successfully get committed/rolled back as expected without having to > > manually enlist the JDBC connection. It works great. Those same > components > > also will send various JMS messages as they succeed/fail. Our goal is > that > > if a component sends a JMS message on success and later rolls back the > JMS > > message would be retracted. If we lookup a JMS ConnectionFactory, create > a > > connection, session, manually enlist the session into the current > > transaction and send the message all in code it actually works as > desired. > > > > What we hope to be able to do however is to remove the code and use camel > > instead to process the message and pass it along to the JMS topic, in the > > same transaction that the OSGI component is running in but we can't quite > > get it to work. Below is our latest configuration and code and at this > > point the message posts to the topic but never rolls back. > > > > Blueprint File > > <bean id="activemq" > > class="org.apache.activemq.camel.component.ActiveMQComponent"> > > <property name="connectionFactory" ref="jmsXaConnectionFactory"/> > > <property name="transacted" value="true"/> > > <property name="transactionManager" ref="jmsTransactionManager"/> > > </bean> > > > > <bean id="mandatory" > > class="org.apache.camel.spring.spi.SpringTransactionPolicy"> > > <property name="transactionManager" ref="jmsTransactionManager"/> > > <property name="propagationBehaviorName" > > value="PROPAGATION_MANDATORY"/> > > </bean> > > > > <bean id="jmsXaConnectionFactory" > > class="org.apache.activemq.ActiveMQXAConnectionFactory"> > > <property name="brokerURL" value="tcp://localhost:61616"/> > > </bean> > > > > <reference id="jmsTransactionManager" > > interface="org.springframework.transaction.PlatformTransactionManager"/> > > > > > > <camel:camelContext id="camelCtx" trace="true"> > > <camel:route> > > <camel:from uri="direct:genEvent"/> > > <camel:wireTap uri="direct:wireTap"/> > > <camel:transacted ref="mandatory"/> > > <camel:to uri="activemq:topic:event-notifications"/> > > </camel:route> > > > > <camel:route> > > <camel:from uri="direct:wireTap"/> > > <camel:to uri="log:logger?showAll=true"/> > > </camel:route> > > </camel:camelContext> > > > > Code: > > > > ProducerTemplate pt = camelCtx.createProducerTemplate(); > > > > Map<String, Object> headers = new HashMap<String, Object>(); > > headers.put("EventType", eventType); > > headers.put("ClientID", 0); > > headers.put("EntityType", "Address"); > > > > pt.sendBodyAndHeaders("direct:genEvent", getAddress(addressID), > > headers); > > > > > > Like I mentioned, the code all works in the success case but doesn't > > rollback the JMS message in the failure case. Apparently the transaction > > context isn't being passed on to the camel route even though it's using > the > > same transaction manager under the covers. Is that by design or is there > a > > way to make this scenario work? We'd really like to be able use the camel > > route approach so we can do more complex things than what I show here. > > > > Thanks, > > Chris > > >