No the problem is I want it to rollback and it isnt. :( Clearly something in my config or roure is borked. Wish I knew what. Thanks for the info Claus. That will help at least contain what could be wrong.
*Robert Simmons Jr. MSc. - Lead Java Architect @ EA* *Author of: Hardcore Java (2003) and Maintainable Java (2012)* *LinkedIn: **http://www.linkedin.com/pub/robert-simmons/40/852/a39 <http://www.linkedin.com/pub/robert-simmons/40/852/a39>* On Tue, Apr 29, 2014 at 10:44 AM, Claus Ibsen <[email protected]> wrote: > On Tue, Apr 29, 2014 at 5:37 PM, kraythe . <[email protected]> wrote: > > Thats what I thought. That makes my problem perplexing. Well I will > update > > the thread when I figure it out. If anyone has any ideas it would be > > appreciated. > > > > If you want the message to stay, then define a 2nd jms component and > send the message using that. > > > *Robert Simmons Jr. MSc. - Lead Java Architect @ EA* > > *Author of: Hardcore Java (2003) and Maintainable Java (2012)* > > *LinkedIn: **http://www.linkedin.com/pub/robert-simmons/40/852/a39 > > <http://www.linkedin.com/pub/robert-simmons/40/852/a39>* > > > > > > On Tue, Apr 29, 2014 at 4:11 AM, Claus Ibsen <[email protected]> > wrote: > > > >> On Tue, Apr 29, 2014 at 10:59 AM, kraythe . <[email protected]> wrote: > >> > Yeah no problem. I was just hoping someone would have the answer. I > keep > >> > plugging away at it. Probably some transaction issue, I dont know. You > >> can > >> > answer this perhaps :) , when I send a message to an activemq endpoint > >> with > >> > InOnly exchange pattern, will that message be subject to the > transation? > >> > I.e. if the transaction fails will it get popped off AMQ? > >> > > >> > >> Yes if you do that from a camel route using the same jms component / > >> endpoint that started the transaction (eg same jms session). > >> > >> Then only when the TX commit, the message on the queue will be commit > >> and "visible" for consumers. > >> Its like figure 9.6 in Camel in Action book. > >> > >> > >> > *Robert Simmons Jr. MSc. - Lead Java Architect @ EA* > >> > *Author of: Hardcore Java (2003) and Maintainable Java (2012)* > >> > *LinkedIn: **http://www.linkedin.com/pub/robert-simmons/40/852/a39 > >> > <http://www.linkedin.com/pub/robert-simmons/40/852/a39>* > >> > > >> > > >> > On Tue, Apr 29, 2014 at 2:55 AM, Claus Ibsen <[email protected]> > >> wrote: > >> > > >> >> On Mon, Apr 28, 2014 at 8:48 PM, kraythe . <[email protected]> > wrote: > >> >> > No one has any idea on this? It would be really great if I could > find > >> the > >> >> > formula to get this to work. > >> >> > > >> >> > >> >> I dont think people always have the time to help, and especially when > >> >> its more complicated with transactions and a lot of Camel route code. > >> >> > >> >> If you want to get priority help then there is some companies that > offer > >> >> that > >> >> http://camel.apache.org/commercial-camel-offerings.html > >> >> > >> >> > *Robert Simmons Jr. MSc. - Lead Java Architect @ EA* > >> >> > *Author of: Hardcore Java (2003) and Maintainable Java (2012)* > >> >> > *LinkedIn: **http://www.linkedin.com/pub/robert-simmons/40/852/a39 > >> >> > <http://www.linkedin.com/pub/robert-simmons/40/852/a39>* > >> >> > > >> >> > > >> >> > On Tue, Apr 15, 2014 at 5:15 PM, kraythe . <[email protected]> > wrote: > >> >> > > >> >> >> So I think there is a problem with the way rollback is > implemented in > >> >> >> relation to Camel. As far as I can tell there is no way to get the > >> >> >> following working. > >> >> >> > >> >> >> package com.ea.wwce.camel.test.utilities; > >> >> >> > >> >> >> import com.ea.wwce.camel.utilities.data.RecordList; > >> >> >> import com.ea.wwce.camel.utilities.transactions.TxnHelper; > >> >> >> import org.apache.camel.ExchangePattern; > >> >> >> import org.apache.camel.builder.AdviceWithRouteBuilder; > >> >> >> import org.apache.camel.builder.RouteBuilder; > >> >> >> import org.apache.camel.component.mock.MockEndpoint; > >> >> >> import org.testng.annotations.Test; > >> >> >> import static > >> com.ea.wwce.camel.test.utilities.TransactionTestTools.*; > >> >> >> import static > >> >> >> com.ea.wwce.camel.utilities.activemq.ActiveMQHelper.endpointAMQ; > >> >> >> import static > >> >> >> > >> >> > >> > com.ea.wwce.camel.utilities.jackson.RecordSerialization.toListOfJsonStrings; > >> >> >> import static org.apache.camel.ExchangePattern.InOnly; > >> >> >> > >> >> >> /** This test suite validates the transaction configuration in the > >> test > >> >> >> suite. */ > >> >> >> public class JMSOnlyTransactionTest extends AMQRouteTestSupport { > >> >> >> private static final String QUEUE_DEAD = "dead"; > >> >> >> private static final String QUEUE_INBOX = "inbox"; > >> >> >> private static final String QUEUE_OUTBOX = "outbox"; > >> >> >> private static final String ROUTE_ID_FEED = "Feed"; > >> >> >> private static final String ROUTE_ID_TEST_ROUTE = "TestRoute"; > >> >> >> private static final String ROUTE_ID_RESULTS = "ResultsRoute"; > >> >> >> private static final String ROUTE_ID_DEAD = "DeadRoute"; > >> >> >> private static final String DIRECT_FEED_INBOX = > >> "direct:feed_inbox"; > >> >> >> > >> >> >> private static final String MOCK_END = "mock:end"; > >> >> >> private static final String MOCK_BEFORE_TO_QUEUE = > >> >> >> "mock:before_to_queue"; > >> >> >> private static final String MOCK_AFTER_TO_QUEUE = > >> >> "mock:after_to_queue"; > >> >> >> > >> >> >> /** Mock endpoints. */ > >> >> >> private MockEndpoint mockEnd, mockDead, mockOutbox, > >> mockBeforeToQueue, > >> >> >> mockAfterToQueue; > >> >> >> > >> >> >> /** Helper to initialize mocks in the test. */ > >> >> >> private void initMocks() { > >> >> >> mockEnd = assertAndGetMockEndpoint(MOCK_END); > >> >> >> mockDead = assertAndGetMockEndpoint(MOCK_DEAD); > >> >> >> mockBeforeToQueue = > >> assertAndGetMockEndpoint(MOCK_BEFORE_TO_QUEUE); > >> >> >> mockAfterToQueue = > assertAndGetMockEndpoint(MOCK_AFTER_TO_QUEUE); > >> >> >> mockOutbox = > >> >> assertAndGetMockEndpoint(mockEndpointAMQ(QUEUE_OUTBOX)); > >> >> >> } > >> >> >> > >> >> >> @Override > >> >> >> protected RouteBuilder createRouteBuilder() { > >> >> >> System.out.println("createRouteBuilder"); > >> >> >> return new RouteBuilder(this.context) { > >> >> >> @Override > >> >> >> public void configure() { > >> >> >> getContext().setTracing(true); > >> >> >> from(DIRECT_FEED_INBOX).routeId(ROUTE_ID_FEED) > >> >> >> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >> > >> >> >> .split(body()).marshal(dfCaseRecord).to(endpointAMQ(QUEUE_INBOX)); > >> >> >> from(endpointAMQ(QUEUE_OUTBOX)).routeId(ROUTE_ID_RESULTS) > >> >> >> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >> .unmarshal(dfCaseRecord).to(MOCK_END); > >> >> >> from(endpointAMQ(QUEUE_DEAD)).routeId(ROUTE_ID_DEAD) > >> >> >> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >> .unmarshal(dfCaseRecord).to(MOCK_DEAD); > >> >> >> > from(endpointAMQ(QUEUE_INBOX)).routeId(ROUTE_ID_TEST_ROUTE) > >> >> >> > >> >> >> > >> .onException(RuntimeException.class).handled(true).useOriginalMessage() > >> >> >> .to(InOnly, endpointAMQ(QUEUE_DEAD)).end() > >> >> >> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRES_NEW) > >> >> >> .unmarshal(dfCaseRecord) > >> >> >> .to(MOCK_BEFORE_TO_QUEUE) > >> >> >> .marshal(dfCaseRecord) > >> >> >> .to(endpointAMQ(QUEUE_OUTBOX)) > >> >> >> .unmarshal(dfCaseRecord) > >> >> >> .to(MOCK_AFTER_TO_QUEUE); > >> >> >> } > >> >> >> }; > >> >> >> } > >> >> >> > >> >> >> /** Advice the route, mocking ActiveMQ endpoints. */ > >> >> >> protected void adviceRoute() throws Exception { > >> >> >> > this.context.getRouteDefinition(ROUTE_ID_TEST_ROUTE).adviceWith( > >> >> >> this.context, new AdviceWithRouteBuilder() { > >> >> >> @Override > >> >> >> public void configure() throws Exception { > >> >> >> mockEndpoints("activemq:queue:*"); > >> >> >> } > >> >> >> } > >> >> >> ); > >> >> >> } > >> >> >> > >> >> >> @Test > >> >> >> public void testNormalRouting() throws Exception { > >> >> >> adviceRoute(); > >> >> >> startCamelContext(); > >> >> >> initMocks(); > >> >> >> final RecordList cases = casesA(); > >> >> >> > >> >> >> mockEnd.expectedBodiesReceived(cases); > >> >> >> mockBeforeToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >> > >> >> >> > >> mockOutbox.expectedBodiesReceivedInAnyOrder(toListOfJsonStrings(mapper, > >> >> >> cases)); > >> >> >> mockAfterToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >> > >> >> >> template.sendBody(DIRECT_FEED_INBOX, cases); > >> >> >> > >> >> >> mockBeforeToQueue.assertIsSatisfied(); > >> >> >> mockAfterToQueue.assertIsSatisfied(); > >> >> >> mockEnd.assertIsSatisfied(); > >> >> >> mockDead.assertIsSatisfied(); > >> >> >> mockOutbox.assertIsSatisfied(); > >> >> >> } > >> >> >> > >> >> >> @Test > >> >> >> public void testRollbackBeforeEnqueue() throws Exception { > >> >> >> adviceRoute(); > >> >> >> startCamelContext(); > >> >> >> initMocks(); > >> >> >> final RecordList cases = casesA(); > >> >> >> > >> >> >> mockEnd.expectedBodiesReceivedInAnyOrder(cases.get(1), > >> >> cases.get(2)); > >> >> >> mockDead.expectedBodiesReceived(cases.get(0)); > >> >> >> mockBeforeToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >> mockBeforeToQueue.whenExchangeReceived(1, > EXCEPTION_PROCESSOR); > >> >> >> > >> >> >> > >> mockOutbox.expectedBodiesReceivedInAnyOrder(toListOfJsonStrings(mapper, > >> >> >> cases.get(1), cases.get(2))); > >> >> >> > mockAfterToQueue.expectedBodiesReceivedInAnyOrder(cases.get(1), > >> >> >> cases.get(2)); > >> >> >> > >> >> >> template.sendBody(DIRECT_FEED_INBOX, cases); > >> >> >> > >> >> >> mockBeforeToQueue.assertIsSatisfied(); > >> >> >> mockAfterToQueue.assertIsSatisfied(); > >> >> >> mockEnd.assertIsSatisfied(); > >> >> >> mockDead.assertIsSatisfied(); > >> >> >> mockOutbox.assertIsSatisfied(); > >> >> >> } > >> >> >> > >> >> >> @Test > >> >> >> public void testRollbackAfterEnqueue() throws Exception { > >> >> >> adviceRoute(); > >> >> >> startCamelContext(); > >> >> >> initMocks(); > >> >> >> final RecordList cases = casesA(); > >> >> >> > >> >> >> mockEnd.expectedBodiesReceivedInAnyOrder(cases.get(1), > >> >> cases.get(2)); > >> >> >> mockDead.expectedBodiesReceivedInAnyOrder(cases.get(0)); > >> >> >> mockBeforeToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >> > >> >> >> > >> mockOutbox.expectedBodiesReceivedInAnyOrder(toListOfJsonStrings(mapper, > >> >> >> cases)); > >> >> >> mockAfterToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >> mockAfterToQueue.whenExchangeReceived(1, EXCEPTION_PROCESSOR); > >> >> >> > >> >> >> template.sendBody(DIRECT_FEED_INBOX, cases); > >> >> >> > >> >> >> mockBeforeToQueue.assertIsSatisfied(); > >> >> >> mockAfterToQueue.assertIsSatisfied(); > >> >> >> mockDead.assertIsSatisfied(); > >> >> >> mockOutbox.assertIsSatisfied(); > >> >> >> mockEnd.assertIsSatisfied(); > >> >> >> } > >> >> >> } > >> >> >> > >> >> >> I have tried dozens of combinations in the onException clause and > >> >> nothing > >> >> >> works. Adding markRollbackOnly(), or rollback() only succeeds in > >> rolling > >> >> >> back the dead letter channel as well. Making the handled(false) > cause > >> >> AMQ > >> >> >> to resubmit the transaction and rolls back the dead letter > channel. I > >> >> have > >> >> >> tried a dozen combinations so if anyone has one that works I > would be > >> >> >> grateful. > >> >> >> > >> >> >> *Robert Simmons Jr. MSc. - Lead Java Architect @ EA* > >> >> >> *Author of: Hardcore Java (2003) and Maintainable Java (2012)* > >> >> >> *LinkedIn: ** > http://www.linkedin.com/pub/robert-simmons/40/852/a39 > >> >> >> <http://www.linkedin.com/pub/robert-simmons/40/852/a39>* > >> >> >> > >> >> >> > >> >> >> On Mon, Apr 14, 2014 at 1:10 PM, kraythe . <[email protected]> > >> wrote: > >> >> >> > >> >> >>> So, in the ongoing perfect transaction configuration we have an > >> >> >>> interesting use case: Consider the following route in a test: > >> >> >>> > >> >> >>> @Override > >> >> >>> protected RouteBuilder createRouteBuilder() { > >> >> >>> System.out.println("createRouteBuilder"); > >> >> >>> return new RouteBuilder(this.context) { > >> >> >>> @Override > >> >> >>> public void configure() { > >> >> >>> getContext().setTracing(true); > >> >> >>> from(DIRECT_FEED_INBOX).routeId(ROUTE_ID_FEED) > >> >> >>> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >>> > >> >> >>> > .split(body()).marshal(dfCaseRecord).to(endpointAMQ(QUEUE_INBOX)); > >> >> >>> from(endpointAMQ(QUEUE_OUTBOX)).routeId(ROUTE_ID_RESULTS) > >> >> >>> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >>> .unmarshal(dfCaseRecord).to(MOCK_END); > >> >> >>> from(endpointAMQ(QUEUE_DEAD)).routeId(ROUTE_ID_DEAD) > >> >> >>> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >>> .unmarshal(dfCaseRecord).to(MOCK_DEAD); > >> >> >>> > from(endpointAMQ(QUEUE_INBOX)).routeId(ROUTE_ID_TEST_ROUTE) > >> >> >>> > >> >> >>> > >> >> > >> > .onException(RuntimeException.class).handled(true).useOriginalMessage().to(endpointAMQ(QUEUE_DEAD)).end() > >> >> >>> .transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) > >> >> >>> .unmarshal(dfCaseRecord) > >> >> >>> .to(MOCK_BEFORE_TO_QUEUE) > >> >> >>> .marshal(dfCaseRecord) > >> >> >>> .to(endpointAMQ(QUEUE_OUTBOX)) > >> >> >>> .unmarshal(dfCaseRecord) > >> >> >>> .to(MOCK_AFTER_TO_QUEUE); > >> >> >>> } > >> >> >>> }; > >> >> >>> } > >> >> >>> > >> >> >>> Note that the transacted(TxnHelper.KEY_TXNPOLICY_REQUIRED) simply > >> looks > >> >> >>> up the transaction policy by name as it is just a string key for > our > >> >> JNDI > >> >> >>> registry. Our test case looks like the following. > >> >> >>> > >> >> >>> @Test > >> >> >>> public void testRollbackAfterEnqueue() throws Exception { > >> >> >>> adviceRoute(); > >> >> >>> startCamelContext(); > >> >> >>> initMocks(); > >> >> >>> final RecordList cases = casesA(); > >> >> >>> > >> >> >>> mockEnd.expectedMessageCount(2); > >> >> >>> mockEnd.expectedBodiesReceived(cases.get(1), cases.get(2)); > >> >> >>> mockDead.expectedMessageCount(1); > >> >> >>> mockDead.expectedBodiesReceived(cases.get(0)); > >> >> >>> mockBeforeToQueue.expectedMessageCount(3); > >> >> >>> mockBeforeToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >>> mockOutbox.expectedMessageCount(3); > >> >> >>> > >> >> >>> > >> mockOutbox.expectedBodiesReceivedInAnyOrder(toListOfJsonStrings(mapper, > >> >> >>> cases)); > >> >> >>> mockAfterToQueue.expectedMessageCount(3); > >> >> >>> mockAfterToQueue.expectedBodiesReceivedInAnyOrder(cases); > >> >> >>> mockAfterToQueue.whenExchangeReceived(1, > EXCEPTION_PROCESSOR); > >> >> >>> > >> >> >>> template.sendBody(DIRECT_FEED_INBOX, cases); > >> >> >>> > >> >> >>> mockBeforeToQueue.assertIsSatisfied(); > >> >> >>> mockAfterToQueue.assertIsSatisfied(); > >> >> >>> mockEnd.assertIsSatisfied(); > >> >> >>> mockDead.assertIsSatisfied(); > >> >> >>> mockOutbox.assertIsSatisfied(); > >> >> >>> } > >> >> >>> > >> >> >>> In this route the goal is that if any exceptions are thrown even > >> after > >> >> >>> the message is enqueued, it should be rolled back, the message > that > >> >> >>> excepted should go to the DLQ and the messages in the outbox > should > >> be > >> >> >>> rolled back but the message from the inbox should not be put > back on > >> >> the > >> >> >>> queue. This is proving to be a bit of a juggling act. > >> >> >>> > >> >> >>> I tried putting markRollBackOnly() in the exception handler after > >> the > >> >> >>> to(dead) but that rolled back the dead letter queue and outbox > and > >> then > >> >> >>> redelivered the inbox message. Removing the markRollbackOnly() > means > >> >> >>> that the message arrives at dead and is off the inbox but it > doesn't > >> >> get > >> >> >>> removed from the outbox. > >> >> >>> > >> >> >>> So I am looking for the right combination of calls to accomplish > >> what I > >> >> >>> want to do. Any suggestions? > >> >> >>> > >> >> >>> Thanks in advance. > >> >> >>> > >> >> >>> *Robert Simmons Jr. MSc. - Lead Java Architect @ EA* > >> >> >>> *Author of: Hardcore Java (2003) and Maintainable Java (2012)* > >> >> >>> *LinkedIn: ** > http://www.linkedin.com/pub/robert-simmons/40/852/a39 > >> >> >>> <http://www.linkedin.com/pub/robert-simmons/40/852/a39>* > >> >> >>> > >> >> >> > >> >> >> > >> >> > >> >> > >> >> > >> >> -- > >> >> Claus Ibsen > >> >> ----------------- > >> >> Red Hat, Inc. > >> >> Email: [email protected] > >> >> Twitter: davsclaus > >> >> Blog: http://davsclaus.com > >> >> Author of Camel in Action: http://www.manning.com/ibsen > >> >> hawtio: http://hawt.io/ > >> >> fabric8: http://fabric8.io/ > >> >> > >> > >> > >> > >> -- > >> Claus Ibsen > >> ----------------- > >> Red Hat, Inc. > >> Email: [email protected] > >> Twitter: davsclaus > >> Blog: http://davsclaus.com > >> Author of Camel in Action: http://www.manning.com/ibsen > >> hawtio: http://hawt.io/ > >> fabric8: http://fabric8.io/ > >> > > > > -- > Claus Ibsen > ----------------- > Red Hat, Inc. > Email: [email protected] > Twitter: davsclaus > Blog: http://davsclaus.com > Author of Camel in Action: http://www.manning.com/ibsen > hawtio: http://hawt.io/ > fabric8: http://fabric8.io/ >
