Camel Spring remoting with Artemis Proton/Qpid client - hangs sending message - spring

When i use the Camel spring remoting configuration to send some message, both the producer and consumer are running in different JVM.
using Apache artemis 2.14.0 version
version of camel (2.20.0), qpid (0.54.0), pooled-jms (1.1.1)
i was using the LoadMessageSupport class to push message, i see the camel routes are invoked and below debug log message.
I noticed a producer session enabled in the Artemis console.
Any clue, how to debug this or what might cause this issue.
There were some netty related debug errors which i safely ignored.
...
DEBUG [main] (DefaultManagementAgent.java:470) - Registered MBean with ObjectName: org.apache.camel:context=camel,type=components,name="bean"
DEBUG [main] (DefaultComponent.java:266) - Cannot resolve property placeholders on component: org.apache.camel.component.bean.BeanComponent#cda0432 as PropertiesComponent is not in use
DEBUG [main] (AbstractAutowireCapableBeanFactory.java:448) - Creating instance of bean 'org.apache.camel.component.jackson.converter.JacksonTypeConverters'
DEBUG [main] (AbstractAutowireCapableBeanFactory.java:484) - Finished creating instance of bean 'org.apache.camel.component.jackson.converter.JacksonTypeConverters'
INFO [main] (CamelLogger.java:159) - ID-local-vm-1624040900482-0-1 >>> (processMessage) from(direct://proxy-msg-handler) --> log[Log message on incoming message with body] <<< Pattern:InOnly, Headers:{breadcrumbId=ID-local-vm-1624040900482-0-1}, BodyType:org.apache.camel.component.bean.BeanInvocation, Body:BeanInvocation public abstract void com.myexample.MessageHandler.processMessage(com.myexample.MessageType,java.lang.String) with [ITEM_DESCRIPTION, {"info": " my name"}]]
DEBUG [main] (CamelLogger.java:153) - Log message on incoming message with body
INFO [main] (CamelLogger.java:159) - ID-local-vm-1624040900482-0-1 >>> (SubmitNotificationEvent) log[Log message on incoming message with body] --> amqpcomponent://queue:message.queue <<< Pattern:InOnly, Headers:{breadcrumbId=ID-local-vm-1624040900482-0-1}, BodyType:org.apache.camel.component.bean.BeanInvocation, Body:BeanInvocation public abstract void com.myexample.MessageHandler.processMessage(com.myexample.MessageType,java.lang.String) with [ITEM_DESCRIPTION, {"info": " my name"}]]
DEBUG [main] (SendProcessor.java:147) - >>>> service-event-queue://queue:message.queue Exchange[ID-local-vm-1624040900482-0-1]
DEBUG [main] (InternalLoggerFactory.java:45) - Using SLF4J as the default logging framework
...
DEBUG [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpConnectionBuilder.java:84) - AmqpConnection { ID:6d0c8673-6a92-401d-a239-12ec696fc9d3:1 } is now open:
INFO [AmqpProvider :(1):[amqp://localhost:5672]] (JmsConnection.java:1339) - Connection ID:6d0c8673-6a92-401d-a239-12ec696fc9d3:1 connected to server: amqp://localhost:5672
DEBUG [main] (JmsTemplate.java:492) - Executing callback on JMS Session: JmsPoolSession { org.apache.qpid.jms.JmsSession#7fd26ad8 }
DEBUG [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProducerBuilder.java:68) - Creating AmqpFixedProducer for: null
DEBUG [main] (JmsConfiguration.java:622) - Sending JMS message to: message.queue with message: JmsObjectMessageFacade
After enabling the TRACE level Logs, noticed below msg
DEBUG [main] (JmsConfiguration.java:622) - Sending JMS message to: message.queue with message: JmsObjectMessageFacade { org.apache.qpid.jms.provider.amqp.message.AmqpJmsObjectMessageFacade#36cc9385 }
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpFixedProducer.java:100) - Holding Message send until credit is available.
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProvider.java:1625) - IdleTimeoutCheck rescheduling with delay: 15000
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (NettyTcpTransport.java:560) - New incoming data read: PooledUnsafeDirectByteBuf(ridx: 0, widx: 8, cap: 65536)
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProtocolTracer.java:49) - [1673389762:0] RECV: Empty Frame
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProtocolTracer.java:54) - [1673389762:0] SENT: Empty Frame
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (NettyTcpTransport.java:259) - Attempted write of buffer: PooledUnsafeDirectByteBuf(ridx: 0, widx: 8, cap: 8/8)
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (NettyTcpTransport.java:273) - Attempted flush of pending writes
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProvider.java:1625) - IdleTimeoutCheck rescheduling with delay: 15000
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (NettyTcpTransport.java:560) - New incoming data read: PooledUnsafeDirectByteBuf(ridx: 0, widx: 8, cap: 65536)
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProtocolTracer.java:49) - [1673389762:0] RECV: Empty Frame
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProtocolTracer.java:54) - [1673389762:0] SENT: Empty Frame
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (NettyTcpTransport.java:259) - Attempted write of buffer: PooledUnsafeDirectByteBuf(ridx: 0, widx: 8, cap: 8/8)
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (NettyTcpTransport.java:273) - Attempted flush of pending writes
TRACE [AmqpProvider :(1):[amqp://localhost:5672]] (AmqpProvider.java:1625) - IdleTimeoutCheck rescheduling with delay: 15000
Below is the context xml which i used to send message from java class.
<?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:camel="http://camel.apache.org/schema/spring"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd
http://www.springframework.org/schema/util ttp://www.springframework.org/schema/util/spring-util.xsd">
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<property name="remoteURI" value="amqp://localhost:5672?amqp.traceFrames=true"/>
</bean>
<bean id="jpcf" class="org.messaginghub.pooled.jms.JmsPoolConnectionFactory" init-method="start" destroy-method="stop" >
<property name="maxConnections" value="3" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jpcf" />
<property name="concurrentConsumers" value="3" />
</bean>
<bean id="amqpcomponent" class="org.apache.camel.component.amqp.AMQPComponent">
<property name="configuration" ref="jmsConfig" />
</bean>
<!-- Camel Spring Remoting Interface -->
<camel:proxy id="proxyObject" binding="false" serviceUrl="direct:proxy-msg-handler" serviceInterface="com.myexample.MessageHandler"/>
<!-- Bean that initialize the Spring Remoting for handling message -->
<bean id="BeanProxy" class="com.myexample.MessageProducer">
<property name="messageHandler" ref="proxyObject"/>
</bean>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring" autoStartup="true" trace="true">
<camel:route autoStartup="true" id="processMessage">
<camel:from uri="direct:proxy-msg-handler"/>
<camel:log message="Log incoming message" logName="Incoming" loggingLevel="DEBUG"/>
<camel:inOnly uri="amqpcomponent:queue:message.queue"/>
</camel:route>
</camelContext>
</beans>
java class running the context, used to invoke the remote spring bean method.
Using below java class to push message to Artemis queue
package com.myexample;
public class LoadMessageSupport {
public static void main(String ...strings) {
ApplicationContext appContext =null;
try {
appContext = new ClassPathXmlApplicationContext("file:/paht/to/context/message-handler-context.xml");
MessageProducer messageProducer = appContext.getBean(MessageProducer.class);
message = "{ \"itemDesc\" : \"test description\" }" ;
System.out.println(message);
messageProducer.sendMessage(MessageType.ITEM_DESC, message);
// enum messagetype already defined within project
//System.exit(0);
}catch(Exception exe) {
System.out.println("Something wrong... ");
exe.printStackTrace();
}finally {
if(camelContext!=null) {
System.out.println("camel context stopped...");
camelContext.stop();
}
}
}
}
message receiver class
#InOnly
public interface MessageHandler{
public processMessage(MessageType type, Order order);
public processMessage(MessageType type, String message); // trying to invoke this message
}
producer class
public class MessageProducer{
​// using the proxy object within the producer object
​// this will invoke the spring bean using remote (rmi)
​private MessageHandler messageHandler;
protected MessageHandler getMessageHandler() {
return this.messageHandler;
}
public void setMessageHandler(MessageHandler messageHandler) {
this.messageHandler = messageHandler;
}
//constructor
public ​MessageProducer() {}
​
public void sendMessage(MessageType type, Order order ){
​getMessageHandler().processMessage(type,order);
​}
​public void sendMessage(MessageType type, String message ){
​getMessageHandler().processMessage(type,message);
​}
message Receiver
public class MessageReceiver implements MessageHandler {
#Handler
public void processMessage(MessageType type, Order order){
System.out.println(" received type and ORDER info ...");
// invoke methods for logical processing
}
#Handler
public void processMessage(MessageType type, String message){
System.out.println(" received type and MESSAGE info for procesing...");
// invoke methods for logical processing
}
}

When i was trying earlier, seems like my VM didn't have sufficient memory.
free -h indicate only 500MB left out.
After restarting the VM the message is now sent to Artemis borker.

Related

Camel Splitter Unit Test get wrong ExpectedMessageCount

I have to write unit test for a camel RouteBuilder that use splitter pattern.
Here my RouteConfiguration
protected void configureTest(){
from("direct:in").id("in")
.to("mock:a")
.split(body())
.to("mock:b")
.end();
}
And the test
public class AlertingRouteBuilderTest extends CamelSpringTestSupport {
#Test
public void testest() throws Exception {
String[] bodyArray = new String[]{"tenant1", "tenant2", "tenant3"};
getMockEndpoint("mock:a").setExpectedMessageCount(1);
getMockEndpoint("mock:b").setExpectedMessageCount(3);
template.sendBody("direct:in", bodyArray);
assertNotNull(context.hasEndpoint("direct:in"));
assertMockEndpointsSatisfied();
}
}
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("classpath:cmCtx_alertingProcessTest.xml");
}
with this context.xml file
<bean id="A"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="foo.AProcessor"/>
</bean>
<bean id="B"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="foo.BProcessor"/>
</bean>
<bean id="routeBuilder"
class="foo.RouteBuilder" >
</bean>
<camel:camelContext id="context-objectAnalysis" trace="true" errorHandlerRef="errorHandler">
<camel:propertyPlaceholder id="properties" location="camel.properties"/>
<camel:routeBuilder ref="routeBuilder"/>
</camel:camelContext>
I tried different way to split my body
.split(body())
.split(body(String[].class))
....
But I get
java.lang.AssertionError: mock://b Received message count. Expected: <3> but was: <0>
I don't understand why my splitter does'nt go into my mock:b processor.
In the trace console I have
16:18:34.046 [main] DEBUG o.a.camel.processor.SendProcessor - >>>> Endpoint[mock://a] Exchange[Message: [Ljava.lang.String;#58ec5e8]
16:18:34.051 [main] DEBUG o.a.c.component.mock.MockEndpoint - mock://a >>>> 0 : Exchange[Message: [Ljava.lang.String;#58ec5e8] with body: [Ljava.lang.String;#58ec5e8 and headers:{breadcrumbId=ID-EFR02223-61984-1495635511863-0-1}
16:18:34.053 [main] INFO o.a.c.processor.interceptor.Tracer - ID-EFR02223-61984-1495635511863-0-2 >>> (direct:in) mock://a --> split[bodyAs[[Ljava.lang.String;]] <<< Pattern:InOnly, Headers:{breadcrumbId=ID-EFR02223-61984-1495635511863-0-1}, BodyType:String[], Body:[Ljava.lang.String;#58ec5e8
16:18:34.064 [main] DEBUG o.a.c.processor.MulticastProcessor - Done sequential processing 3 exchanges
Tell me if you need more info to help me.
EDIT:
camel version 2.12.1
Thanks.

Persist message in ActiveMQ across server restart

I am learning Spring Integration JMS. Since ActiveMQ is a message broker. I referring to project given here-> http://www.javaworld.com/article/2142107/spring-framework/open-source-java-projects-spring-integration.html?page=2#
But I want to know how can I persist message in ActiveMQ. I mean I started ActiveMQ then send request using REST client. I am calling publishService.send( message ); in for loop for 50 times and and the receiver end I have sleep timer of 10 seconds. So that 50 messages gets queued and its start processing at 10 seconds interval.
EDIT:
Look at the screen shot below:
It says 50 messages enqueued and 5 of them have been dequeued.
But then in between I stopped ActiveMQ server and by the time it has consumed 5 messages out of 50 and then again restart it.
But then I was expecting it to show remaining 45 in Messages Enqueued column. But I can see 0(see screenshot below) there and they all vanished after server restart without having to persist remaining 45 messages. How can I come over this problem ?
Please have a look at the configuration below:
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:int-jme="http://www.springframework.org/schema/integration"
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
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<!-- Component scan to find all Spring components -->
<context:component-scan base-package="com.geekcap.springintegrationexample" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="order" value="1" />
<property name="messageConverters">
<list>
<!-- Default converters -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
<!-- Define a channel to communicate out to a JMS Destination -->
<int:channel id="topicChannel"/>
<!-- Define the ActiveMQ connection factory -->
<bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<!--
Define an adaptor that route topicChannel messages to the myTopic topic; the outbound-channel-adapter
automagically fines the configured connectionFactory bean (by naming convention
-->
<int-jms:outbound-channel-adapter channel="topicChannel"
destination-name="topic.myTopic"
pub-sub-domain="true" />
<!-- Create a channel for a listener that will consume messages-->
<int:channel id="listenerChannel" />
<int-jms:message-driven-channel-adapter id="messageDrivenAdapter"
channel="getPayloadChannel"
destination-name="topic.myTopic"
pub-sub-domain="true" />
<int:service-activator input-channel="listenerChannel" ref="messageListenerImpl" method="processMessage" />
<int:channel id="getPayloadChannel" />
<int:service-activator input-channel="getPayloadChannel" output-channel="listenerChannel" ref="retrievePayloadServiceImpl" method="getPayload" />
</beans>
Also please see the code:
Controller from where I am sending message in for loop at once:
#Controller
public class MessageController
{
#Autowired
private PublishService publishService;
#RequestMapping( value = "/message", method = RequestMethod.POST )
#ResponseBody
public void postMessage( #RequestBody com.geekcap.springintegrationexample.model.Message message, HttpServletResponse response )
{
for(int i = 0; i < 50; i++){
// Publish the message
publishService.send( message );
// Set the status to 201 because we created a new message
response.setStatus( HttpStatus.CREATED.value() );
}
}
}
Consumer code to which I have applied timer:
#Service
public class MessageListenerImpl
{
private static final Logger logger = Logger.getLogger( MessageListenerImpl.class );
public void processMessage( String message )
{
try {
Thread.sleep(10000);
logger.info( "Received message: " + message );
System.out.println( "MessageListener::::::Received message: " + message );
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Further by searching more I found here that As per the JMS specification, the default delivery mode is persistent. But in my case it does not seems to be worked.
Please help me to have right configuration in place so that messages can be persist across broker failure.
This is typically not a problem, but the way activeMQ was built.
you can find the following explanation in book 'ActiveMQ in action'
Once a message has been consumed and acknowledged by a message
consumer, it’s typically deleted from the broker’s message store.
So when you restart your server, it only shows you the messages which are in broker's message store. In most cases you will never have the need to have a look at the processed messages.
Hope this helps!
Good luck!

Spring + tomee JTA transactions

I have been struggling through trying to build a very simple application that deploys to tomee using spring, hibernate and JMS. I believe that all of my configurations are correct (have the mysql xa data source and the xa active mq connection factory) but things aren't working as I would expect. Currently I have a simple service that writes using the injected entity manager then pushes to JMS within one method that is annotated as being transactional (spring annotation) but my message listener is being delivered these messages before the transaction is committed in spring.
I've tried using JMS template and the xa connection factory directly, but neither works properly. The template is configured with the jta transaction manager received from jndi. Any ideas what to look at for hints as to why the JMS sends are not participating in the same transaction as the database writes?
Spring Configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:encryption="http://www.jasypt.org/schema/encryption"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd
http://www.jasypt.org/schema/encryption http://www.jasypt.org/schema/encryption/jasypt-spring31-encryption-1.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd"
default-autowire="byType" default-lazy-init="false">
<context:component-scan annotation-config="false" base-package="org.superbiz" />
<bean class="org.springframework.orm.jpa.DefaultJpaDialect" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="false" />
<property name="jndiFactory" >
<ref local="jndiFactory"/>
</property>
</bean>
<bean id="jndiFactory" class="org.springframework.jndi.support.SimpleJndiBeanFactory">
<property name="resourceRef" value="true" />
</bean>
<bean id="PrintTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref local="jmsFactory" />
</property>
<property name="defaultDestinationName" value="resources/jms/PrintQueue" />
<property name="deliveryPersistent" value="true"/>
<!-- <property name="sessionTransacted" value="true"/> -->
<!-- <property name="sessionAcknowledgeMode" value="0"/> -->
</bean>
<bean id="PersistTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref local="jmsFactory" />
</property>
<property name="defaultDestinationName" value="resources/jms/PersistQueue" />
<property name="deliveryPersistent" value="true"/>
<!-- <property name="sessionTransacted" value="true"/> -->
<!-- <property name="sessionAcknowledgeMode" value="0"/> -->
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="defaultPersistenceUnitName" value="movie-unit" />
<property name="persistenceContexts">
<map>
<entry key="movie-unit" value="persistence/movie-unit" />
</map>
</property>
</bean>
<context:component-scan base-package="org.superbiz.ejb" annotation-config="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<jee:jndi-lookup id="jmsFactory" jndi-name="resources/jms/ConnectionFactory" expected-type="javax.jms.ConnectionFactory" />
<tx:jta-transaction-manager />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="printBean" class="org.superbiz.mdb.PrintBean"/>
<bean id="persistBean" class="org.superbiz.mdb.PersistBean"/>
<jms:listener-container container-type="default" connection-factory="jmsFactory" cache="none" transaction-manager="transactionManager" concurrency="1" receive-timeout="1000" prefetch="-1">
<jms:listener destination="resources/jms/PrintQueue" ref="printBean" />
<jms:listener destination="resources/jms/PersistQueue" ref="persistBean" />
</jms:listener-container>
</beans>
tomee.xml (cobbled together from http://tomee-openejb.979440.n4.nabble.com/MDB-doesn-t-read-messages-td4666169.html)
<Resource id="ActiveMQResourceAdapter" type="ActiveMQResourceAdapter">
BrokerXmlConfig=broker:(vm://localhost)
</Resource>
<Resource id="resources/jms/ConnectionFactory" type="javax.jms.ConnectionFactory">
ResourceAdapter = ActiveMQResourceAdapter
</Resource>
<Resource id="resources/jms/XAConnectionFactory" class-name="org.apache.activemq.ActiveMQXAConnectionFactory">
BrokerURL = vm://localhost
ResourceAdapter = ActiveMQResourceAdapter
</Resource>
<Resource id="resources/jms/PrintQueue" type="javax.jms.Queue"/>
<Resource id="resources/jms/PersistQueue" type="javax.jms.Queue"/>
<Resource id="MySQL Database" type="DataSource">
JdbcDriver com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
JdbcUrl jdbc:mysql://localhost/test
UserName test
</Resource>
I've tried several ways to include not using the XAConnectionFactory with the JMSTemplate configured to be sessionTransacted and not, removing the JMSTemplate and creating the connection/session/producer/message from the connectionFactory, but I've run into an issue each time. With manually creating the connection/session/producer/message from the ConnectionFactory I notice that the 20 items I attempt to write to the database then send to another JMS Queue start being read before the services transaction completes.
As far as I can tell everything is configured correctly (although I could definitely be wrong since this was pulled from lots of places). My goal is to be able to use the JMSTemplate instead of manually creating the connection/session/etc myself, but I'm at a loss for why this is happening at this point so any ideas are greatly appreciated.
I've also bumped the logging of the Spring JtaTransactionManager up and I see the following happening when the #Transactional method is called
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.superbiz.ejb.Movies.send]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
Then I see the my MDB code trying to retrieve the item from the entityManager (which works/fails intermittently). When it succeeds I see this
printing from MDB: director: director0title: title0year: 0
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
When it fails I see this
/***************** BROKEN ***************/
/*******************435265*****************/
/***************** BROKEN ***************/
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
I've further cranked up the logging
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#1]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
**bold** [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jms.connection.JmsResourceHolder#81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]
[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jms.connection.JmsResourceHolder#eaebd86] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1]
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Participating in existing transaction
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Getting transaction for [org.superbiz.mdb.PersistBean.onMessage]
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.jms.connection.JmsResourceHolder#81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] bound to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]
Persisted finished, but not yet committed
Leaving persist, should commit
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [org.superbiz.mdb.PersistBean.onMessage]
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.jta.JtaTransactionManager - Triggering beforeCommit synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.jta.JtaTransactionManager - Triggering beforeCompletion synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.jms.connection.JmsResourceHolder#81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] from thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]
**bold** [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
Entering print
/***************** BROKEN ***************/
/*******************597852*****************/
/***************** BROKEN ***************/
in this case DefaultMessageListenerContainer#1-1 is my Persist bean and 0-1 is a bean that retrieves the entity by id and then prints the content.
I am not 100% sure how to read this, but it's interesting to me that the DMLC#1-1 commits well after a new transaction has begun on DMLC#0-1, but DMLC#0-1 sees the message. I would have thought that DMLC#0-1 would have needed to start a new transaction to see this OR since he received the JMS message the entity should also be persisted to the database.
Contents of my persist bean
#Override
#Transactional
public void onMessage(Message message) {
TextMessage msg = (TextMessage)message;
int x;
try {
x = Integer.parseInt(msg.getText());
Movie movie = new Movie("director" + x, "title" + x, x);
entityManager.persist(movie);
final long id = movie.getId();
template.send(new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(Long.toString(id));
}
});
System.out.println("Persisted finished, but not yet committed");
System.out.println("Leaving persist, should commit");
} catch (Exception e) {
e.printStackTrace();
}
}
Contents of my print bean
public void onMessage(Message message) {
System.out.println("Entering print");
final TextMessage textMessage = (TextMessage) message;
try {
long id = Long.parseLong(textMessage.getText());
Movie movie = entityManager.find(Movie.class, id);
if(movie == null){
System.out.println("/***************** BROKEN ***************/");
System.out.println("/*******************" + id + "*****************/");
System.out.println("/***************** BROKEN ***************/");
} else {
System.out.println("updating: "+ movie);
}
} catch (Exception e) {
e.printStackTrace();
}
}
The entire app is available at https://github.com/jej2003/simple-spring, running a vanilla Tomee 1.7.1 with the necessary hibernate jars added to the tomee/lib directory.
I'm really at a loss here, does no one run JTA transactions in Tomee with Spring?
After a ton of debugging it turns out that the failure was not in the JTA implementation, but more so my understanding of JTA in general. While JTA ensures that both transactions will successfully commit, it does not enforce an order apparently of those transactions. The answer was ultimately provided here https://jira.spring.io/browse/SPR-12535, by Stéphane Nicoll.

Hibernate doesn't save edited entities, while saves new ones

I'm facing a weird problem. I'm currently writing a web application based on Spring-MVC 3.2, and Hibernate 4.1.9. I wrote a sample controller with its TestNG unit tests, and everything is fine except for editing. I can see that when saving a new object, it works like a charm, but if I try to edit an existing object, it doesn't get saved without giving out any reason (I'm calling the same method for adding and updating).
The log of adding a new object of type Application
14:26:36.636 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/add.json]
14:26:36.637 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/add.json
14:26:36.650 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.createApp(com.wstars.kinzhunt.platform.model.apps.Application)]
14:26:36.651 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController'
14:26:36.821 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:26:36.890 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:26:36.890 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968
14:26:36.892 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: com.wstars.kinzhunt.platform.model.apps.Application#54fc519b[id=<null>,name=KinzHunt,company=com.wstars.kinzhunt.platform.model.apps.Company#151c2b4[id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.kinzhunt.com,senderEmail=no-reply#kinzhunt.com,logoUrl=<null>]
14:26:36.892 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:26:36.893 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968
14:26:36.893 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:26:36.894 [main] DEBUG o.h.e.def.AbstractSaveEventListener - executing identity-insert immediately
14:26:36.898 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
14:26:36.899 [main] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
14:26:36.899 [main] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1]
14:26:36.901 [main] DEBUG org.hibernate.SQL - /* insert com.wstars.kinzhunt.platform.model.apps.Application */ insert into applications (id, callback_url, company_id, logo_url, name, sender_email, website) values (null, ?, ?, ?, ?, ?, ?)
14:26:36.904 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2
14:26:36.904 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
14:26:36.905 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
14:26:36.926 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [2] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:26:36.927 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
14:26:36.928 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
While the log for saving an edited object is
14:27:03.398 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/1/edit.json]
14:27:03.398 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/1/edit.json
14:27:03.401 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.editApp(com.wstars.kinzhunt.platform.model.apps.Application,java.lang.Long)]
14:27:03.401 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController'
14:27:03.404 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:27:03.409 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:27:03.410 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234
14:27:03.411 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: com.wstars.kinzhunt.platform.model.apps.Application#1ba4f8a6[id=1,name=KinzHunt,company=com.wstars.kinzhunt.platform.model.apps.Company#6bc06877[id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.wstars.com/KinzHunt/,senderEmail=no-reply#kinzhunt.com,logoUrl=<null>]
14:27:03.412 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:27:03.412 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234
14:27:03.413 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:27:03.422 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:27:03.424 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [1] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:27:03.424 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
14:27:03.425 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
As you can see, in the second log, no prepared statement is created, and no JDBC connection is opened. My test configuration for the database is like this:
<bean id="targetDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="targetDataSource" />
<property name="packagesToScan">
<list>
<value>com.mypackage.model.*</value>
</list>
</property>
<property name="namingStrategy">
<bean class="com.example.common.config.MyOwnNamingStrategy"/>
</property>
<property name="hibernateProperties">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<entry key="hibernate.max_fetch_depth" value="1" />
<entry key="hibernate.use_sql_comments" value="true" />
<entry key="hibernate.hbm2ddl.auto" value="update" />
</map>
</property>
<!-- <property key="hibernate.current_session_context_class" value="thread"/> -->
<!-- <property key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JDBCTransactionFactory"/> -->
</bean>
<bean id="h2WebServer" class="org.h2.tools.Server"
factory-method="createWebServer" depends-on="targetDataSource"
init-method="start" lazy-init="false">
<constructor-arg value="-web,-webPort,11111" />
</bean>
My controller code is:
#Controller
public class AppController extends BaseAnnotatedController {
#Autowired
private AppManagementService appManagementService;
#RequestMapping(value="/app/add", method=RequestMethod.POST, consumes={"application/json"})
public #ResponseBody Long createApp(#RequestBody Application app) {
saveApp(app);
return app.getId();
}
#RequestMapping(value="/app/{appId}/edit", method=RequestMethod.POST, consumes={"application/json"})
public #ResponseBody Long editApp(#RequestBody Application app, #PathVariable Long appId) {
if (!appId.equals(app.getId())) {
WSError error = new WSError(ValidationErrorType.GENERIC, "id");
throw new ValidationException(error);
} else {
saveApp(app);
return app.getId();
}
}
#RequestMapping(value="/app/list", method=RequestMethod.GET)
public #ResponseBody List<Application> listApps() {
return appManagementService.listAllApps();
}
#RequestMapping(value="/app/{appId}/get", method=RequestMethod.GET)
public #ResponseBody Application getAppDetails(#PathVariable Long appId) {
return appManagementService.getApplication(appId);
}
private void saveApp(Application app) {
if (isValid(app)) {
appManagementService.saveApp(app);
}
}
public #ResponseBody List<Application> listAllApps() {
return appManagementService.listAllApps();
}
}
My test class is:
#Test
public class AppControllerIntegrationTests extends AbstractContextControllerTests {
private MockMvc mockMvc;
#Autowired
AppController appController;
#Autowired
private AppManagementService appManagementService;
#Autowired
private BaseDao baseDao;
#BeforeClass
public void classSetup() {
Company comp = new Company();
comp.setName("Some Company");
baseDao.saveObject(comp);
}
#BeforeMethod
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void testAddInvalidAppWebJson() throws Exception {
String appJson = getInvalidApp().toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
ResultActions resultAction = this.mockMvc.perform(requestBuilder);
resultAction.andExpect(status().isForbidden());
MvcResult mvcResult = resultAction.andReturn();
Exception resolvedException = mvcResult.getResolvedException();
assertTrue(resolvedException instanceof ValidationException);
ValidationException validationException = (ValidationException) resolvedException;
assertEquals(validationException.getErrors().size(), 3);
}
#Test
public void testAddAppWebJson() throws Exception {
Application app = getMockApp();
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk());
}
#Test
public void testEditAppWithWrongIdWebJson() throws Exception {
String appJson = getMockAppWithId().toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/2/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc
.perform(requestBuilder)
.andExpect(status().isForbidden())
.andExpect(
content()
.string("{\"errors\":[{\"errorType\":\"-100\",\"field\":\"id\",\"constraint\":null}],\"objects\":null}"));
}
#Test(dependsOnMethods={"testAddApp", "testAddAppWebJson"})
public void testEditAppWebJson() throws Exception {
Application app = getMockAppWithId();
setAppWebsiteToDifferentOne(app);
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk());
}
#Test
public void testEditInvalidAppWebJson() throws Exception {
Application app = getMockAppWithId();
app.setWebsite("Saba7o 3asal");
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc
.perform(requestBuilder)
.andExpect(status().isForbidden())
.andExpect(
content()
.string("{\"errors\":[{\"errorType\":\"-114\",\"field\":\"website\",\"constraint\":null}],\"objects\":null}"));
}
#Test(dependsOnMethods="testEditAppWebJson")
public void testGetAppDetails() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/app/1/get.json");
Application app = getMockAppWithId();
setAppWebsiteToDifferentOne(app);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk())
.andExpect(content().string(app.toJsonString()));
}
}
My service method is:
#Override
#Transactional(readOnly=false)
public void saveApp(Application app) {
baseDao.saveObject(app);
}
All test methods pass, except for the last one, since it's expecting the website of the app to be the one which was edited. Where have I gone wrong?
Need to know which hibernate method is called in saveApp() also make sure your service is annotated with #Transactional.

Spring integration: Receiving JMS messages via adapter randomly fails

I am trying to write channel adapter for JMS queue. I'd like to send message to JMS queue and receive it on Spring Integration's channel.
When I use plain JMS (with ActiveMQ), everything works properly, so I assume bug is somewhere in my Spring code.
So here's my Spring config 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:int="http://www.springframework.org/schema/integration"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<!-- jms beans -->
<bean id="jms.msgQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="MSG_QUEUE" />
</bean>
<bean name="jms.connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<!-- spring integration beans -->
<int:channel id="channels.jms.allMessages">
<int:queue capacity="1000" />
</int:channel>
<jms:inbound-channel-adapter id="adapters.jms.msgAdapter"
connection-factory="jms.connectionFactory"
destination="jms.msgQueue"
channel="channels.jms.allMessages">
<int:poller fixed-rate="500" />
</jms:inbound-channel-adapter>
</beans>
Here is plain JMS sending-receiving code that works without problems:
#Test
public void testPlainJms() throws JMSException {
MessageProducer producer = session.createProducer(msgQueue);
MessageConsumer consumer = session.createConsumer(msgQueue);
// send to JMS queue
TextMessage textMessage = session.createTextMessage();
textMessage.setText("Message from JMS");
producer.send(textMessage);
connection.start();
javax.jms.Message message = consumer.receive(TIMEOUT);
assertEquals("Message from JMS", ((TextMessage) message).getText());
connection.stop();
}
And here is code using Spring's MessageChannel that usually doesn't work (it sometimes does but I am not able to determine when):
#Test
public void testInboundAdapter() throws JMSException {
MessageProducer producer = session.createProducer(msgQueue);
// send to JMS queue
TextMessage textMessage = session.createTextMessage();
textMessage.setText("Message from JMS");
producer.send(textMessage);
// receive in local channel (using inbound adapter)
Message<?> received = ((PollableChannel) msgChannel).receive(TIMEOUT);
String payload = (String) received.getPayload();
assertEquals("Message from JMS", payload);
}
I am getting NullPointerException on receiving message from pollable msgChannel. Here's how I autowired beans from Spring config to my test class:
#Autowired #Qualifier("jms.msgQueue")
Queue msgQueue;
#Autowired #Qualifier("channels.jms.allMessages")
MessageChannel msgChannel;
#Autowired
ConnectionFactory connectionFactory;
Strange, I am able to reproduce your issue, could be a bug with inbound-channel-adapter, I have something which consistently works though, by changing from an inbound-channel-adapter to message-driven-channel-adapter, try with this:
<jms:message-driven-channel-adapter id="adapters.jms.msgAdapter"
connection-factory="jms.connectionFactory"
destination="jms.msgQueue"
channel="channels.jms.allMessages" />
It fail when it timeout.
Message<?> received = ((PollableChannel) msgChannel).receive(TIMEOUT);
You must check received for null

Resources