Raul, I gave that a shot but it actually made the problem worse. ProducerTemplate.requestBodyAndHeader uses an InOut exchange pattern but since I'm not sending responses it always fails (regardless of transaction) with a timeout saying it didn't get a response. It also send the message to the topic even without the transaction being committed so it wouldn't solve the transaction problem anyway.
Chris On Tue, Apr 17, 2012 at 1:47 AM, Raul Kripalani <r...@fusesource.com> wrote: > Hi Chris! > > Transaction Managers bind transactions to threads, and a possible cause for > your transaction getting lost is that your route is being called > asynchronously from another thread. > > This is because you are using ProducerTemplate.send...(). > > Can you replace this with ProducerTemplate.requestBodyAndHeader(...), which > in theory should call the route synchronously in the same thread? > > Regards, > > *Raúl Kripalani* > Principal Consultant | FuseSource Corp. > r...@fusesource.com | fusesource.com <http://www.fusesource.com/> skype: > raul.fuse | twitter: @raulvk <http://twitter.com/raulvk>, > @fusenews<http://twitter.com/fusenews> > > <http://twitter.com/fusenews> > > On 16 April 2012 23:09, Chris Geer <ch...@cxtsoftware.com> wrote: > > > Claus, > > > > I'm still struggling with this so I've put together a quick sample > project > > that shows the problem. It consists of an OSGI component that runs under > a > > transaction and posts two JMS messages (one with Camel and one with JMS > > APIs) then rolls back the transactions. I would hope to see both messages > > not be delivered but instead what I see if the one sent via camel being > > delivered while the other one is rolled back. I'm sure I'm probably doing > > something wrong but I can't figure it out. > > > > Is there a place I can post my sample project where someone might be able > > to give it a quick look? > > > > Thanks, > > Chris > > > > On Sat, Apr 7, 2012 at 3:19 AM, Claus Ibsen <claus.ib...@gmail.com> > wrote: > > > > > On Thu, Apr 5, 2012 at 5:57 PM, Chris Geer <ch...@cxtsoftware.com> > > wrote: > > > > Claus, > > > > > > > > I realize that but I can't explain what I'm seeing. Here is an > > additional > > > > piece of info, here is debug log for the sending of the message. As > you > > > can > > > > see, the transaction fields are all null but I don't know if that is > > > normal > > > > or a symptom of the problem. > > > > > > > > 08:51:22,906 | DEBUG | erations/address | JmsConfiguration > > > > | 169 - org.apache.camel.camel-jms - 2.9.2.SNAPSHOT | Sending JMS > > message > > > > to: topic://event-notifications with message: ActiveMQBytesMessage > > > > {commandId = 0, responseRequired = false, messageId = null, > > > > originalDestination = null, originalTransactionId = null, producerId > = > > > > null, destination = null, transactionId = null, expiration = 0, > > > timestamp = > > > > 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = > > > null, > > > > replyTo = null, persistent = true, type = null, priority = 0, > groupID = > > > > null, groupSequence = 0, targetConsumerId = null, compressed = false, > > > > userID = null, content = null, marshalledProperties = null, > > > dataStructure = > > > > null, redeliveryCounter = 0, size = 0, properties = > > {EntityType=Address, > > > > breadcrumbId=ID-CXTMBP-Chris-local-62052-1333577461603-22-3, > > > > EventType=EntityCreated, ClientID=0}, readOnlyProperties = false, > > > > readOnlyBody = false, droppable = false} ActiveMQBytesMessage{ > > bytesOut = > > > > org.apache.activemq.util.ByteArrayOutputStream@51762faf, dataOut = > > > > java.io.DataOutputStream@2634b3f1, dataIn = null } > > > > > > > > > > I would only suspect transaction ids being populated in the AMQ > > > message if the message originated from the AMQ broker. Creating a new > > > message to be send would most likely not populate TX ids and whatnot. > > > But the work is still carried out under the TX manager. (if TX is > > > properly configured and working - yeah thats the hard part). > > > > > > > Here is more of the stack trace that shows the transaction being > > > committed > > > > for some reason. > > > > > > > > 08:51:22,888 | DEBUG | erations/address | TransactionErrorHandler > > > > | 166 - org.apache.camel.camel-core - 2.9.2.SNAPSHOT | Transaction > > begin > > > > (0x1f2198ab) redelivered(unknown) for (MessageId: > > > > ID-CXTMBP-Chris-local-62052-1333577461603-22-3 on ExchangeId: > > > > ID-CXTMBP-Chris-local-62052-1333577461603-22-4)) > > > > 08:51:22,888 | DEBUG | erations/address | JtaTransactionManager > > > > | 139 - org.springframework.transaction - 3.0.6.RELEASE | > > Participating > > > in > > > > existing transaction > > > > 08:51:22,906 | DEBUG | erations/address | JmsConfiguration > > > > | 169 - org.apache.camel.camel-jms - 2.9.2.SNAPSHOT | Sending JMS > > message > > > > to: topic://event-notifications with message: ActiveMQBytesMessage > > > > {commandId = 0, responseRequired = false, messageId = null, > > > > originalDestination = null, originalTransactionId = null, producerId > = > > > > null, destination = null, transactionId = null, expiration = 0, > > > timestamp = > > > > 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = > > > null, > > > > replyTo = null, persistent = true, type = null, priority = 0, > groupID = > > > > null, groupSequence = 0, targetConsumerId = null, compressed = false, > > > > userID = null, content = null, marshalledProperties = null, > > > dataStructure = > > > > null, redeliveryCounter = 0, size = 0, properties = > > {EntityType=Address, > > > > breadcrumbId=ID-CXTMBP-Chris-local-62052-1333577461603-22-3, > > > > EventType=EntityCreated, ClientID=0}, readOnlyProperties = false, > > > > readOnlyBody = false, droppable = false} ActiveMQBytesMessage{ > > bytesOut = > > > > org.apache.activemq.util.ByteArrayOutputStream@51762faf, dataOut = > > > > java.io.DataOutputStream@2634b3f1, dataIn = null } > > > > 08:51:22,907 | DEBUG | erations/address | JtaTransactionManager > > > > | 139 - org.springframework.transaction - 3.0.6.RELEASE | > Registering > > > > after-completion synchronization with existing JTA transaction > > > > 08:51:22,907 | DEBUG | erations/address | TransactionErrorHandler > > > > | 166 - org.apache.camel.camel-core - 2.9.2.SNAPSHOT | Transaction > > > commit > > > > (0x1f2198ab) redelivered(unknown) for (MessageId: > > > > ID-CXTMBP-Chris-local-62052-1333577461603-22-3 on ExchangeId: > > > > ID-CXTMBP-Chris-local-62052-1333577461603-22-4)) > > > > > > > > > > That last debug logging is just Camel saying that the TX completed > > > successfully (in that leg). Its up to the TX manager when actually to > > > commit the TX. If a TX was started outside, then the commit is > > > executed at that point. > > > > > > So this is normal. > > > > > > > On Thu, Apr 5, 2012 at 8:19 AM, Claus Ibsen <claus.ib...@gmail.com> > > > wrote: > > > > > > > >> On Thu, Apr 5, 2012 at 4:59 PM, Chris Geer <ch...@cxtsoftware.com> > > > wrote: > > > >> > 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? > > > >> > > > > >> > > > >> Camel does not have its own TX manager etc. All we do is to hook > into > > > >> the Spring TX manager. > > > >> So if there is already a TX in progress, then Camel should just play > > > >> along, and run in that same TX. > > > >> > > > >> The Camel processing occurs in a Spring TX template in its - > > > >> doInTransaction method. That happens when you use the <transacted> > in > > > >> the Route. > > > >> > > > >> > 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 > > > >> >> > > > > >> >> > > > >> > > > >> > > > >> > > > >> -- > > > >> Claus Ibsen > > > >> ----------------- > > > >> CamelOne 2012 Conference, May 15-16, 2012: http://camelone.com > > > >> FuseSource > > > >> Email: cib...@fusesource.com > > > >> Web: http://fusesource.com > > > >> Twitter: davsclaus, fusenews > > > >> Blog: http://davsclaus.blogspot.com/ > > > >> Author of Camel in Action: http://www.manning.com/ibsen/ > > > >> > > > > > > > > > > > > -- > > > Claus Ibsen > > > ----------------- > > > CamelOne 2012 Conference, May 15-16, 2012: http://camelone.com > > > FuseSource > > > Email: cib...@fusesource.com > > > Web: http://fusesource.com > > > Twitter: davsclaus, fusenews > > > Blog: http://davsclaus.blogspot.com/ > > > Author of Camel in Action: http://www.manning.com/ibsen/ > > > > > >