package cgl.iotcloud.transport.rabbitmq; import cgl.iotcloud.core.msg.MessageContext; import cgl.iotcloud.core.transport.Manageable; import cgl.iotcloud.core.transport.TransportConstants; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; public class RabbitMQSender implements Manageable { private static Logger LOG = LoggerFactory.getLogger(RabbitMQSender.class); private Channel channel; private Connection conn; private BlockingQueue<MessageContext> outQueue; private String exchangeName; private String routingKey; private String queueName; private String url; private ExecutorService executorService; public RabbitMQSender(BlockingQueue<MessageContext> outQueue, String exchangeName, String routingKey, String queueName, String url) { this.outQueue = outQueue; this.exchangeName = exchangeName; this.routingKey = routingKey; this.url = url; this.queueName = queueName; } public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; } public void start() { ConnectionFactory factory = new ConnectionFactory(); factory.setAutomaticRecoveryEnabled(true); factory.setNetworkRecoveryInterval(5000); try { factory.setUri(url); if (executorService != null) { conn = factory.newConnection(executorService); } else { conn = factory.newConnection(); } channel = conn.createChannel(); channel.exchangeDeclare(exchangeName, "direct", false); channel.queueDeclare(this.queueName, false, false, false, null); channel.queueBind(queueName, exchangeName, routingKey); Thread t = new Thread(new Worker()); t.start(); } catch (IOException e) { String msg = "Error creating the RabbitMQ channel"; LOG.error(msg, e); throw new RuntimeException(msg, e); } catch (Exception e) { String msg = "Error creating the RabbitMQ channel"; LOG.error(msg, e); throw new RuntimeException(msg, e); } } public void stop() { try { channel.queueDelete(queueName, true, false); channel.close(); conn.close(); } catch (IOException e) { LOG.error("Error closing the rabbit MQ connection", e); } } private class Worker implements Runnable { @Override public void run() { boolean run = true; int errorCount = 0; while (run) { try { try { MessageContext input = outQueue.take(); Map<String, Object> props = new HashMap<String, Object>(); for (Map.Entry<String, Object> e : input.getProperties().entrySet()) { props.put(e.getKey(), e.getValue()); } props.put(TransportConstants.SENSOR_ID, input.getSensorId()); channel.basicPublish(exchangeName, routingKey, new AMQP.BasicProperties.Builder().headers(props).build(), input.getBody()); } catch (InterruptedException e) { LOG.error("Exception occurred in the worker listening for consumer changes", e); } } catch (Throwable t) { errorCount++; if (errorCount <= 3) { LOG.error("Error occurred " + errorCount + " times.. trying to continue the worker", t); } else { LOG.error("Error occurred " + errorCount + " times.. terminating the worker", t); run = false; } } } String message = "Unexpected notification type"; LOG.error(message); throw new RuntimeException(message); } } }