Spring Boot ActiveMQ embedded Broker - spring-boot

I am using Spring Boot with embedded Broker as below:
#Configuration
#EnableJms
public class JmsConfig {
#Bean
public BrokerService brokerService() throws Exception {
BrokerService broker = new BrokerService();
broker.addConnector("tcp://localhost:61616");
broker.setPersistent(false);
return broker;
}
}
How can I do, if I want to detect when a client connected?

Related

Spring Tomcat configuration for JMS (IBM MQ, Tomcat, Spring)

I have a relatively old application that uses Websphere MQ for messaging. It runs on WAS (Websphere Application Server) and uses MDBs (Message Driven Beans). I have to migrate that application from Websphere so Tomcat
I tried something using springboot and was able to write a sample JMS application that connects to queues and read messages and is able to process them but have not implemented transaction management with JMS.
Now I have been asked to configure the application so that it runs on tomcat.
Can anyone please help, how and where I have to setup configuration in tomcat.
Or what all changes will be required if package my springboot application as war and deploy it on Tomcat.
This is how my code in applicationconfig.java looks like
#Bean(name = "mqQueueConnectionFactory")
public MQQueueConnectionFactory mqQueueConnectionFactory() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
try {
mqQueueConnectionFactory.setHostName("hostname");
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setCCSID(1208);
mqQueueConnectionFactory.setChannel("channel");
mqQueueConnectionFactory.setPort(1415);
mqQueueConnectionFactory.setQueueManager("qManager");
} catch (Exception e) {
System.out.println("MQQueueConnectionFactory bean exception" + e);
}
return mqQueueConnectionFactory;
}
#Bean
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(
MQQueueConnectionFactory mqQueueConnectionFactory) {
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
userCredentialsConnectionFactoryAdapter.setUsername("");
userCredentialsConnectionFactoryAdapter.setPassword("");
userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
return userCredentialsConnectionFactoryAdapter;
}
#Bean
#Primary
public CachingConnectionFactory cachingConnectionFactory(
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
cachingConnectionFactory.setReconnectOnException(true);
return cachingConnectionFactory;
}
#Bean
public JmsOperations jmsOperations(CachingConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setReceiveTimeout(50000);
return jmsTemplate;
}
#Bean(name = "wmq")
public JmsComponent wmQ(#Value(AppConstants.WMQ_CONNECTION_TYPE) int connType,
#Value(AppConstants.WMQ_HOST) String hostName,
#Value(AppConstants.WMQ_PORT) Integer port,
#Value(AppConstants.WMQ_QUEUE_MANAGER) String queueManager,
#Value(AppConstants.WMQ_CHANNEL) String channel,
#Value(AppConstants.WMQ_CONCURRENT_CONSUMERS) int concurrentConsumers,
#Value(AppConstants.WMQ_USERNAME) String username,
#Value(AppConstants.WMQ_PASSWORD) String password
) throws JMSException {
JmsComponent jmsComponent = new JmsComponent();
MQConnectionFactory mqConnectionFactory = new MQConnectionFactory();
try {
mqConnectionFactory.setTransportType(connType);
mqConnectionFactory.setHostName(hostName);
mqConnectionFactory.setPort(port);
mqConnectionFactory.setQueueManager(queueManager);
mqConnectionFactory.setChannel(channel);
jmsComponent.setConnectionFactory(mqConnectionFactory);
JmsConfiguration jmsConfiguration = new JmsConfiguration(mqConnectionFactory);
jmsConfiguration.setUsername(username);
jmsConfiguration.setPassword(password);
jmsConfiguration.setConcurrentConsumers(concurrentConsumers);
jmsComponent.setConfiguration(jmsConfiguration);
} catch (JMSException e) {
String msg = "Error while creating IBM MQ Connection Factory";
throw new JMSException(msg);
}
return jmsComponent;
}

Connect to embedded ActiveMQ from different Spring Boot project

I have a Spring Boot project configured with ActiveMQ. There is another Spring Boot project which is acting as the consumer of that ActiveMQ instance. When I tried to connect it always shows the error message
retrying using FixedBackOff{interval=5000, currentAttempts=113,
maxAttempts=unlimited}. Cause: Could not connect to broker URL:
tcp://localhost:61616. Reason: java.net.ConnectException: Connection
refused (Connection refused)
Following is my configurations in the consumer project.
#Configuration
#EnableJms
public class Config {
#Autowired
ConnectionFactory connectionFactory;
#Autowired
MessageListener messageListener;
#Bean
public ActiveMQQueue getQueue(){
return new ActiveMQQueue("my.queue");
}
#Bean
public ActiveMQConnectionFactory getActiveMQConnectionFactory(){
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL("tcp://localhost:61616");
//activeMQConnectionFactory.setBrokerURL("vm://localhost");
return activeMQConnectionFactory;
}
#Bean
public JmsTemplate getJmsTemplate(){
return new JmsTemplate(activeMQConnectionFactory());
}
#Bean
public MessageListenerContainer getContainer() {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
container.setConnectionFactory(connectionFactory);
container.setMessageListener(messageListener);
container.setDestinationName("my.queue");
return container;
}
How can I connect to the embedded ActiveMQ running on the other project? Both projects are running on same vm.

Activemq web console in Spring

I am creating an embedded ActiveMQ broker in Spring application like this:
#EnableJms
#Configuration
public class MqConfig {
#Bean
public BrokerService broker() throws Exception {
BrokerService broker = new BrokerService();
broker.setBrokerName("ETL");
broker.addConnector("tcp://localhost:61616");
broker.start();
return broker;
}
}
How can I embed the ActiveMQ Admin Web console also in the same spring application? Searched the net for 2-3 hours, but found no useful answer. The only thing that ActiveMQ site mentions is this http://activemq.apache.org/web-console.html, however is not useful with Spring

Atomikos Transaction management spring boot/spring jams

I have a spring boot application with spring JMS using DefaultMessageListener container. I am using Atomikos for transaction management.
On exception the message queue roll back works fine and messages do move to back out queue, but the database updates do not roll back. I have set the autoconfigured JtaTransactionManager on DefaultMessageContainerBean. Are there any other configurations required here to get a true global transaction management. I am using My Batis for database.
public class CusListener implements MessageListener{
public void onMessage(Message message) {
//Database call
catch (Exception ex) {
throw (new RuntimeException());
}
}
}
#Configuration
public class ListenerContainer{
#Bean
public DefaultMessageListenerContainer defaultMessageListenerContainer(ConnectionFactory queueConnectionFactory,MQQueue queue, MessageListener listener,
JtaTransactionManager jtaTransactionManager) {
DefaultMessageListenerContainer defaultMessageListenerContainer =
new DefaultMessageListenerContainer();
defaultMessageListenerContainer.setConnectionFactory(queueConnectionFactory);
defaultMessageListenerContainer.setDestination(queue);
defaultMessageListenerContainer.setMessageListener(listerner);
defaultMessageListenerContainer.setTransactionManager(jtaTransactionManager);
defaultMessageListenerContainer.setSessionTransacted(true);
defaultMessageListenerContainer.setConcurrency("3-10");
return defaultMessageListenerContainer;
}
//other beans declaration passed in the method above
}
#Configuration
public class PlanListenerSqlSessFac {
#Bean(name="sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(#Qualifier("dataSource") NMCryptoDataSourceWrapper dataSource) throws Exception {
}
#Bean(name="driverManagerDataSource")
public DriverManagerDataSource driverManagerDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
return driverManagerDataSource;
}
}
You should use AtomikosDataSourceBean as dataDource.
See documentation : https://www.atomikos.com/bin/view/Documentation/ConfiguringJdbc

Ensuring Spring Integration deployment's JMS listener threads are cleaned up on Tomcat undeploy

I have a simple Spring Integration application which runs on Tomcat (v7.0.x) and consumes messages off a Websphere MQ Queue. When I un-deploy the WAR from the Tomcat server, the WAR un-deploys okay but, a JMS listener thread is left running on the Tomcat server which will still consume messages off the Websphere MQ Queue. I am therefore assuming that I am not handling the JMS listener clean up part of the application properly?
Here is the stack I am using:
Java 8
Tomcat 7.0.55
Spring Integration 4.0.4
Spring Integration Java Dsl 1.0.0.M3
In terms of my SI application's configurations, I have a JmsConfig class:
#Configuration
#ComponentScan
public class JmsConfig {
#Autowired
private Properties jndiProperties;
private ConnectionFactory mqConnectionFactory() throws NamingException {
Context ctx = new InitialContext(jndiProperties);
try {
MQQueueConnectionFactory connectionFactory = (MQQueueConnectionFactory)
ctx.lookup("jms/service/SERVICE_QCF");
return connectionFactory;
} finally {
ctx.close();
}
}
#Bean
public ConnectionFactory cachingConnectionFactory() throws NamingException {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setTargetConnectionFactory(mqConnectionFactory());
connectionFactory.setSessionCacheSize(10);
return connectionFactory;
}
}
I have an Integration config class:
#Configuration
#EnableIntegration
public class IntegrationConfig {
#Autowired
private ConnectionFactory cachingConnectionFactory;
#Bean
public IntegrationFlow requestFlow() {
return IntegrationFlows
.from(Jms.inboundAdapter(cachingConnectionFactory).destination(
"SERVICE_QUEUE_NAME"), c -> {
c.poller(Pollers.fixedRate(100));
})
.channel("request.service.ch").get();
}
}
Web Initialiser config class:
#Configuration
public class WebInitialiser implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext)
throws ServletException {
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(ApplicationConfig.class, JmsConfig.class,
IntegrationConfig.class, DatabaseConfig.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
During the un-deploy stage I see the following in the catalina logs which may or may not be related:
SEVERE: The web application [/service-a] appears to have started a thread named [Thread-7] but has failed to stop it. This is very likely to create a memory leak.
Is there anything that I have yet NOT set or configured or annotated in order to ensure that the deployment's JMS listener thread is cleaned up from Tomcat's JVM during the WAR's un-deploy stage?
Thanks in advance,
PM.
To ensure that JMS listener threads are cleared up upon the application's un-deploy stage, I simply created a CachingConnectionFactory bean with its targetConnectionFactory being that of the MQConnectionFactory. Then, in the Spring Integration flows, I simply pass in the cachingConnectionFactory bean to the JMS adapters instead. I've updated the configs in this post to show this. Cheers, PM.

Resources