I am able to successfully integrate ActiveMQ(in bound message driven channel) and Kafka (as outbound channel). It working fine.
Now, since Both ActiveMQ and MQ Series are JMS compliant, i thought transition would be easier. But, its throwing below error :
Setup of JMS Message listener invoker failed for destination 'queue://abcd' - trying to recover - Cause: JMSQ1112: The operation for a domain specific object was not valid. The operation 'createConsumer' is not valid for type 'com.ibm.mq.jms.MQQueue'
My spring integration config looks like 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:jms="http://www.springframework.org/schema/integration/jms"
xmlns:integration="http://www.springframework.org/schema/integration"
xmlns:int-kafka="http://www.springframework.org/schema/integration/kafka"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/kafka
http://www.springframework.org/schema/integration/kafka/spring-integration-kafka.xsd">
<jms:message-driven-channel-adapter id="requestChannelAdapter" channel="requestChannel"
container="requestListenerContainer" error-channel=""/>
<int-kafka:outbound-channel-adapter
id="kafkaOutboundChannelAdapter" kafka-template="kafkaTemplate"
auto-startup="true" sync="true" channel="inputToKafka" topic="test">
</int-kafka:outbound-channel-adapter>
</beans>
And my respective code looks like below:
public MQQueueConnectionFactory jmsConnectionfactory() {
MQQueueConnectionFactory jmsFactory = new MQQueueConnectionFactory();
jmsFactory.setHostName(hostname);
jmsFactory.setPort(1444);
jmsFactory.setQueueManager(//valid queue manager);
jmsFactory.setChannel(//valid channel name);
jmsFactory.setTransportType(1);
jmsFactory.setSSLCipherSuite(// valid suite);
return jmsFactory;
}
#Bean
public DefaultMessageListenerContainer requestListenerContainer() {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(jmsConnectionfactory());
container.setSessionTransacted(true);
container.setDestination(helloJMSQueue());
return container;
}
#Bean
public Queue helloJMSQueue() {
return new MQQueue(HELLO_QUEUE);
}
Why I am getting this error ? I saw some posts that it is due to pubLocal value not available in jmsTemplate w.r.t MQQueue but that was dated back to 2005 and i noticed the change has been released.
Use just container.setDestinationName(HELLO_QUEUE) instead and let the container to resolve it properly over Session.
We would like to migrate our Spring application from JBoss 7.1.1 to WildFly 10.1. We used CXF based and Spring managed web services but on WildFly 10.1 we couldn't configure these services.
We tried two methods.
When we use WildFly webservices subsystem the web services are published correctly but in WS implementation we can't access spring managed beans.
When we exclude webservices subsystem in the jboss-deployment-structure.xml, configure CXFServlet in web.xml and configure jaxws:endpoint in spring xml configuration file the log shows that service creation is ok, but not based on the real implementation. Wrong service name, namespace and address.
Used spring configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxws.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="testWs" implementor="ns.test.ws.impl.TestWsImpl"
address="/test">
<jaxws:properties>
<entry key="schema-validation-enabled" value="true" />
</jaxws:properties>
</jaxws:endpoint>
</beans>
Log content:
18:31:11,783 INFO
[org.springframework.beans.factory.xml.XmlBeanDefinitionReader]
(ServerService Thread Pool -- 58) Loading XML bean definitions from
class path resource [META-INF/cxf-beans.xml] 18:31:12,177 INFO
[org.springframework.beans.factory.xml.XmlBeanDefinitionReader]
(ServerService Thread Pool -- 58) Loading XML bean definitions from
class path resource [META-INF/cxf/cxf.xml] 18:31:12,290 INFO
[org.springframework.beans.factory.xml.XmlBeanDefinitionReader]
(ServerService Thread Pool -- 58) Loading XML bean definitions from
class path resource [META-INF/cxf/cxf-extension-jaxws.xml]
18:31:12,455 INFO
[org.springframework.beans.factory.xml.XmlBeanDefinitionReader]
(ServerService Thread Pool -- 58) Loading XML bean definitions from
class path resource [META-INF/cxf/cxf-servlet.xml] 18:31:12,960
INFO
[org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean]
(ServerService Thread Pool -- 58) Creating Service
{http://impl.ws.test.ns/}TestWsImplService from class
ns.test.ws.impl.TestWsImpl
WS implementation:
package ns.test.ws.impl;
import java.util.ArrayList;
import javax.jws.WebService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import ns.test.ws.api.TestWs;
import ns.test.ws.domain.ApplicationInfo;
import ns.test.ws.domain.ApplicationInfoRequest;
import ns.test.ws.domain.ApplicationInfoResultContainer;
import ns.test.ws.domain.CallContext;
import ns.test.ws.domain.ResultContext;
import ns.test.ws.domain.ResultMessage;
#WebService(name = "ApplicationInfoService", serviceName = "ApplicationInfoService", portName = "ApplicationInfoServicePort", endpointInterface = "ns.test.ws.api.TestWs", targetNamespace = "http://test.ns/")
#Transactional
public class TestWsImpl implements TestWs {
#SuppressWarnings("unused")
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestWsImpl.class);
#Autowired
private VersionInfo versionInfo;
public ApplicationInfoResultContainer test(CallContext callContext, ApplicationInfoRequest appInfoRequest) {
ApplicationInfo result = new ApplicationInfo();
result.setAppName(versionInfo.getAppName());
result.setAppVersion(versionInfo.getVersion());
ResultContext resultContext = new ResultContext();
resultContext.setCorrelationId("corrId");
resultContext.setHighestMessageSeverity("W");
resultContext.setMessageList(new ArrayList<ResultMessage>());
resultContext.getMessageList().add(new ResultMessage("code", "sev", "system", "message"));
return new ApplicationInfoResultContainer(result, resultContext);
}
}
What do we wrong? How should we configure the spring application?
Used dependencies:
WildFly 10.1
CXF 3.1.6 (WildFly 10.1 module)
Spring 4.3.7
I found the solution. See my sample code on the following repo.
https://github.com/SeniorRoland/spring-wildfly
I have requirement where I need receive message from MQ every seconds , the message will be in XML format , so i need to write a high effecient MDB. Problem here is I am new to MQ,JMS,Spring JMS and Spring Integration but not spring tough.
Based on google search so far I am able to write below code
MDB
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class MyMessageListener implements MessageListener{
#Override
public void onMessage(Message m) {
TextMessage message=(TextMessage)m;
try{
System.out.println(message.getText());
}catch (Exception e) {e.printStackTrace(); }
}
}
XMl config
<?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:jms="http://www.springframework.org/schema/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />
<bean id="listener" class="com.springexample.MyMessageListener"></bean>
<jms:listener-container container-type="default" connection-factory="connectionFactory"
acknowledge="auto">
<jms:listener destination="myfirstqueue" ref="listener" method="onMessage"></jms:listener>
</jms:listener-container>
</beans>
I know what i have written is very basic one but i dont know what is the efficient one , how to provide transaction support and how to handle such load where i am going to recieve message every seconds.
Should i use Spring JMS or Spring Integration any help is much appreciated.
The question you asked is which to use: definitely go Spring JMS
I am new to this Spring Integration and JMS and i started playing with it. In here i want to create plain jms message via activemq and receive it through spring inbound adapter(message driven).
following is my spring config file
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
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/stream
http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd>
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<!-- jms beans -->
<beans:bean id="jms.msgQueue" class="org.apache.activemq.command.ActiveMQQueue">
<beans:constructor-arg value="MSG_QUEUE" />
</beans:bean>
<beans:bean name="jms.connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<beans:property name="brokerURL" value="tcp://localhost:61616" />
</beans:bean>
<!-- spring integration beans -->
<channel id="channels.jms.allMessages">
<queue capacity="1000" />
</channel>
<jms:message-driven-channel-adapter id="adapters.jms.msgAdapter"
connection-factory="jms.connectionFactory"
destination="jms.msgQueue"
channel="channels.jms.allMessages" />
and this is my testing class
package com.bst.jms;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.core.PollableChannel;
public class TestActiveMQ {
public static void main(String[] args){
try{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("app-context.xml");
ConnectionFactory connectionFactory = (ConnectionFactory)context.getBean("jms.connectionFactory");
Destination destination = (Destination)context.getBean("jms.msgQueue");
PollableChannel msgChannel = (PollableChannel) context.getBean("channels.jms.allMessages", PollableChannel.class );
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(destination);
TextMessage textMessage = session.createTextMessage();
textMessage.setText("Message from JMS");
producer.send(textMessage);
System.out.println("--------------- Message Sending ------------------------");
Message<?> received = msgChannel.receive();
String payload = (String) received.getPayload();
System.out.println("Receving message = " + payload);
}catch(JMSException ex){
System.out.println("----------- JMS Exception --------------");
}
}
}
But the thing is i can not guarantee the delivery. some times the program can not receive the message and some tomes it succeeds with some warnings like
Setup of JMS message listener invoker failed for destination 'queue://MSG_QUEUE' - trying to recover. Cause: Connection reset
Could not refresh JMS Connection for destination 'queue://MSG_QUEUE' - retrying in 5000 ms. Cause: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
Could not refresh JMS Connection for destination 'queue://MSG_QUEUE' - retrying in 5000 ms. Cause: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
This occurs few times before it succeeds.
Do you guys have any idea about this.
appreciate your help.
thanks,
keth
This just means the broker isn't running when the listener container starts. When using a tcp:// URL you should run the broker in it's own context (or another JVM) before creating this context.
I have tested these code in my STS its working fine .
The only problem in your side is , first start message Broker (say ActiveMQ) then run your project, you can get your required output.
Thanks.
I have made task using Spring #Scheduled annotation, but for some reason it is executing task twice. My Spring Framework version is 3.0.2.
#Service
public class ReportService {
#Scheduled(fixedDelay=1000 * 60 * 60* 24)
#Transactional
public void dailyReportTask()
{
... code here ...
}
}
Here is my XML:
<?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:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<task:scheduler id="taskScheduler" />
<task:executor id="taskExecutor" pool-size="1" />
<task:annotation-driven executor="taskExecutor"
scheduler="taskScheduler" />
</beans>
it is happening because of context listener
Just remove
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
from web.xml it should work.
I had this same problem, and I eventually found out that the problem was occurring as a result of the beans being created in the root context as well as the servlet context.
So, to fix this, you need to separate the creation of the beans into the appropriate contexts.
This answer explains really well how to that and was what fixed my problem.
According to this post: http://www.vodori.com/blog/spring3scheduler.html
Spring 3.0.0 Release had a bug where
web apps with a task scheduler would
end up executing scheduled methods
twice. This has been resolved in
Spring 3.0.1.
There has been another bug reported which affects Version/s: 3.0.2
https://jira.springsource.org/browse/SPR-7216
Which should be fixed in Version/s: 3.0.3.
I just had this problem recently and it was caused by my app being deployed twice in Tomcat by eclipse. The problem was that I had renamed my application in eclipse but the "wb-module deploy-name" specified in the "org.eclipse.wst.common.component" .settings file still had the old name.
In the tomcat manager, I could see that I had 2 apps running with different names.
Where are you actually running it? Your PC? Single server? 2 x load-balanced app servers?
Could be it's running on (a) your PC and (b) your server, so it just looks like it's running twice, if you see what I mean: it's correctly running once, just on two distinct locations.
Check if you have any manual scheduler config in your configuration files (through Java/XML). I'ved the same problem, and I discover that my config was loading my scheduler class twice:
In Java:
package com.mywork.br.myschuedulerpackage;
{...}
#Configuration
#EnableScheduling
public class SchedulerConfiguration {
#Bean
public CTXDataImporterScheduler ctxDataImporterScheduler() {
return new CTXDataImporterScheduler();
}
}
In XML applicationContext.xml:
<context:component-scan base-package="com.mywork.br.myschuedulerpackage" />
And in my scheduler class, I had #Component annotation thats was catch by the component scan and loaded a second time causing the #scheduler methods being executed twice.
I removed the Java config and then is working well now!
To solve twice-working of #Scheduled method just delete ContextLoaderListener from you web.xml (if you use web.xml-based application):
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Or if you use WebApplicationInitializer-based application just delete a string that adds ContextLoaderListener:
package com.dropbox.shortener.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class DropboxShortenerWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// (!) Delete the next string
// container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class);
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
setupCharEncodingFilter(container);
}
private void setupCharEncodingFilter(ServletContext container) {
container.setInitParameter("defaultHtmlEscape", "true");
FilterRegistration charEncodingFilterReg = container.addFilter("CharacterEncodingFilter", CharacterEncodingFilter.class);
charEncodingFilterReg.setInitParameter("encoding", "UTF-8");
charEncodingFilterReg.setInitParameter("forceEncoding", "true");
charEncodingFilterReg.addMappingForUrlPatterns(null, false, "/*");
}
}
Use #Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE) on your bean
Disabling below will work.
<!-- <listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener> -->
One solution I would suggest is to do component scat like this
-In application context
<context:component-scan base-package="com.abc.cde.dao" />
In yourservlet-servlet.xml
<!-- package that had all the #Controller classes -->
I this way the servlet is only loaded if the web.xml is loaded
Similar can be done for task