I am trying to build a basic registration form that sends the form data to a stateless bean through a Servlet. But inside ActiveMQ console I see two consumers for same queue also I need to register twice to add a new user in the list.
Any help is appreciated.
Logs:
WARNING: All illegal access operations will be denied in a future release
15:35:34,892 WARN [org.wildfly.extension.undertow] (MSC service thread 1-3) WFLYUT0101: Duplicate servlet mapping /Register found
15:35:35,008 INFO [javax.enterprise.resource.webcontainer.jsf.config] (ServerService Thread Pool -- 84) Initializing Mojarra 2.3.14.SP01 for context '/demowarproject'
15:35:35,436 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 84) WFLYUT0021: Registered web context: '/demowarproject' for server 'default-server'
15:35:35,509 INFO [org.jboss.as.server] (ServerService Thread Pool -- 46) WFLYSRV0010: Deployed "activemq-rar-5.17.2.rar" (runtime-name : "activemq-rar-5.17.2.rar")
15:35:35,510 INFO [org.jboss.as.server] (ServerService Thread Pool -- 46) WFLYSRV0010: Deployed "demowarproject.war" (runtime-name : "demowarproject.war")
15:35:35,510 INFO [org.jboss.as.server] (ServerService Thread Pool -- 46) WFLYSRV0010: Deployed "demoejbprojectEAR.ear" (runtime-name : "demoejbprojectEAR.ear")
15:35:35,551 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
15:35:35,555 INFO [org.apache.activemq.ra.ActiveMQEndpointWorker] (Controller Boot Thread) Starting
15:35:35,561 INFO [org.apache.activemq.ra.ActiveMQEndpointWorker] (Controller Boot Thread) Starting
15:35:35,559 INFO [org.apache.activemq.ra.ActiveMQEndpointWorker] (default-threads - 1) Establishing connection to broker [tcp://localhost:61616]
15:35:35,565 INFO [org.apache.activemq.ra.ActiveMQEndpointWorker] (default-threads - 2) Establishing connection to broker [tcp://localhost:61616]
15:35:35,567 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 21.0.2.Final (WildFly Core 13.0.3.Final) started in 8578ms - Started 648 of 874 services (390 services are lazy, passive or on-demand)
15:35:35,574 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
15:35:35,574 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
15:35:35,801 INFO [org.apache.activemq.ra.ActiveMQEndpointWorker] (default-threads - 2) Successfully established connection to broker [tcp://localhost:61616]
15:35:35,801 INFO [org.apache.activemq.ra.ActiveMQEndpointWorker] (default-threads - 1) Successfully established connection to broker [tcp://localhost:61616]
15:35:50,821 INFO [stdout] (default task-1) message sent!
15:35:51,154 INFO [stdout] (default-threads - 3) Registered!!, User count is: 1
15:35:51,158 INFO [stdout] (default-threads - 3) All users are:
15:35:51,158 INFO [stdout] (default-threads - 3) 87KumarPrashant#gmail.com
15:35:51,158 INFO [stdout] (default-threads - 3)
15:36:10,979 INFO [stdout] (default task-1) message sent!
15:36:10,995 INFO [stdout] (default-threads - 4) Registered!!, User count is: 1
15:36:10,996 INFO [stdout] (default-threads - 4) All users are:
15:36:10,996 INFO [stdout] (default-threads - 4) 87KumarPrashant#gmail.com
15:36:10,996 INFO [stdout] (default-threads - 4)
15:36:12,270 INFO [stdout] (default task-1) message sent!
15:36:12,286 INFO [stdout] (default-threads - 5) Email already registered 1
15:36:12,287 INFO [stdout] (default-threads - 5) All users are:
15:36:12,287 INFO [stdout] (default-threads - 5) 87KumarPrashant#gmail.com
15:36:12,287 INFO [stdout] (default-threads - 5)
15:36:13,438 INFO [stdout] (default task-1) message sent!
15:36:13,448 INFO [stdout] (default-threads - 6) Email already registered 1
15:36:13,449 INFO [stdout] (default-threads - 6) All users are:
15:36:13,449 INFO [stdout] (default-threads - 6) 87KumarPrashant#gmail.com
15:36:13,449 INFO [stdout] (default-threads - 6)
As you can see it needs twice to register before it says already registered, but user count is not increased second time (weird). And WildFly console shows two consumers for the same queue (also weird) as I am not using the same queue anywhere else.
ActiveMQ Console showing 2 consumers instead of 1:
Here are related files:
MDB:
import java.util.ArrayList;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/queue/demo")})
public class DemoEjb implements MessageListener
{
static ArrayList<User> usersList = new ArrayList<User>();
static int userCount = 0;
User u = null;
public void onMessage(Message message)
{
try
{
if (message instanceof ObjectMessage)
{
User user = (User) ((ObjectMessage) message).getObject();
if(user.getOperation().equals("register"))
registerUser(user);
// else
// loginUser(user);
}
} catch (Exception e)
{
e.printStackTrace();
}
}
public void registerUser(User user)
{
if (isUserPresent(user.getEmail())) {
System.out.println("Email already registered " + userCount);
giveAllUsers();
return;
}
addUser(user);
System.out.println("Registered!!, User count is: " + userCount);
giveAllUsers();
}
public boolean isUserPresent(String email)
{
return usersList.stream().anyMatch(d -> d.getEmail().equals(email));
}
public void addUser(User newUser)
{
usersList.add(newUser);
userCount++;
}
public void giveAllUsers()
{
System.out.println("All users are: ");
for(User u: usersList)
{
System.out.println(u.getEmail());
}
System.out.println();
}
}
User (POJO):
import java.io.Serializable;
public class User implements Serializable
{
private static final long serialVersionUID = 1L;
private String name;
private String password;
private String email;
private String operation;
public User(String name, String email, String password, String operation)
{
this.name = name;
this.email = email;
this.password = password;
this.operation = operation;
}
public String getName()
{
return this.name;
}
public void setOperation(String operation) {
this.operation = operation;
}
public String getPassword()
{
return this.password;
}
public String getEmail()
{
return this.email;
}
public void setName(String name)
{
this.name = name;
}
public void setPassword(String pass)
{
this.password = pass;
}
public String getOperation() {
return this.operation;
}
}
Servlet:
import java.io.IOException;
import java.io.PrintWriter;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.activemq.ActiveMQConnectionFactory;
import com.enovate.demoejb.User;
#WebServlet("/Register")
public class Register extends HttpServlet
{
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String name = request.getParameter("userName");
String pass = request.getParameter("userPassword");
String email = request.getParameter("userEmail");
User user = new User(name, email, pass, "register");
try
{
System.out.println("message sent!");
sendMessage(user);
PrintWriter out = response.getWriter();
out.println("Message sent!");
} catch (Exception e)
{
e.printStackTrace();
}
}
public void sendMessage(User user) throws Exception
{
Connection connection = null;
try
{
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
String queue = "jms/queue/demo";
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destinationQueue = session.createQueue(queue);
MessageProducer publisher = session.createProducer(destinationQueue);
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject(user);
publisher.send(objectMessage);
session.close();
}
finally
{
closeConnection(connection);
}
}
private void closeConnection(Connection con)
{
try
{
if (con != null)
con.close();
}
catch(JMSException jmse)
{
System.out.println("Could not close connection " + con +" exception was " + jmse);
}
}
}
HTML file:
<html>
<head>
<meta charset="ISO-8859-1">
<title>Register</title>
</head>
<body>
<form method="post" action="Register">
Name: <input name="userName" type="text"><br>
Email: <input name="userEmail" type="email"><br>
Password: <input name="userPassword" type="password"><br>
<input type="submit" value="Register">
</form>
</body>
</html>
Web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>demowarproject</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>
<servlet>
<description></description>
<display-name>Register</display-name>
<servlet-name>Register</servlet-name>
<servlet-class>com.enovate.demoservlet.Register</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Register</servlet-name>
<url-pattern>/Register</url-pattern>
</servlet-mapping>
</web-app>
I was expecting it should work fine and have only one consumer.
It feels like there are two consumer created (don't know how) and then each try accepts the data one after the other.
Related
A continuation of Make Spring RabbitMQ fail on missing exchange
I register MessageListenerContainer for multiple queues.
Where and how should I configure channel returnListener? - I thing the way I have done it is wrong. I inserted CachingConnectionFactory configuration into createQueueBMessageListener(...) - method responsible for creating one of multiple MessageListeners.
1. How should be CachingConnectionFactory additional configuration done Spring and Rabbit way? By now I didn't configure it in Java (only by application.properties and admins in K8S environment). I only injected ConnectionFactory and set it as connectionFactory in SimpleMessageListenerContainer (as in createQueueAMessageListener(...)), I even didn't know it's CachingConnectionFactory.
Is there something like CachingConnectionFactoryConfigurer?
2. Why is ReturnListener.handleReturn(..) not executed? ChannelListener.onCreate(...) is executed.
3. Checking missing exchange exception in cachingConnectionFactory.setCloseExceptionLogger and doing System.exit(1) there seems wrong to me, isn't it? But this is all I managed to do by now. I want to application not start when there is no exchange during binding creation. When I throw exception there application still starts. ReturnListener.handleReturn seems a better place for it, but it isn't executed when configured as below.
4. How can I stop Spring Application Context gracefully instead of System.exit(1)? - throwing exception doesn't stop Application Context. How to make RabbitMq fail to start in such situation? - when a creation of #Bean Binding at Spring Application Context start fails.
#Bean
MessageListenerContainer createQueueAMessageListener(SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory,
ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = rabbitListenerContainerFactory.createListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("queueA");
MessageConverter jsonMessageConverter = null;
container.setMessageListener(new MessageListenerAdapter(new Object(), jsonMessageConverter));
return container;
}
#Bean
MessageListenerContainer createQueueBMessageListener(SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory,
ConnectionFactory connectionFactory,
CachingConnectionFactory cachingConnectionFactory) {
// I think configuring CachingConnectionFactory here is a lame, isn't it? Of course connectionFactory is redundant now, I left it to show how was it done earlier.
// Where and how should I add listeners to CachingConnectionFactory?
cachingConnectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
cachingConnectionFactory.setPublisherReturns(true);
cachingConnectionFactory.addChannelListener(new ChannelListener() {
#Override
public void onCreate(final Channel channel, final boolean transactional) {
log.info("channelListener onCreate - this is executed");
channel.addReturnListener(new ReturnListener() {
#Override
public void handleReturn(final int replyCode, final String replyText, final String exchange, final String routingKey,
final AMQP.BasicProperties properties,
final byte[] body) throws IOException
{
log.info("!!! Why is this not executed ?!!! handleReturn replyCode: " + replyCode + " replyText: " + replyText);
}
});
}
});
cachingConnectionFactory.addConnectionListener(new ConnectionListener() {
#Override
public void onCreate(final Connection connection) {
log.info("connectionListener onCreate - this is executed" + connection);
}
});
cachingConnectionFactory.setCloseExceptionLogger(new ConditionalExceptionLogger() {
#Override
public void log(final Log logger, final String message, final Throwable t) {
try {
logger.error(message + ": " + t.getMessage());
if (t.getMessage().contains("reply-code=404, reply-text=NOT_FOUND")) {
// throw new RuntimeException(); it doesn't stop Spring ApplicationContext from starting
log.error("Executing System.exit(1) command.");
// System.exit(1);
}
} catch (Exception e) {
log.error("err in listener ", e);
}
}
});
SimpleMessageListenerContainer container = rabbitListenerContainerFactory.createListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("queueB");
MessageConverter jsonMessageConverter = null;
container.setMessageListener(new MessageListenerAdapter(new Object(), jsonMessageConverter));
return container;
}
#Bean
MessageListenerContainer createQueueCMessageListener(SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory,
ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = rabbitListenerContainerFactory.createListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("queueC");
MessageConverter jsonMessageConverter = null;
container.setMessageListener(new MessageListenerAdapter(new Object(), jsonMessageConverter));
return container;
}
// I think configuring CachingConnectionFactory here is a lame, isn't it?
It is not "lame"; that is the normal way of configuring beans with additional properties not exposed directly by Boot.
It should be called; have you tried debugging?
Why don't you do what I advised here Make Spring RabbitMQ fail on missing exchange - it's much simpler.
close() it - but, since you are using Spring Boot, it will do that for you - it registers a JVM shutdown hook that closes the context.
EDIT
Binding to a non-existent exchange will fail; you just need to force it to happen before the application is fully initialized, e.g. in an ApplicationRunner.
#SpringBootApplication
public class So70212347Application {
public static void main(String[] args) {
SpringApplication.run(So70212347Application.class, args);
}
#Bean
Binding binding() {
return new Binding("foo", DestinationType.QUEUE, "doesn't exist", "foo", null);
}
#Bean
Queue queue() {
return new Queue("foo");
}
#Bean
ApplicationRunner runner(ConnectionFactory cf) {
return args -> {
cf.createConnection().close();
};
}
}
Created new connection: rabbitConnectionFactory#6a0cbc6f:0/SimpleConnection#6cd164a6 [delegate=amqp://guest#127.0.0.1:5672/, localPort= 62884]
Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'doesn't exist' in vhost '/', class-id=50, method-id=20)
Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'doesn't exist' in vhost '/', class-id=50, method-id=20)
Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'doesn't exist' in vhost '/', class-id=50, method-id=20)
Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'doesn't exist' in vhost '/', class-id=50, method-id=20)
Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'doesn't exist' in vhost '/', class-id=50, method-id=20)
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
Application run failed
java.lang.IllegalStateException: Failed to execute ApplicationRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:748)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:309)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
at com.example.demo.So70212347Application.main(So70212347Application.java:16)
Caused by: org.springframework.amqp.AmqpIOException: java.io.IOException
at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:70)
at org.springframework.amqp.rabbit.connection.RabbitAccessor.convertRabbitAccessException(RabbitAccessor.java:113)
at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2192)
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2138)
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2118)
at org.springframework.amqp.rabbit.core.RabbitAdmin.initialize(RabbitAdmin.java:691)
at org.springframework.amqp.rabbit.core.RabbitAdmin.lambda$null$10(RabbitAdmin.java:619)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:209)
at org.springframework.amqp.rabbit.core.RabbitAdmin.lambda$afterPropertiesSet$11(RabbitAdmin.java:618)
at org.springframework.amqp.rabbit.connection.CompositeConnectionListener.lambda$onCreate$0(CompositeConnectionListener.java:38)
at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:807)
at org.springframework.amqp.rabbit.connection.CompositeConnectionListener.onCreate(CompositeConnectionListener.java:38)
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:730)
at com.example.demo.So70212347Application.lambda$0(So70212347Application.java:33)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:758)
... 5 common frames omitted
Caused by: java.io.IOException: null
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:129)
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:125)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:147)
at com.rabbitmq.client.impl.ChannelN.queueBind(ChannelN.java:1077)
at com.rabbitmq.client.impl.ChannelN.queueBind(ChannelN.java:46)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:1157)
at com.sun.proxy.$Proxy47.queueBind(Unknown Source)
at org.springframework.amqp.rabbit.core.RabbitAdmin.declareBindings(RabbitAdmin.java:870)
at org.springframework.amqp.rabbit.core.RabbitAdmin.lambda$initialize$12(RabbitAdmin.java:694)
at org.springframework.amqp.rabbit.core.RabbitTemplate.invokeAction(RabbitTemplate.java:2227)
at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2186)
... 18 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'doesn't exist' in vhost '/', class-id=50, method-id=20)
...
I’m using RabbitMQ MQTT Adapter and Paho MQTT client.
RabbitMQ version: {rabbitmq_mqtt,"RabbitMQ MQTT Adapter","3.2.1"}
Paho MQTT client version:
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>RELEASE</version>
</dependency>
Please see code inline.
I’m trying to understand if, the subscriber queue can be durable without expiration time. And If the messages can be durable also.
As I understood from RabbitMQ documentation, each time a subscriber subscribes to a topic
RabbitMQ will create a queue with this naming convention:
mqtt-subscription-<ClientName>qos<ClientQOS>
This queue has an expiration time, how can I create a queue without an expiration time? Can I change this queue expiration time to infinite?
As for now each time I run this command: “service rabbitmq-server restart”
The messages in the queue get deleted.
How can I prevent this? Is there a way I can keep the messages in the queue after restart?
In RabbitMQ management UI, I can see under “Publish message” -> “Delivery mode:” which can be “2-persistent”.
If I use management UI to publish messages with Delivery mode = 2-persistent. The messages will be in the queue after service restart.
How can I achieve the same using Paho MQTT Client?
// Heavily based on RabbitMQ MQTT adapter test case code!
// first, import the RabbitMQ Java client
// and the Paho MQTT client classes, plus any other
// requirements
import com.rabbitmq.client.*;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.internal.NetworkModule;
import org.eclipse.paho.client.mqttv3.internal.TCPNetworkModule;
// import org.eclipse.paho.client.mqttv3.internal.trace.Trace;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttOutputStream;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttPublish;
import javax.net.SocketFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.*;
/***
* MQTT v3.1 tests
* TODO: synchronise access to variables
*/
public class MqttTestClean implements MqttCallback {
// setup some variables which define where the MQTT broker is
private final String host = "0.0.0.0";
private final int port = 1883;
private final String brokerUrl = "tcp://" + host + ":" + port;
private String clientId;
private String clientId3;
private MqttClient client;
private MqttClient client3;
private MqttConnectOptions conOpt;
private ArrayList<MqttMessage> receivedMessages;
// specify a message payload - doesn't matter what this says, but since MQTT expects a byte array
// we convert it from string to byte array here
private final byte[] payload = "This payload was published on MQTT and read using AMQP.".getBytes();
// specify the topic to be used
private final String topic = "topic/proxy/1.0.0/Report/*";
private int testDelay = 2000;
private long lastReceipt;
private boolean expectConnectionFailure;
private ConnectionFactory connectionFactory;
private Connection conn;
private Channel ch;
// override 10s limit
private class MyConnOpts extends MqttConnectOptions {
private int keepAliveInterval = 60;
#Override
public void setKeepAliveInterval(int keepAliveInterval) {
this.keepAliveInterval = keepAliveInterval;
}
#Override
public int getKeepAliveInterval() {
return keepAliveInterval;
}
}
public void setUpMqtt() throws MqttException {
clientId = getClass().getSimpleName() + ((int) (10000*Math.random()));
client = new MqttClient(brokerUrl, clientId);
conOpt = new MyConnOpts();
setConOpts(conOpt);
receivedMessages = new ArrayList<MqttMessage>();
expectConnectionFailure = false;
}
public void tearDownMqtt() throws MqttException {
try {
client.disconnect();
} catch (Exception _) {}
}
private void setUpAmqp() throws Exception {
connectionFactory = new ConnectionFactory();
connectionFactory.setHost(host);
conn = connectionFactory.newConnection();
ch = conn.createChannel();
}
private void tearDownAmqp() throws IOException {
conn.close();
}
private void setConOpts(MqttConnectOptions conOpts) {
conOpts.setCleanSession(true);
conOpts.setKeepAliveInterval(60);
}
private void publish(MqttClient client, String topicName, int qos, byte[] payload) throws MqttException {
MqttTopic topic = client.getTopic(topicName);
MqttMessage message = new MqttMessage(payload);
message.setQos(qos);
MqttDeliveryToken token = topic.publish(message);
token.waitForCompletion();
}
public void connectionLost(Throwable cause) {
if (!expectConnectionFailure)
System.out.println("Connection unexpectedly lost");
}
public void messageArrived(String topic, MqttMessage message) throws Exception {
lastReceipt = System.currentTimeMillis();
System.out.println("-------------------------------------------------");
System.out.println("------------------" + lastReceipt + "-------------------------------");
System.out.println("------------------" + message.toString() + "-------------------------------");
receivedMessages.add(message);
}
public void deliveryComplete(IMqttDeliveryToken token) {
}
public void run() {
try {
setUpMqtt(); // initialise the MQTT connection
setUpAmqp(); // initialise the AMQP connection
connect();
//String queue = ch.queueDeclare().getQueue();
// String queue = ch.queueDeclare("mqtt-subscription-Snabel-3qos1", true, false, false, null).getQueue();
//ch.queueBind(queue, "amq.topic", "sci-topic.sc.proxy_1393.1.0.0.ApReport.*"/*topic*/);
client.connect(conOpt);
publish(client, "topic/proxy/1.0.0/Report/123456789",1, payload); // publish the MQTT message
client.disconnect();
Thread.sleep(testDelay);
tearDownAmqp(); // cleanup AMQP resources
tearDownMqtt(); // cleanup MQTT resources*/
disConnect();
} catch (Exception mqe) {
mqe.printStackTrace();
}
}
private void connect() throws Exception {
clientId3 = "Test-3";
client3 = new MqttClient(brokerUrl, clientId3);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(false);
client3.connect(connOpts);
client3.setCallback(this);
client3.subscribe(topic);
if(!client3.isConnected()){
System.out.println("Not Connected");
return;
}
System.out.println("Connected");
}
private void disConnect() throws Exception {
try {
client3.disconnect();
} catch (Exception _) {}
}
public static void main(String[] args) {
MqttTest mqt = new MqttTest();
mqt.run();
}
}
This was a RabbitMQ bug:
http://rabbitmq.1065348.n5.nabble.com/MQTT-plugin-message-delivery-mode-td32925.html
It was fixed in:
http://www.rabbitmq.com/release-notes/README-3.2.4.txt
I am using this property with informix version 4.10.6.20151104
spring.informix.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.informix.datasource.dataSourceClassName=com.informix.jdbcx.IfxDataSource
spring.informix.datasource.dataSourceProperties.serverName=CISCO-UCCE-EXP
spring.informix.datasource.dataSourceProperties.portNumber=1504
spring.informix.datasource.dbcp2.pool-prepared-statements=true
spring.informix.datasource.dataSourceProperties.IFXHOST = cisco_ucce_exp_uccx
Getting error this
java.lang.RuntimeException: Property IFXHOST does not exist on target class com.informix.jdbcx.IfxDataSource
at com.zaxxer.hikari.util.PropertyElf.setProperty(PropertyElf.java:155) ~[HikariCP-2.4.7.jar:na]
at com.zaxxer.hikari.util.PropertyElf.setTargetFromProperties(PropertyElf.java:67) ~[HikariCP-2.4.7.jar:na]
at com.zaxxer.hikari.pool.PoolBase.initializeDataSource(PoolBase.java:295) ~[HikariCP-2.4.7.jar:na]
at com.zaxxer.hikari.pool.PoolBase.<init>(PoolBase.java:91) ~[HikariCP-2.4.7.jar:na]
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:101) ~[HikariCP-2.4.7.jar:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:94) ~[HikariCP-2.4.7.jar:na]
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) ~[spring-jdbc-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) ~[spring-jdbc-4.3.3.RELEASE.jar:4.3.3.RELEASE]
I have also tried same configuration with referring the
https://docs.oracle.com/cd/E19575-01/821-0185/beanj/index.html
for IfxIFXHost also I got the same issue
kindly help.
P.S I am new to Hikari
Never used Hikari before, but a quick test shows the properties you should add to the datasource to get a connection:
With "IFXHOST" I get the exception:
D:\JJTMP>grep IFXHOST p.java
config.addDataSourceProperty("IFXHOST", "420ito");
config.addDataSourceProperty("IfxIFXHOST", "420ito");
D:\JJTMP>java p
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
[main] ERROR com.zaxxer.hikari.util.PropertyElf - Property IFXHOST does not exist on target class com.informix.jdbcx.IfxDataSource
Exception in thread "main" java.lang.NullPointerException
at p.main(p.java:64)
Using "IfxIFXHOST" works:
D:\JJTMP>grep IFXHOST p.java
//config.addDataSourceProperty("IFXHOST", "420ito");
config.addDataSourceProperty("IfxIFXHOST", "420ito");
D:\JJTMP>javac p.java
D:\JJTMP>java p
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
[main] INFO com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (M
ethod not supported : IfxSqliConnect.getNetworkTimeout())
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
The Connection Object is of Class: class com.zaxxer.hikari.pool.HikariProxyConnection
systables,informix ,1048580
syscolumns,informix ,1048581
sysindices,informix ,1048582
systabauth,informix ,1048583
syscolauth,informix ,1048584
D:\JJTMP>
And just in case, the code I was using:
// ----- p.java -----
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class p
{
private static DataSource datasource;
public static DataSource getDataSource()
{
if(datasource == null)
{
HikariConfig config = new HikariConfig();
config.setDataSourceClassName("com.informix.jdbcx.IfxDataSource");
config.addDataSourceProperty("serverName", "ids1210");
//config.addDataSourceProperty("IFXHOST", "420ito");
config.addDataSourceProperty("IfxIFXHOST", "420ito");
config.addDataSourceProperty("PortNumber", "9088");
config.addDataSourceProperty("databaseName", "sysmaster");
config.addDataSourceProperty("user", "informix");
config.addDataSourceProperty("password", "ximrofni");
config.setMaximumPoolSize(10);
config.setAutoCommit(false);
datasource = new HikariDataSource(config);
}
return datasource;
}
public static void main(String[] args)
{
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try
{
DataSource dataSource = p.getDataSource();
connection = dataSource.getConnection();
pstmt = connection.prepareStatement("SELECT FIRST 5 * FROM systables");
System.out.println("The Connection Object is of Class: " + connection.getClass());
resultSet = pstmt.executeQuery();
while (resultSet.next())
{
System.out.println(resultSet.getString(1) + "," + resultSet.getString(2) + "," + resultSet.getString(3));
}
}
catch (Exception e)
{
try
{
connection.rollback();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
// ----- p.java -----
So this worked for me
spring.informix.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.informix.datasource.minimumIdle=10
spring.informix.datasource.maximumPoolSize=30
spring.informix.datasource.idleTimeout=500
spring.informix.datasource.dataSourceClassName=com.informix.jdbcx.IfxDataSource
spring.informix.datasource.dataSourceProperties.databaseName=db_
spring.informix.datasource.dataSourceProperties.serverName=CISCO-UCCE-EXP
#spring.informix.datasource.dataSourceProperties.url = jdbc:informix-sqli://CISCO-UCCE-EXP:1504/db_cra:INFORMIXSERVER=cisco_ucce_exp_uccx; Protocol=onsoctcp; client_locale=en_US.57372; db_locale=en_US.57372
spring.informix.datasource.dataSourceProperties.portNumber=1504
spring.informix.datasource.dbcp2.pool-prepared-statements=true
spring.informix.datasource.dataSourceProperties.LoginTimeout=0
spring.informix.datasource.connectionTimeout=0
spring.informix.datasource.dataSourceProperties.IfxIFXHOST=cisco_ucce_exp_uccx
I have a Use Case of managing Spring AMQP client message resiliency in case of RabbitMQ server connectivity down,
For the same I have used Spring Retry
RabbitTemplate template = // get template from some bean
RetryTemplate retryTemplate = new RetryTemplate();
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
// 10 sec
backOffPolicy.setInitialInterval(10000);
// 1 hr
backOffPolicy.setMultiplier(360.0);
// 1 hr max interval
backOffPolicy.setMaxInterval(3600001);
retryTemplate.setBackOffPolicy(backOffPolicy);
template.setRetryTemplate(retryTemplate);
template.convertAndSend("Direct-Exchange",
"Test.Routing.Key", AMQPMessage);
But when a try to test it and bring broker down it hangs at template.convertAndSend() and never recovers even when RabbitMQ broker connectivity is restored
Your retry configuration is rather extreme. Did you wait for an hour?
It works fine for me...
#SpringBootApplication
public class So44300651Application implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(So44300651Application.class, args).close();
}
#Autowired
private RabbitTemplate template;
#Override
public void run(String... args) throws Exception {
template.convertAndSend("foo");
}
#Bean
public RabbitTemplate template(ConnectionFactory cf) {
RabbitTemplate template = new RabbitTemplate(cf);
RetryTemplate retry = new RetryTemplate();
ExponentialBackOffPolicy backOff = new ExponentialBackOffPolicy();
backOff.setInitialInterval(10_000);
backOff.setMultiplier(1.5);
backOff.setMaxInterval(15_000);
retry.setBackOffPolicy(backOff);
template.setRetryTemplate(retry);
return template;
}
}
Result:
09:19:45.592 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
09:19:45.603 [main] DEBUG o.s.r.b.ExponentialBackOffPolicy - Sleeping for 10000
09:19:55.607 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
09:19:55.607 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
09:19:55.608 [main] DEBUG o.s.r.b.ExponentialBackOffPolicy - Sleeping for 15000
09:20:10.610 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
09:20:10.610 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
09:20:10.654 [main] INFO o.s.a.r.c.CachingConnectionFactory - Created new connection: SimpleConnection#13cf7d52 [delegate=amqp://guest#127.0.0.1:5672/, localPort= 56958]
I am trying to read data from a file and write to a rabbitmq queue using apache camel but ending up with the error
Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> To[rabbitmq://localhost:15672?queue=hello] <<< in route: Route(route1)[[From[file://target/?fileName=doctor.txt&chars... because of Failed to resolve endpoint: rabbitmq://localhost:15672?queue=hello due to: No URI path as the exchangeName for the RabbitMQEndpoint, the URI is rabbitmq://localhost:15672?queue=hello
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:945)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:187)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:794)
at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:2184)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:1916)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:1777)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:1745)
at test.RMQCamelSender.main(RMQCamelSender.java:38)
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: rabbitmq://localhost:15672?queue=hello due to: No URI path as the exchangeName for the RabbitMQEndpoint, the URI is rabbitmq://localhost:15672?queue=hello
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:545)
at org.apache.camel.util.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:71)
at org.apache.camel.model.RouteDefinition.resolveEndpoint(RouteDefinition.java:202)
at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:106)
at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:112)
at org.apache.camel.model.SendDefinition.resolveEndpoint(SendDefinition.java:61)
at org.apache.camel.model.SendDefinition.createProcessor(SendDefinition.java:55)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:500)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:213)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:942)
... 8 more
Caused by: java.lang.IllegalArgumentException: No URI path as the exchangeName for the RabbitMQEndpoint, the URI is rabbitmq://localhost:15672?queue=hello
at org.apache.camel.component.rabbitmq.RabbitMQComponent.createEndpoint(RabbitMQComponent.java:50)
at org.apache.camel.component.rabbitmq.RabbitMQComponent.createEndpoint(RabbitMQComponent.java:31)
at org.apache.camel.impl.DefaultComponent.createEndpoint(DefaultComponent.java:122)
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:525)
... 17 more
Following are my implementations of the classes which are creating camel context and rabbitmq queue.
RMQCamleSender.java
package test;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import test.Producer;
public class RMQCamelSender {
public static void main(String[] argv) throws Exception {
Producer queueProd = new Producer();
queueProd.setupConnection();
System.out.println(queueProd.toString());
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() throws Exception {
System.out.println("hello world");
from("file://target/?fileName=doctor.txt&charset=utf-8")
.process(new Processor() {
public void process(Exchange msg) throws Exception {
System.out.println(msg.getIn().getBody(
String.class));
}
}).to("rabbitmq://localhost:15672?queue=hello");
}
});
context.start();
Thread.sleep(4000);
context.stop();
}
}
Producer.java
package test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
public class Producer {
public static final String QUEUE_NAME = "hello";
public static Connection connection;
public void setupConnection() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
}
}
The program is working fine if I am not using Camel and trying to contact the queue using standard rabbitmq library.
The error message is pretty indicative: you are missing the exchange name in your endpoint URI, it cannot be blank, as the official Camel documentation says it has to follow the given format:
rabbitmq://hostname[:port]/exchangeName?[options]
I suggest you try using the amq.direct exchange (for more details, refer to the official RabbitMQ documentation), like so:
public void configure() throws Exception {
System.out.println("hello world");
from("file://target/?fileName=doctor.txt&charset=utf-8")
.process(new Processor() {
public void process(Exchange msg) throws Exception {
System.out.println(msg.getIn().getBody(String.class));
}
}).to("rabbitmq://localhost:5672/amq.direct?routingKey=hello");
}
Additionally, you are using 15672 port, which is by default the port for RabbitMQ's web management console, I guess you haven't changed the default settings so the port needs to be 5672. You also have to use the routingKey parameter instead of the queue one since in RabbitMQ semantics you publish to exchange:routingKey and only consume from queues.
You need to include the rabbitmq exchange name. It is missing from here;
.to("rabbitmq://localhost:15672?queue=hello");
It should be something like this:
.to("rabbitmq://localhost:15672/exchangeName?routingKey=hello");
Also, if you are sending to exchange, why do you want to specify a queue? You need only to specify the routing key and the exchange will send to that queue if there is a binding for that routing key.