Spring Integration JMS Inbound Gateway reply channel has no subscriber - spring

I have test with JMS Inbound Gateway in Spring Integration 5.1.3
But I got error as following:
Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:138) ~[spring-integration-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105) ~[spring-integration-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73) ~[spring-integration-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
POM:
<dependencies>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
</dependencies>
I configure the Inbound Gateway as following:
#Bean
JmsInboundGateway jmsInboundGateway(
MessageChannel errorChannel,
ConnectionFactory connectionFactory,
DetailJmsProperties properties) {
final Listener listener = properties.getListener();
return Jms
.inboundGateway(connectionFactory)
.destination("request-queue")
.requestChannel("inputChannel")
.replyChannel("outputChannel")
.defaultReplyQueueName("response-queue")
.get();
}
And, the Service Activator:
#ServiceActivator(inputChannel = "inputChannel", outputChannel = "outputChannel")
public String process(String request) {
String response = null;
try {
LOGGER.info("Received message content: [{}]", request);
response = request + " was processed";
}
catch (Exception e) {
LOGGER.error("Error", e);
}
return response;
}
By the way, it works only if I remove outputChannel = "outputChannel" in Service Activator.
Is there any explanation for this issue, do I have any misunderstanding ?

You can't use DSL factories (Jms) like that, they are intended for use in a DSL flow
#Bean
IntegrationFLow flow()
return IntegrationFlows.from(jmsInboundGateway())
.handle("service", "process")
.get();
The DSL processing does all the wiring.
It works without the channel because a component without an output channel routes the reply to the replyChannel header.
If you don't want to use the DSL, you must wire up the inbound gateway directly as a bean instead of using the Jms factory.

Related

Spring Boot JTA exception while making JMS call

I'm getting JTA exception while running an example from the Pro Spring 5 book (12. Using Spring Remote, boot-jms project). Here is the entirety of the code (exclude the imports). It only has one file Application.java:
#SpringBootApplication
public class Application {
private static Logger logger = LoggerFactory.getLogger(Application.class);
#Bean
public JmsListenerContainerFactory<DefaultMessageListenerContainer> connectionFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
public static void main(String... args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
JmsTemplate jmsTemplate = ctx.getBean(JmsTemplate.class);
jmsTemplate.setDeliveryDelay(5000L);
for (int i = 0; i < 10; ++i) {
logger.info(">>> Sending: Test message: " + i);
jmsTemplate.convertAndSend("prospring5", "Test message: " + i);
}
System.in.read();
ctx.close();
}
#JmsListener(destination = "prospring5", containerFactory = "connectionFactory")
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
logger.info(">>> Received: " + textMessage.getText());
} catch (JMSException ex) {
logger.error("JMS error", ex);
}
}
}
First, I got the following error:
Exception in thread "main" java.lang.AbstractMethodError:
com.atomikos.jms.AtomikosJmsMessageProducerProxy.setDeliveryDelay(J)V
at
org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:628)
at
org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:608)
at
org.springframework.jms.core.JmsTemplate.lambda$send$3(JmsTemplate.java:586)
at
org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:504)
at
org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:584)
at
org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:661)
at com.apress.prospring5.ch12.Application.main(Application.java:54)
Then I commented out "jmsTemplate.setDeliveryDelay(5000L);". So I was able to get pass this error but only end up with the JTA exception.
Exception in thread "main"
org.springframework.jms.UncategorizedJmsException: Uncategorized
exception occurred during JMS processing; nested exception is
com.atomikos.jms.AtomikosTransactionRequiredJMSException: The JMS
session you are using requires a JTA transaction context for the
calling thread and none was found. Please correct your code to do one
of the following:
start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
create a non-transacted session and do session acknowledgment yourself, or
set localTransactionMode to true so connection-level commit/rollback are enabled. at
org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:311)
at
org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:185)
at
org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:507)
at
org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:584)
at
org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:661)
at com.apress.prospring5.ch12.Application.main(Application.java:54)
Caused by: com.atomikos.jms.AtomikosTransactionRequiredJMSException:
The JMS session you are using requires a JTA transaction context for
the calling thread and none was found. Please correct your code to do
one of the following:
start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
create a non-transacted session and do session acknowledgment yourself, or
set localTransactionMode to true so connection-level commit/rollback are enabled. at
com.atomikos.jms.AtomikosTransactionRequiredJMSException.throwAtomikosTransactionRequiredJMSException(AtomikosTransactionRequiredJMSException.java:23)
at
com.atomikos.jms.ConsumerProducerSupport.enlist(ConsumerProducerSupport.java:90)
at
com.atomikos.jms.AtomikosJmsMessageProducerProxy.send(AtomikosJmsMessageProducerProxy.java:34)
at
org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:634)
at
org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:608)
at
org.springframework.jms.core.JmsTemplate.lambda$send$3(JmsTemplate.java:586)
at
org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:504)
... 3 more
My project includes the dependency of spring-boot-starter-artemis and spring-boot-starter-jta-atomikos:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-server</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-hibernate4</artifactId>
<version>4.0.4</version>
</dependency>
The error message seems suggesting the Transaction is missing, so I had added #Transactional annotation at the listener and jmsTemplate, but the same problem still persists.
The problem seems is that I had included spring-boot-starter-jta-atomikos and transactions-hibernate4 in the dependencies. Once I removed these 2 dependencies, the code works. The intention of this example is not to do transaction but demonstrate spring-boot doing JMS over artemis. But since I have these 2 transaction related files in classpath, spring-boot automatically asks for transaction.

Spring - Websockets - JSR-356

I implemented websockets into my application. I copied the configuration and dependencies from jHipster generated app, but I am getting the following errors:
java.lang.IllegalArgumentException: No 'javax.websocket.server.ServerContainer' ServletContext attribute. Are you running in a Servlet container that supports JSR-356?
and
org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
I believe these errors are the reason for the socket connection not being consistent and the therefore the client is not able to send and/or receive any messages.
I searched for a solution but other post didn't help (ie. adding glassfish dependencies).
These are my ws dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
</dependency>
Do I need to include some other dependencies or is the problem elsewhere?
I found a solution here.
I added these 2 beans:
#Bean
public TomcatServletWebServerFactory tomcatContainerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();;
factory.setTomcatContextCustomizers(Collections.singletonList(tomcatContextCustomizer()));
return factory;
}
#Bean
public TomcatContextCustomizer tomcatContextCustomizer() {
return new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.addServletContainerInitializer(new WsSci(), null);
}
};
}

Spring Boot JMS No JmsTemplate bean available

I'm trying to send a message with JMS from my application.
I add in my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
</dependency>
The spring getting started say
JmsTemplate and ConnectionFactory are created automatically by Spring Boot. In this case, the ActiveMQ broker runs embedded.
and in my batch writer
#Autowired
JmsTemplate jmsTemplate,
void writer(List<String> items) {
jmsTemplate.convertAndSend(items);
}
But the bean JmsTemplate is not found
No qualifying bean of type 'org.springframework.jms.core.JmsTemplate' available: expected at least 1 bean which qualifies as autowire candidate
I tried to add an message converter in the #configuration
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
I tried to add the #EnableJMS (even if it's just for listener...)
But it dosen't work...
I don't understand why, on tutorials it looks like easy...
To work we need to create a jmsTemplate bean
#Bean
public ConnectionFactory getConnectionFactory() {
TibjmsConnectionFactory connectionFactory = new TibjmsConnectionFactory(urlBrocker);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(getConnectionFactory());
template.setPubSubDomain(false); // false for a Queue, true for a Topic
return template;
}

Spring Reactive kafka Receiver always overrides bootstrap server to localhost

I am trying to write Spring boot applications for a Reactive Kafka consumer using #EnableKafka and #KafkaListener annotations.
i have configured my kafka brokers are on different machine. when i give bootstrap-server to advertised host of kafka brokers, it is always overriding advertised host ip addresses to localhost. below are my code.
pom.xml file:-
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.kafka</groupId>
<artifactId>reactor-kafka</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
config:-
#Configuration
#EnableKafka
public class AppConfig {
#Bean
Map consumerProps() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.12.12.24:9092,192.14.14.28:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "example-group");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
return props;
}
#Bean
ReceiverOptions receiverOptions() {
ReceiverOptions receiverOptions = ReceiverOptions.create(consumerProps()).subscription(Arrays.asList("hellochange"));
return receiverOptions;
}
#Bean
public KafkaReceiver kafkaReceiver() {
return KafkaReceiver.create(receiverOptions());
}
}
Consumer:-
#Service
public class ChangeListener {
#Autowired
KafkaReceiver kafkaReceiver;
#KafkaListener(topics="hellochange",groupId="example-group")
public void receiver() {
kafkaReceiver.receive().subscribe(System.out::println);
}
}
Console:-
auto.commit.interval.ms = 5000
auto.offset.reset = latest
bootstrap.servers = [localhost:9092]
check.crcs = true
client.id =
connections.max.idle.ms = 540000
enable.auto.commit = true
2018-06-07 19:59:17.640 WARN 23536 --- [ntainer#0-0-C-1] org.apache.kafka.clients.NetworkClient : [Consumer clientId=consumer-1, groupId=example-group] Connection to node -1 could not be established. Broker may not be available.
I have validated without spring configurations in a simple consumer and non-reactive Spring kafka, for both, it is working fine. only Reactor kafka with EnableKafka and KafkaListener annotations i am getting this problem.
am i missing something/ doing wrong here ?
can we use EnableKafka and KafkaListener annotations with Reactor Kafka in Spring boot?
P.S. i understood, #EnableKafka and #KafkaListener are not reactive, if i remove spring-kafka from pom.xml, both the annotations are not available.
Like #EnableKafka and #KafkaListener for non-reactive kafka, is there any annotations are available to configure reactive kafka consumer with Spring boot application?
You cannot use KafkaListener annotations with Reactor Kafka; #KafkaListener is not reactive.

Spring Boot client to connect to existing JBoss EAP7 ActiveMQ

I've been searching the web but I cannot find an example on how to connect to ActiveMQ on JBoss (up and running) with a Spring-Boot client.
There'se a lot of tutorials from Spring but using an embedded Broker.
Any pointers would be great!
Thanks in advance,
ML
With the info provided, I've got this:
#Configuration
#SpringBootApplication
#EnableJms
public class Application {
#Bean
ActiveMQConnectionFactory activeMQConnectionFactory() {
final String host = "http://127.0.0.1:8080";
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(host);
factory.setUserName("user");
factory.setPassword("pwd");
factory.setTrustAllPackages(true);
return factory;
}
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the
// message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
#Bean // Serialize message content to json using TextMessage
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
public static void main(String[] args) {
// Launch the application
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
// Send a message with a POJO - the template reuse the message converter
System.out.println("Sending an email message.");
jmsTemplate.convertAndSend("TestQ", new Email("info#example.com", "Hello"));
}
}
my dependencies in pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-optional</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
But I've got this exception:
2017-06-01 17:55:54.176 INFO 2053 --- [ main] hello.Application : Started Application in 2.02 seconds (JVM running for 5.215)
Sending an email message.
[WARNING]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:527)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not create Transport. Reason: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=127.0.0.1}
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:487)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:570)
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:658)
at hello.Application.main(Application.java:69)
... 6 more
Caused by: javax.jms.JMSException: Could not create Transport. Reason: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=127.0.0.1}
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36)
at org.apache.activemq.ActiveMQConnectionFactory.createTransport(ActiveMQConnectionFactory.java:333)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:346)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:304)
at org.apache.activemq.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:244)
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:180)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:474)
... 9 more
Caused by: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=127.0.0.1}
at org.apache.activemq.transport.TransportFactory.doConnect(TransportFactory.java:126)
at org.apache.activemq.transport.TransportFactory.connect(TransportFactory.java:65)
at org.apache.activemq.ActiveMQConnectionFactory.createTransport(ActiveMQConnectionFactory.java:331)
... 14 more
I don't know what is this:
Caused by: java.lang.IllegalArgumentException: Invalid connect
parameters: {wireFormat.host=127.0.0.1}
thanks
For configuration, but change the broker url to your external ActiveMQ server: see http://activemq.apache.org/uri-protocols.html for different protocols (e.g. tcp). You may also need to include a user and password.
I started with this tutorial https://spring.io/guides/gs/messaging-jms/ and made my own edits to get it to work the way I wanted with ActiveMQ, you can also look here for other options: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-messaging.html. There are a few different ways to do this in Spring.
Also included the factory bean as well. From here, I use #JmsListener annotation to listen for messages and jmstemplate to post messages.
import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
#Configuration
#EnableJms
public class JMSConfiguration {
private static final Logger logger = LoggerFactory.getLogger(JMSConfiguration.class);
#Bean ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory factory =
new ActiveMQConnectionFactory("tcp://somehost:61616");
factory.setTrustAllPackages(true);
return factory;
}
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the
// message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
}
Dependencies: spring-boot-starter-activemq
Spring version: 1.4.3.RELEASE

Resources