package Messaging;
import GlobalData.CTANetwork;
import System.PeopleCTA;
import com.rabbitmq.client.AMQP.*;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
//import com.rabbitmq.client.ConnectionParameters;
import com.rabbitmq.client.QueueingConsumer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A static class to manage send and receive from the queue. It extends thread
* so that receive can be done in a loop. This class handles the rabbitMQ
* message queue for the given CTA
*/
public class QueueManager extends Thread implements Serializable {
/**
* The rabbitMQ queue manager object
*/
private static QueueManager queueManager = null;
/**
* The parameters for the queues to be created
*/
private QueueParameters queueParameters = null;
/**
* The rabbitMQ queue receiver object
*/
private QueueUser queueUser = null;
/**
* A hash map of the list of rabbitMQ channels corresponding the hostname
* Each hostname is a host running CTA and these channels are used to send
* messages to them. This map represents a directory / address map
*/
private HashMap<String, Channel> hostChannelMap = null;
/**
* Flag to check to set up a new queue listener
*/
public boolean setupQueueListener = false;
/**
* Create a new queue manager given the QueueParameters
*
* @param queueParameters the QueueParameters for the queue manager
* @see QueueManager
* @see QueueParameters
*/
private QueueManager(QueueParameters queueParameters) {
this.queueParameters = queueParameters;
}
/**
* Get an instance of the QueueManager
*
* @param queueParameters the parameters for the QueueManager
* @param queueUser the QueueUser for the QueueManager
* @return returns an instance of QueueManager
* @see QueueManager
*/
public static QueueManager getInstance(QueueParameters queueParameters, QueueUser queueUser) {
if (queueManager == null) {
queueManager = new QueueManager(queueParameters);
}
queueManager.queueUser = queueUser;
return queueManager;
}
/**
* The run method addes a listener which listens to received messages in a
* seperate theread
*/
@Override
public void run() {
addQueueListener(queueParameters);
}
/**
* This method creates a connection to the rabbitMQ server on each of the
* given hosts and opens channels for communication. These channels are used
* for communication between between the given CTA and the rest of the CTAs.
*
* @throws Exception
*/
private void createConnectionAndChannel() throws Exception {
Utilities.Log.logger.info("Creating a connection and channel");
List<String> hosts = CTANetwork.hosts;
Map<String, QueueParameters> hostQueueParamMap = CTANetwork.hostQueueMap;
Utilities.Log.logger.info("Size of hosts: " + hosts.size() + " and host queue map: " + hostQueueParamMap.size());
hostChannelMap = new HashMap<String, Channel>();
for (int i = 0; i < hosts.size(); i++) {
String host = hosts.get(i);
QueueParameters hostQueueParameters = hostQueueParamMap.get(host);
//ConnectionParameters params = new ConnectionParameters();
//params.setUsername(hostQueueParameters.username);
//params.setPassword(hostQueueParameters.password);
//params.setVirtualHost(hostQueueParameters.virtualHost);
//params.setRequestedHeartbeat(0);
//ConnectionFactory factory = new ConnectionFactory(params);
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(host);
factory.setPort(13000);
factory.setUsername(hostQueueParameters.username);
factory.setPassword(hostQueueParameters.password);
factory.setVirtualHost(hostQueueParameters.virtualHost);
factory.setRequestedHeartbeat(0);
//Connection conn = null;
//conn= factory.newConnection();
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.exchangeDeclare(hostQueueParameters.exchange, "direct");
//channel.queueDeclarePassive(hostQueueParameters.queueName);
//channel.queueDeclare();
channel.queueDeclare(hostQueueParameters.queueName,false,false,true,null);
channel.queueBind(hostQueueParameters.queueName, hostQueueParameters.exchange, hostQueueParameters.routingKey);
hostChannelMap.put(host, channel);
}
setupQueueListener = true;
Utilities.Log.logger.info("Finished creating connection and channel");
Utilities.Log.logger.info("Contents of Host Channel Map: " + hostChannelMap.toString());
}
/**
* This method is called during CTA shutdown for stopping the messaging and
* running cleanup on the message queues and channels
*
* @throws IOException
*/
public void exitMessaging() throws IOException {
List<String> hosts = CTANetwork.hosts;
for (int i = 0; i < hosts.size(); i++) {
String host = hosts.get(i);
Channel channel = hostChannelMap.get(host);
Connection conn = channel.getConnection();
channel.close();
conn.close();
}
}
/**
* This method adds a new queue listener given the queue parameters. The
* listener waits for a message to arrive and calls the appropriate method
* for processing, after it arrives
*
* @param queueParameters the QueueParameters for listening
* @see QueueParameters
*/
private void addQueueListener(QueueParameters queueParameters) {
Utilities.Log.logger.info("Adding queue listener");
try {
createConnectionAndChannel();
Utilities.Log.logger.info("started listening to input queue");
// ConnectionParameters params = new ConnectionParameters();
// params.setUsername(queueParameters.username);
// params.setPassword(queueParameters.password);
// params.setVirtualHost(queueParameters.virtualHost);
// params.setRequestedHeartbeat(0);
// ConnectionFactory factory = new ConnectionFactory(params);
// Connection conn = null;
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(GlobalData.Constants.localHost);
factory.setPort(13000);
factory.setUsername(queueParameters.username);
factory.setPassword(queueParameters.password);
factory.setVirtualHost(queueParameters.virtualHost);
factory.setRequestedHeartbeat(0);
Connection conn = factory.newConnection();
//conn = factory.newConnection(GlobalData.Constants.localHost);
Channel channel = conn.createChannel();
channel.exchangeDeclare(queueParameters.exchange, "direct");
//channel.queueDeclare(queueParameters.queueName);
//channel.queueDeclare();
channel.queueDeclare(queueParameters.queueName,false,false,true,null);
channel.queueBind(queueParameters.queueName, queueParameters.exchange, queueParameters.routingKey);
//byte[] messageBodyBytes = "Hello, worldoooo!".getBytes();
//channel.basicPublish(queueParameters.exchange, queueParameters.routingKey, null, messageBodyBytes);
boolean noAck = false;
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueParameters.queueName, noAck, consumer);
//AMQP.Queue.Purge(1, queueParameters.queueName, true);
while (!noAck) {
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 1");
QueueingConsumer.Delivery delivery;
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 2");
try {
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 3");
delivery = consumer.nextDelivery();
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 4");
} catch (InterruptedException ie) {
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 5");
continue;
}
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 6");
//String message = new String(delivery.getBody());
InputStream inputStream = new ByteArrayInputStream(delivery.getBody());
ObjectInputStream input = new ObjectInputStream(inputStream);
Message message = (Message) input.readObject();
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 7");
inputStream.close();
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 8");
input.close();
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 9");
//System.out.println("Received Message" + message);
Utilities.Log.logger.info("Received Message");
queueUser.processMessage.message = message;
queueUser.processMessage.run();
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 10");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
// Utilities.Log.logger.info("QM: I am listening for messages in the while loop 11");
}
Utilities.Log.logger.info("Finished Adding queue listener");
} catch (ClassNotFoundException ex) {
Logger.getLogger(QueueManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(QueueManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(QueueManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method is called when a message has to be sent form one CTA to
* another. The method makes use of the already open channels between the
* CTAs to send its messages.
*
* @param host the destination host name
* @param message the message that has to be sent
* @return true if the message was successfully sent
* @see Message
*/
public boolean send(String host, Message message) {
//Utilities.Log.logger.info("RabbitMQ Send Method");
while (setupQueueListener == false) {
Utilities.Log.logger.info("Waiting to send");
}
QueueParameters hostQueueParameters = CTANetwork.hostQueueMap.get(host);
ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
//System.out.println(" send 1");
try {
//Utilities.Log.logger.info("Contents of Host Channel Map: " + hostChannelMap.toString());
Channel channel = hostChannelMap.get(host);
ObjectOutputStream outputWriter = new ObjectOutputStream(outputBuffer);
outputWriter.writeObject(message);
outputWriter.close(); //write to buffer and flush;
byte[] messageBodyBytes = outputBuffer.toByteArray();
channel.basicPublish(hostQueueParameters.exchange, hostQueueParameters.routingKey, null, messageBodyBytes);
outputBuffer.close();
return true;
} catch (IOException ex) {
Logger.getLogger(QueueManager.class.getName()).log(Level.SEVERE, null, ex);
Utilities.Log.logger.info("Error Sending Message" + ex.getMessage());
return false;
}
}
/**
* This method checks if two QueueManager objects are same
*
* @param obj an object of QueueManager type
* @return true if the objects are equal
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final QueueManager other = (QueueManager) obj;
if (this.queueParameters != other.queueParameters && (this.queueParameters == null || !this.queueParameters.equals(other.queueParameters))) {
return false;
}
return true;
}
/**
* Returns the hash code of the QueueManager object
*
* @return the hash code of the QueueManager object
*/
@Override
public int hashCode() {
int hash = 5;
hash = 79 * hash + (this.queueParameters != null ? this.queueParameters.hashCode() : 0);
return hash;
}
/**
* This is a Debug Main method used to ping different servers
*
* @param args UNSUED
*/
public static void main(String[] args) {
QueueParameters queueParameters = new QueueParameters("queue1", "guest", "guest", "/", "77", "exchangeName", "routingkey");
CTANetwork.hostQueueMap.put("192.168.0.124", queueParameters);
PeopleCTA peopleCTA = new PeopleCTA();
QueueManager qm = QueueManager.getInstance(queueParameters, peopleCTA);
//qm.send("192.168.0.124", "192.168.0.124 - gud morng");
}
}