[mule-user] FunctionalTestCase with Transacted JMS Queues

9 views
Skip to first unread message

Mike Cantrell

unread,
Jan 12, 2009, 2:31:07 PM1/12/09
to us...@mule.codehaus.org
I'm just getting started with Mule's FunctionalTestCase and I'm having some difficulties sending messages to JMS queues with transactions. It appears to be closing the session to the JMS server before the transaction is completed. I'm sure I've missed something obvious but I just can't seem to fix this. Any help would be greatly appreciated.


The error message is:

********************************************************************************
Message               : Transaction commit failed
Type                  : org.mule.api.transaction.TransactionException
Code                  : MULE_ERROR-90097
JMS Code              : null
JavaDoc               : http://www.mulesource.org/docs/site/current2/apidocs/org/mule/api/transaction/TransactionException.html
********************************************************************************
Exception stack is:
1. The Session is closed(JMS Code: null) (javax.jms.IllegalStateException)
  org.apache.activemq.ActiveMQSession:581 (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/jms/IllegalStateException.html)
2. Transaction commit failed (org.mule.api.transaction.TransactionException)
  org.mule.transport.jms.JmsTransaction:74 (http://www.mulesource.org/docs/site/current2/apidocs/org/mule/api/transaction/TransactionException.html)
********************************************************************************
Root Exception stack trace:
javax.jms.IllegalStateException: The Session is closed
    at org.apache.activemq.ActiveMQSession.checkClosed(ActiveMQSession.java:581)
    at org.apache.activemq.ActiveMQSession.commit(ActiveMQSession.java:461)


The client code is (groovy):

    void testGeneratePriceGuideFromXml() {
        def input = getClass().getResourceAsStream("/832-sample-file.xml")?.text

        client.dispatch("jms://edi/832/inbox", new DefaultMuleMessage(input),
                [JMSReplyTo: 'edi/832/testResponse'])

        def result = client.request("jms://edi/832/testResponse", 10000)

        assertNotNull("No results on response queue", result)
        assertTrue("Incorrect number of messages sent to SMTP server: ${mailServer.receivedEmailSize}",
                mailServer.receivedEmailSize == 1)
    }

The config has a transaction wired to the endpoint:

        <service name="PriceGuideOutput">
            <inbound>
                <jms:inbound-endpoint queue="edi/832/inbox" transformer-refs="JMSToObject">
                    <jms:transaction action="ALWAYS_BEGIN"/>
                </jms:inbound-endpoint>
            </inbound>
            <outbound>
                <multicasting-router>
                    <!-- transform to edi flat file and send to gentran folder -->
                    <file:outbound-endpoint path="c:/temp/832/outbox" transformer-refs="PriceGuideToGentran">
                        <jms:transaction action="ALWAYS_JOIN"/>
                        <properties>
                            <spring:entry key="outputPattern" value="832_[SYSTIME].txt"/>
                        </properties>
                    </file:outbound-endpoint>
                    <!-- email excel document to contacts -->
                    <smtp:outbound-endpoint transformer-refs="PriceGuideToEmail" host="${smtp.host}">
                        <jms:transaction action="ALWAYS_JOIN"/>
                    </smtp:outbound-endpoint>
                </multicasting-router>
            </outbound>
        </service>


Andrew Perepelytsya

unread,
Jan 12, 2009, 2:41:20 PM1/12/09
to us...@mule.codehaus.org
Post a more complete stacktrace and Mule's version. Also, neither file nor smtp transports are transaction, so I'm not sure what you're trying to achieve there.

Andrew

Mike Cantrell

unread,
Jan 12, 2009, 2:57:30 PM1/12/09
to us...@mule.codehaus.org
I'm using mule 2.1.2 and I'm using the transaction on the file and smtp transports because I get an error if I don't:

org.mule.transaction.IllegalTransactionStateException: A transaction is available for this session, but transaction action is "Never"

Here's the complete (root) stacktrace for the session closed error:


javax.jms.IllegalStateException: The Session is closed
    at org.apache.activemq.ActiveMQSession.checkClosed(ActiveMQSession.java:581)
    at org.apache.activemq.ActiveMQSession.commit(ActiveMQSession.java:461)
    at org.mule.transport.jms.JmsTransaction.doCommit(JmsTransaction.java:70)
    at org.mule.transaction.AbstractTransaction.commit(AbstractTransaction.java:100)
    at org.mule.transaction.AbstractSingleResourceTransaction.commit(AbstractSingleResourceTransaction.java:41)
    at org.mule.transaction.TransactionTemplate.resolveTransaction(TransactionTemplate.java:177)
    at org.mule.transaction.TransactionTemplate.execute(TransactionTemplate.java:142)
    at org.mule.transport.AbstractReceiverWorker.doRun(AbstractReceiverWorker.java:131)
    at org.mule.transport.AbstractReceiverWorker.run(AbstractReceiverWorker.java:62)
    at org.mule.work.WorkerContext.run(WorkerContext.java:310)
    at org.mule.work.SyncWorkExecutor.doExecute(SyncWorkExecutor.java:41)
    at org.mule.work.MuleWorkManager.executeWork(MuleWorkManager.java:269)
    at org.mule.work.MuleWorkManager.doWork(MuleWorkManager.java:157)
    at org.mule.transport.jms.MultiConsumerJmsMessageReceiver$SubReceiver.onMessage(MultiConsumerJmsMessageReceiver.java:278)
    at org.apache.activemq.ActiveMQMessageConsumer.dispatch(ActiveMQMessageConsumer.java:854)
    at org.apache.activemq.ActiveMQSessionExecutor.dispatch(ActiveMQSessionExecutor.java:104)
    at org.apache.activemq.ActiveMQSessionExecutor.iterate(ActiveMQSessionExecutor.java:171)
    at org.apache.activemq.thread.PooledTaskRunner.runTask(PooledTaskRunner.java:120)
    at org.apache.activemq.thread.PooledTaskRunner.access$100(PooledTaskRunner.java:26)
    at org.apache.activemq.thread.PooledTaskRunner$1.run(PooledTaskRunner.java:47)
    at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1061)
    at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:575)
    at java.lang.Thread.run(Thread.java:595)

Andrew Perepelytsya

unread,
Jan 12, 2009, 3:07:01 PM1/12/09
to us...@mule.codehaus.org
I think the manual setting of JMSReplyTo is interfering.

Andrew

Mike Cantrell

unread,
Jan 12, 2009, 4:40:51 PM1/12/09
to us...@mule.codehaus.org
Is there a better way to dynamically set the reply to address? I used this method because I found it in some of the mule integration tests.

Andrew Perepelytsya

unread,
Jan 12, 2009, 4:49:03 PM1/12/09
to us...@mule.codehaus.org
Why don't you add this reply destination to the multicasting router you already have?

Andrew

Mike Cantrell

unread,
Jan 12, 2009, 5:07:27 PM1/12/09
to us...@mule.codehaus.org
I didn't put it there because I don't really want a response unless it's a test. If possible, I'd like this to be configured dynamically but if that's not realistic, I understand. I thought there might be an API call I could use instead of passing it in the properties.

When I add the reply to address on the multicast router, the test eventually times out waiting on a response from the client request.

        client.dispatch("jms://edi/832/inbox", new DefaultMuleMessage(input))
        def result = client.request("jms://edi/832/reply", 10000)



                <multicasting-router>
                    <!-- transform to edi flat file and send to gentran folder -->
                    <file:outbound-endpoint path="c:/temp/832/outbox" transformer-refs="PriceGuideToGentran">
                        <jms:transaction action="ALWAYS_JOIN"/>
                        <properties>
                            <spring:entry key="outputPattern" value="832_[SYSTIME].txt"/>
                        </properties>
                    </file:outbound-endpoint>
                    <!-- email excel document to contacts -->
                    <smtp:outbound-endpoint transformer-refs="PriceGuideToEmail" host="${smtp.host}">
                        <jms:transaction action="ALWAYS_JOIN"/>
                    </smtp:outbound-endpoint>
                    <reply-to address="jms://edi/832/reply"/>
                </multicasting-router>


Now, what's really odd is that it does not seem to honor the timeout parameter sent with the request. The last thing I see is the result of the last transport and then a JVM exit from the watchdog thread:

**********************************************************************
* Mule ESB and Integration Platform                                  *
* Version: 2.1.2 Build: 13558                                        *
* MuleSource, Inc.                                                   *
* For more information go to http://mule.mulesource.org              *
*                                                                    *
* Server started: 1/12/09 4:01 PM                                    *
* Server ID: 906bd15d-e0f4-11dd-8df7-c3dcccfdf5b4                    *
* JDK: 1.5.0_14 (mixed mode, sharing)                                *
* Encoding: OS: windows-1252, Mule: UTF-8                            *
* OS: Windows XP - Service Pack 3 (5.1, x86)                         *
* Host: LJ-1FVJ2B1 (172.16.4.109)                                    *
*                                                                    *
* Agents Running: None                                               *
**********************************************************************
[01-12 16:01:33] INFO  MuleClient [main]: Using existing MuleContext: org.mule.DefaultMuleContext@94af2f
[01-12 16:01:33] INFO  FileConnector [ActiveMQ Session Task]: Writing file to: C:\temp\832\outbox\832_1231797693640.txt
[01-12 16:01:33] DEBUG PriceGuideToEmailTransformer [ActiveMQ Session Task]: Applying transformer PriceGuideToEmail (com.sonicdrivein.esb.scm.transformer.PriceGuideToEmailTransformer)
[01-12 16:01:33] DEBUG PriceGuideToEmailTransformer [ActiveMQ Session Task]: Object before transform: <?xml version="1.0" encoding="ISO-8859-1"?>
<priceGuide>
  <id>527</id>
  <effectiveDate>2008-12-01T00:00:00.000-06:00</effectiveDate>
  <endDate>2008-12-31T00:00:00.000-06:00</endDate>
  <popula...
[01-12 16:01:34] DEBUG PriceGuideToEmailTransformer [ActiveMQ Session Task]: Object after transform: javax.mail.internet.MimeMessage@146ad8b
[01-12 16:01:34] DEBUG PriceGuideToEmailTransformer [ActiveMQ Session Task]: The transformed object is of expected type. Type is: MimeMessage
[01-12 16:01:34] DEBUG ExchangeSmtpTransport [ActiveMQ Session Task]: Last Server Response: 250 OK

[01-12 16:02:28] ERROR PriceGuideTransformerIntegrationTest [WatchdogThread-0]: Timeout of 60000ms exceeded - exiting VM!

Andrew Perepelytsya

unread,
Jan 12, 2009, 5:14:28 PM1/12/09
to us...@mule.codehaus.org
I'm not yet following the intent, but it must be my brain steaming...

I was about to blog about a trick these days, but you can try it for now to have more time - add the -Dmule.test.timeoutSecs=XX to have more time to debug and/or wait for reply. As a general rule, when things with jms get tricky, I always fallback to populating jms queues with just java and no TX, for the sake of test correctness and to avoid any relationship with Mule threads.

Andrew

Mike Cantrell

unread,
Jan 12, 2009, 5:29:56 PM1/12/09
to us...@mule.codehaus.org
It's probably me. I've got a horrible cold and I probably have no business doing any code write now :)

I let it run for 5 minutes and still no response. I took out the transaction and still have the same issue with the timeout. It's probably something simple. I probably just need some rest and to look at it again later. Thanks for all of your help.

Mike Cantrell

unread,
Jan 14, 2009, 12:59:43 PM1/14/09
to us...@mule.codehaus.org
OK, so started fresh on this issue. I started up a new project with the simplest configuration to eliminate any possible complexities. My main problem right now seems to be getting the reply-to to work at all. I'm really pretty new to JMS and Mule so I'm sure I must have some fundamental misunderstanding here but I'm just not getting why this isn't working.

Here's my entire mule configuration:

    <!-- active mq 4.1.2 -->
    <jms:activemq-connector name="JmsConnector" brokerURL="tcp://localhost:61616"
                            persistentDelivery="true" durable="true"
                            specification="1.1" recoverJmsConnections="true"/>

    <model name="TestModel">
        <service name="TestService">
            <inbound>
                <jms:inbound-endpoint queue="foo.test" />
            </inbound>
            <test:component appendString="abc"/>
            <outbound>
                <pass-through-router>
                    <file:outbound-endpoint path="c:/temp/foo"/>
                    <reply-to address="jms://foo.reply"/>
                </pass-through-router>
            </outbound>
        </service>
    </model>

And the test method:

    void testResponse() {
        def requestData = "hello"
        client.dispatch("jms://foo.test", new DefaultMuleMessage(requestData))
        def reply = client.request("jms://foo.reply", 10000)
        assertNotNull("No response from reply queue", reply)
    }

Everything seems to work except for the reply. I see the file created in the test directory with the contents of the message. I also see the message enqueue/dequeue on the input queue (JMX console). I also see a consumer connected for the reply queue but it never recieves any messages. The client request eventually times out and the response is null.

Am I missing something? I have a very simple maven project I can send if anyone would like to pick over it.

Andrew Perepelytsya

unread,
Jan 14, 2009, 1:18:03 PM1/14/09
to us...@mule.codehaus.org
What kind of reply are you trying to get from the file endpoint? It doesn't have any. As a max, the same message will be returned.

Andrew

Mike Cantrell

unread,
Jan 14, 2009, 1:21:15 PM1/14/09
to us...@mule.codehaus.org
Currently, I don't care for this test. I'm just trying to get anything at all. If I remove the declared reply to, and set it on the client's properties, it works fine but then  transactions won't work from the tests.

Andrew Perepelytsya

unread,
Jan 14, 2009, 1:22:39 PM1/14/09
to us...@mule.codehaus.org
Sort out what you want to achieve first. Maybe a multicasting router is what you need?

Andrew

Mike Cantrell

unread,
Jan 14, 2009, 1:32:35 PM1/14/09
to us...@mule.codehaus.org
All I need is a response but only for my integration tests. I don't care about the contents, I just want the test method to block long enough for the outbound endpoints to do their jobs correctly.   This provides me with 2 benefits:

1) if I don't get a response on the reply queue, I can assume something went wrong and check the DLQ
2) it keeps temporary resources available that the the test has created such as my mock SMTP server (dumpster)

Maybe my approach is flawed. Is there a better way to accomplish the same points?
Reply all
Reply to author
Forward
0 new messages