Connect to embedded ActiveMQ from different Spring Boot project - spring-boot

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.

Related

Access denied to resource: type=<jms>, application=JMSModule, destinationType=queue, resource=test, action=receive

I'm try to receive a weblogic server jms in spring boot . But I have encountered this problem after launch application successfully.
[]org.springframework.jms.listener.DefaultMessageListenerContainer:handleListenerSetupFailure(892): Setup of JMS message listener invoker failed for destination 'jms/test' - trying to recover. Cause: Access denied to resource: type=<jms>, application=JMSModule, destinationType=queue, resource=ns-alert-test, action=receive
And I found it can be connect successfully in thread of [main] when launching.
It looks like the username and password is missed when thread changed
[main] org.springframework.jndi.JndiObjectFactoryBean:lookup(112): Located object with JNDI name [jms/rtsConnectionFactory]
And I'm try to use wlfullclient.jar and wlclient.jar and wlthint3client.jar in my project . But the problem still exists. Can you give me some suggest of this problem . Below is my code
Config:
#Autowired
private JmsErrorHandler jmsErrorHandler;
#Autowired
private JMSPropertiesConfig jmsPropertiesConfig;
#Bean
public JndiTemplate jndiTemplate(){
JndiTemplate jndiTemplate =new JndiTemplate();
Properties properties = new Properties();
properties.setProperty("java.naming.factory.initial","weblogic.jndi.WLInitialContextFactory");
properties.setProperty("java.naming.provider.url", jmsPropertiesConfig.getUrl());
if(jmsPropertiesConfig.getUname()!=null){
properties.setProperty("username", jmsPropertiesConfig.getUname());
}
if(jmsPropertiesConfig.getUcert()!=null){
properties.setProperty("password", jmsPropertiesConfig.getUcert());
}
jndiTemplate.setEnvironment(properties);
return jndiTemplate;
}
#Bean
public JndiDestinationResolver jmsDestionationProvider() {
JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
destinationResolver.setJndiTemplate(jndiTemplate());
return destinationResolver;
}
#Bean
public JndiObjectFactoryBean connectionFactory(){
JndiObjectFactoryBean cf = new JndiObjectFactoryBean();
cf.setJndiTemplate(jndiTemplate());
cf.setJndiName(jmsPropertiesConfig.getFactory());
return cf;
}
#Bean
public JmsTemplate jmsTemplate(){
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory((ConnectionFactory) connectionFactory().getObject());
template.setSessionAcknowledgeModeName("AUTO_ACKNOWLEDGE");
template.setSessionTransacted(true);
template.setDestinationResolver(jmsDestionationProvider());
return template;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory((ConnectionFactory) connectionFactory().getObject());
factory.setDestinationResolver(jmsDestionationProvider());
factory.setErrorHandler(jmsErrorHandler);
factory.setSessionAcknowledgeMode(0);
return factory;
}
Receive:
#JmsListener(destination = "jms/test")
public void receiveApplicationNotification(String input) throws Exception {
log.info("Receiving message from jms.external.ExampleQueue.queue "+input);
}
Seems to be a bug in Weblogic.
Can you please try applying below patch..
Bug 22550927 - WEBLOGIC JMS CONNECTION IS NOT THREAD-SAFE

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;
}

Spring Boot ActiveMQ embedded Broker

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?

activeMQ does not participate in Weblogic XA transactions

I try to get XA transactions involving a jdbc and jms DataSource working in a Spring webapp deployed to Weblogic.
Using a local Atomikos TransactionManager, this works - I see XA debug messages in ActiveMQ, and stuff stays consistent. In Weblogic however, the database and ActiveMQ are not transactionally consistent.
I have added a foreign JMS server in Weblogic
JNDI Initial Context Factory:
org.apache.activemq.jndi.ActiveMQInitialContextFactory
JNDI Connection URL:
tcp://localhost:61616
JNDI Properties:
connectionFactoryNames=XAConnectionFactory
To that server, I have added a ConnectionFactory (Remote JNDI Name = XAConnectionFactory). Lookups work, so far so good.
In my code, this is how I setup the Spring JTA:
#Override
#Bean
#Profile(AppConfig.PROFILE_WEBLOGIC)
public JtaTransactionManager transactionManager()
{
WebLogicJtaTransactionManager tx = new WebLogicJtaTransactionManager();
tx.afterPropertiesSet();
return tx;
}
And this is my JMS config:
#Bean
#Profile(AppConfig.PROFILE_WEBLOGIC)
public ConnectionFactory connectionFactory()
{
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, env.getProperty(Context.INITIAL_CONTEXT_FACTORY));
props.setProperty(Context.PROVIDER_URL, env.getProperty(Context.PROVIDER_URL));
try
{
InitialContext ctx = new InitialContext(props);
ActiveMQXAConnectionFactory connectionFactory = (ActiveMQXAConnectionFactory) ctx
.lookup(env.getProperty("jms.connectionFactory"));
return connectionFactory;
}
catch(NamingException e)
{
throw new RuntimeException("XAConnectionFactory lookup failed", e);
}
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() throws JMSException
{
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
factory.setTransactionManager(txConfig.transactionManager());
factory.setBackOff(new FixedBackOff());
return factory;
}
#Bean(name = "jmsTemplate")
#Override
public JmsTemplate jmsTemplate() throws JMSException
{
JmsTemplate t = new JmsTemplate();
t.setConnectionFactory(connectionFactory());
t.setMessageTimestampEnabled(true);
t.setMessageIdEnabled(true);
return t;
}
My JMS consumer is annotated with:
#Transactional
#JmsListener(destination = "test.q1")
Is there anything I am missing?
Turns out this only works via the Resource Adapter, its not possible solely via the JNDI ConnectionFactory.
It is possible, using the undocumented ActiveMQ JNDI property "xa=true" in the foreign JMS server definition, see here:
Deployment of ActiveMQ resource adapter fails
ActiveMQInitialConnectionFactory cannot return an
XAConnectionFactory
ActiveMQInitialConnectionFactory returns XA
connection factory

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