package com.kurento.kmf.rabbitmq;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
//import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import com.kurento.kmf.common.Address;
import com.kurento.kmf.common.PropertiesManager;
import com.kurento.kmf.jsonrpcconnector.internal.message.Request;
public class RabbitMqManager {
public static final String RETRY_TIMEOUT_PROPERTY = "rabbit.retryTimeout";
public static final String NUM_RETRIES_PROPERTY = "rabbit.numRetries";
public static final String EVENT_QUEUE_PREFIX = "event_";
public static final String CLIENT_QUEUE_PREFIX = "client_";
public static final String CLIENT_REPLY_QUEUE_PREFIX = "client_reply_";
public static final String MEDIA_PIPELINE_QUEUE_PREFIX = "media_pipeline_";
public static final String PIPELINE_CREATION_QUEUE = "pipeline_creation";
private static final Logger log = LoggerFactory
.getLogger(RabbitMqManager.class);
private final long retryTimeOut;
private final long numRetries;
private static final String EXPIRATION_TIME = "25000";
private CachingConnectionFactory cf;
private RabbitAdmin admin;
private final List<SimpleMessageListenerContainer> containers = new ArrayList<>();
private final Address address;
public interface BrokerMessageReceiverWithResponse {
public String onMessage(String message);
}
public interface BrokerMessageReceiver {
public void onMessage(String message);
}
public RabbitMqManager(Address address) {
this.address = address;
this.retryTimeOut = PropertiesManager.getProperty(
RETRY_TIMEOUT_PROPERTY, 500);
this.numRetries = PropertiesManager
.getProperty(NUM_RETRIES_PROPERTY, 5);
}
public void connect() {
cf = new CachingConnectionFactory(address.getHost(), address.getPort());
admin = new RabbitAdmin(cf);
declarePipelineCreationQueue(admin);
}
private void declarePipelineCreationQueue(RabbitAdmin admin) {
Queue queue = new Queue(PIPELINE_CREATION_QUEUE, true, false, false);
admin.declareQueue(queue);
DirectExchange exchange = new DirectExchange(PIPELINE_CREATION_QUEUE,
true, false);
admin.declareExchange(exchange);
admin.declareBinding(BindingBuilder.bind(queue).to(exchange).with(""));
log.debug("Queue '" + PIPELINE_CREATION_QUEUE
+ "' declared. Exchange '" + PIPELINE_CREATION_QUEUE
+ "' declared.");
}
public Queue declarePipelineQueue(String name) {
Queue queue = new Queue(name);
admin.declareQueue(queue);
return queue;
}
public Queue declareClientQueue() {
return admin.declareQueue();
}
public RabbitTemplate createClientTemplate() {
Queue queue = admin.declareQueue();
RabbitTemplate template = new RabbitTemplate(cf);
template.setReplyTimeout(retryTimeOut);
template.setReplyQueue(queue);
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(
cf);
container.setMessageListener(template);
container.setQueueNames(queue.getName());
container.start();
containers.add(container);
log.debug("Created RabbitMqTemplate receiving messages in queue: {}",
queue.getName());
return template;
}
public String sendAndReceive(String exchange, String routingKey,
Request<? extends Object> message) {
return sendAndReceive(exchange, routingKey, message, null);
}
public String sendAndReceive(String exchange, String routingKey,
Request<? extends Object> request, RabbitTemplate template) {
if (template == null) {
template = new RabbitTemplate(cf);
template.setReplyTimeout(retryTimeOut);
}
log.debug("Req-> Exchange:'" + exchange + "' RoutingKey:'" + routingKey
+ "' " + request);
MessageProperties messageProperties = new MessageProperties();
messageProperties.setExpiration(EXPIRATION_TIME);
messageProperties.setCorrelationId(calculateCorrelationId(request)
.getBytes());
for (int numRequest = 0; numRequest < numRetries + 1; numRequest++) {
if (numRequest > 0) {
log.debug("Retry {} sending message: {}", numRequest, request);
}
Message response = template.sendAndReceive(exchange, routingKey,
new Message(request.toString().getBytes(),
messageProperties));
if (response != null) {
String responseAsString = new String(response.getBody());
log.debug("<-Res " + responseAsString.trim());
return responseAsString;
}
}
throw new RabbitMqException("Timeout waiting a reply to message: "
+ request);
}
private String calculateCorrelationId(Request<? extends Object> request) {
if (request.getSessionId() == null) {
throw new AssertionError(
"request without session can't be send with RabbitMqManager");
}
return request.getSessionId() + "/" + request.getId();
}
public RabbitTemplate createServerTemplate() {
return new RabbitTemplate(cf);
}
public void send(String exchange, String routingKey, String message) {
send(exchange, routingKey, message, null);
}
public void send(String exchange, String routingKey, String message,
RabbitTemplate template) {
if (template == null) {
template = new RabbitTemplate(cf);
}
log.debug("Not-> Exchange:'" + exchange + "' RoutingKey:'" + routingKey
+ "' " + message);
template.send(exchange, routingKey, new Message(message.getBytes(),
new MessageProperties()));
}
public String declareEventsExchange(String pipeline) {
String exchangeName = EVENT_QUEUE_PREFIX + pipeline;
DirectExchange exchange = new DirectExchange(exchangeName, false, true);
admin.declareExchange(exchange);
log.debug("Events exchange '" + exchangeName + "' declared.");
return exchangeName;
}
public void addMessageReceiver(final String queue,
final BrokerMessageReceiver receiver) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(
cf);
MessageListenerAdapter adapter = new MessageListenerAdapter(
new Object() {
@SuppressWarnings("unused")
protected void onMessage(byte[] message) {
onMessage(new String(message));
}
protected void onMessage(String messageJson) {
log.debug("<-Not Queue:'" + queue + "' "
+ messageJson.trim());
receiver.onMessage(messageJson);
}
}, "onMessage");
container.setMessageListener(adapter);
container.setQueueNames(queue);
container.start();
containers.add(container);
log.debug("Registered receiver '" + receiver.getClass().getName()
+ "' for queue '" + queue);
}
public void addMessageReceiverWithResponse(final String queue,
final BrokerMessageReceiverWithResponse receiver) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(
cf);
container.setConcurrentConsumers(10);
MessageListenerAdapter adapter = new MessageListenerAdapter(
new Object() {
@SuppressWarnings("unused")
protected String onMessage(byte[] message) {
String messageJson = new String(message);
log.debug("<-Req Queue:'" + queue + "' " + messageJson);
String responseJson = receiver.onMessage(messageJson);
log.debug("Res-> " + responseJson);
return responseJson;
}
}, "onMessage");
container.setMessageListener(adapter);
container.setQueueNames(queue);
container.start();
containers.add(container);
log.debug("Registered receiver with response '"
+ receiver.getClass().getName() + "' for queue '" + queue);
}
public void bindExchangeToQueue(String exchangeId, String queueId,
String eventRoutingKey) {
Queue queue = new Queue(queueId, false, true, true);
DirectExchange exchange = new DirectExchange(exchangeId);
admin.declareBinding(BindingBuilder.bind(queue).to(exchange)
.with(eventRoutingKey));
log.debug("Exchange '" + exchangeId + "' bind to queue '" + queueId
+ "' with routingKey '" + eventRoutingKey + "'");
}
public String createRoutingKey(String mediaElementId, String eventType) {
return mediaElementId + "/" + eventType;
}
public void destroy() {
for (SimpleMessageListenerContainer container : containers) {
container.destroy();
}
containers.clear();
cf.destroy();
}
}