/*
* Claudia Project
* http://claudia.morfeo-project.org
*
* (C) Copyright 2010 Telefonica Investigacion y Desarrollo
* S.A.Unipersonal (Telefonica I+D)
*
* See CREDITS file for info about members and contributors.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Affero GNU General Public License (AGPL) as
* published by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the Affero GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* If you want to use this software an plan to distribute a
* proprietary application in any way, and you are not licensing and
* distributing your source code under AGPL, you probably need to
* purchase a commercial license of the product. Please contact
* claudia-support@lists.morfeo-project.org for more information.
*/
package com.telefonica.claudia.slm.eventsBus;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import com.telefonica.claudia.slm.common.SMConfiguration;
import com.telefonica.claudia.slm.eventsBus.events.Event;
import com.telefonica.claudia.slm.eventsBus.events.Event.EventType;
public class BusMediator {
private static final String DEFAULT_CONN_FACTORY_NAME = "ConnectionFactory";
private String connFactoryName = null;
private static final long MESSAGE_TIMEOUT=1000*2;
private static Logger logger = Logger.getLogger("Monitoring");
private boolean open = false;
private boolean closed = false;
/** JNDI initial context */
Context initialContext = null;
/** Connection with bus */
private Connection connection = null;
/** Session with bus */
private Session session = null;
private Topic veeHwMonTopic = null;
private Topic infrSLAViolTopic = null;
private Topic servSLAViolTopic = null;
private Topic agentMeasurementTopic = null;
private Topic probesMeasurementTopic = null;
private Topic fsmBusTopic = null;
private Topic smControlTopic = null;
private Queue smiChannelRequest = null;
private Queue smiChannelReply = null;
private Queue administrativeRequest = null;
private Queue administrativeReply = null;
private MessageProducer veeHwMonProducer = null;
private MessageProducer infrSLAViolProducer = null;
private MessageProducer servSLAViolProducer = null;
private MessageProducer agentsMeasProducer = null;
private MessageProducer probesMeasProducer = null;
private MessageProducer smiChannelProducer = null;
private MessageProducer smControlProducer = null;
private MessageProducer administrativeProducer = null;
private MessageProducer fsmBusProducer = null;
private Map<BusListener, List<MessageConsumer>> busListeners = new Hashtable<BusListener, List<MessageConsumer>>();
static {
Logger.getLogger("com.telefonica.claudia.slm.eventsBus").setLevel(Level.INFO);
Logger.getLogger("com.telefonica.claudia.slm.eventsBus").addAppender(
new ConsoleAppender(new PatternLayout("%-5p [%t] %c{2}: %m%n"),
"System.out"));
}
public BusMediator(String connFactoryName) {
this.connFactoryName = connFactoryName;
}
public BusMediator(){
this.connFactoryName = DEFAULT_CONN_FACTORY_NAME;
}
public void openJMSSession() throws NamingException, JMSException {
logger.info("Getting initial JNDI context");
initialContext = new InitialContext(SMConfiguration.getInstance().getJNDIEnv());
logger.info("Looking up for JMS connection factory " + connFactoryName);
ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup(connFactoryName);
logger.info("Creating connection to bus");
connection = connectionFactory.createConnection();
connection.start();
logger.info("Creating session");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
logger.info("Getting topic for event type " + EventType.VEE_HW_MEASUREMENT);
veeHwMonTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.VEE_HW_MEASUREMENT));
veeHwMonProducer = session.createProducer(veeHwMonTopic);
logger.info("Getting topic for event type " + EventType.INFRASTRUCTURE_SLA_VIOLATION_EVENT);
infrSLAViolTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.INFRASTRUCTURE_SLA_VIOLATION_EVENT));
infrSLAViolProducer = session.createProducer(infrSLAViolTopic);
logger.info("Getting topic for event type " + EventType.SERVICE_SLA_VIOLATION_EVENT);
servSLAViolTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.SERVICE_SLA_VIOLATION_EVENT));
servSLAViolProducer = session.createProducer(servSLAViolTopic);
logger.info("Getting topic for event type " + EventType.AGENT_MEASUREMENT);
agentMeasurementTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.AGENT_MEASUREMENT));
agentsMeasProducer = session.createProducer(agentMeasurementTopic);
logger.info("Getting topic for event type " + EventType.PROBE_MEASUREMENT);
probesMeasurementTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.PROBE_MEASUREMENT));
probesMeasProducer = session.createProducer(probesMeasurementTopic);
logger.info("Getting topic for event type " + EventType.SM_CONTROL_EVENT);
smControlTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.SM_CONTROL_EVENT));
smControlProducer = session.createProducer(smControlTopic);
logger.info("Getting queue for event type " + EventType.SMI_CHANNEL_EVENT);
smiChannelRequest = (Queue)initialContext.lookup(Event.busQueueForEventType(EventType.SMI_CHANNEL_EVENT, false));
smiChannelReply = (Queue)initialContext.lookup(Event.busQueueForEventType(EventType.SMI_CHANNEL_EVENT, true));
smiChannelProducer = session.createProducer(smiChannelReply);
logger.info("Getting topic for event type " + EventType.FSM_BUS_EVENT);
fsmBusTopic = (Topic)initialContext.lookup(Event.busTopicForEventType(EventType.FSM_BUS_EVENT));
fsmBusProducer = session.createProducer(fsmBusTopic);
logger.info("Getting queue for event type " + EventType.ADMINISTRATIVE_EVENT);
administrativeRequest = (Queue)initialContext.lookup(Event.busQueueForEventType(EventType.ADMINISTRATIVE_EVENT, false));
administrativeReply = (Queue)initialContext.lookup(Event.busQueueForEventType(EventType.ADMINISTRATIVE_EVENT, true));
administrativeProducer = session.createProducer(administrativeReply);
open = true; closed = false;
}
/**
* Clean all the queues where the BusMediator is suscribed, consuming all the messages in the queue and
* discarding them.
*/
@SuppressWarnings("unchecked")
public void cleanQueues() {
if (session== null) return;
Queue[] queues = new Queue[] {smiChannelRequest, administrativeRequest};
for (Queue actualQueue: queues)
try {
QueueBrowser qb = session.createBrowser(actualQueue);
Enumeration e = qb.getEnumeration();
MessageConsumer messageConsumer = session.createConsumer(actualQueue);
int n=0;
while (e.hasMoreElements()) {
e.nextElement();
n++;
}
for (int i =0; i < n; i++) {
logger.info("Deleting pending messages...");
messageConsumer.receive(MESSAGE_TIMEOUT);
}
messageConsumer.close();
try { Thread.sleep(5000); } catch (InterruptedException ex) { }
} catch (JMSException e) {
logger.warn("Exception cleaning the queue. Execution might continue without errors: " + e.getMessage());
}
}
/**
* Proxy for the sendEvent method, without the need of passing the properties parameter.
*
* @param event
* Event to be sent.
*
* @throws JMSException
*/
public void sendEvent(Event event) throws JMSException {
sendEvent(event, null);
}
/**
* Sends the event passed as a parameter to the event bus. The topic will be chosen
* depending on the event type.
*
* Aditionally, selector properties may be specified. These are properties that will
* be added to the message header, and who let the event bus consumer distingish
* which messages it is interested in.
*
*
* @param event
* Event to be sent
*
* @param selectors
* Map with the properties to be added to the message header for message selection.
*
* @throws JMSException
*/
public void sendEvent(Event event, HashMap<String, String> selectors) throws JMSException {
ObjectMessage message = session.createObjectMessage(event);
if (selectors != null) {
for (String key: selectors.keySet())
message.setStringProperty(key, selectors.get(key));
}
switch(event.getEventType()) {
case VEE_HW_MEASUREMENT:
logger.debug("Sending VEE Hw measurement event");
veeHwMonProducer.send(message);
return;
case INFRASTRUCTURE_SLA_VIOLATION_EVENT:
logger.debug("Sending infrastructure SLA violation event");
infrSLAViolProducer.send(message);
return;
case SERVICE_SLA_VIOLATION_EVENT:
logger.debug("Sending service SLA violation event");
servSLAViolProducer.send(message);
return;
case AGENT_MEASUREMENT:
logger.debug("Sending agent measurement event");
agentsMeasProducer.send(message);
return;
case PROBE_MEASUREMENT:
logger.debug("Sending probe measurement event");
probesMeasProducer.send(message);
return;
case SMI_CHANNEL_EVENT:
logger.debug("Sending SMI channel event");
smiChannelProducer.send(message);
return;
case SM_CONTROL_EVENT:
logger.debug("Sending SM Control event");
smControlProducer.send(message);
return;
case ADMINISTRATIVE_EVENT:
logger.debug("Sending Administrative event");
administrativeProducer.send(message);
return;
case FSM_BUS_EVENT:
logger.debug("Sending FSM Communication event");
fsmBusProducer.send(message);
return;
default:
logger.error("Event type " + event.getEventType() + " not supported by this bus mediator.");
throw new Error("Event type " + event.getEventType() + " not supported by mediator.");
}
}
public void registerEventsReceiver(BusListener busListener, EventType eventType) throws JMSException {
MessageConsumer messageConsumer = null;
switch(eventType) {
case VEE_HW_MEASUREMENT:
logger.debug("Creating events listener for VEE Hw events");
messageConsumer = session.createConsumer(veeHwMonTopic);
break;
case INFRASTRUCTURE_SLA_VIOLATION_EVENT:
logger.debug("Creating events listener for infrastructure SLA violation events");
messageConsumer = session.createConsumer(infrSLAViolTopic);
break;
case SERVICE_SLA_VIOLATION_EVENT:
logger.debug("Creating events listener for service SLA violation events");
messageConsumer = session.createConsumer(servSLAViolTopic);
break;
case AGENT_MEASUREMENT:
logger.debug("Creating events listener for agent measure events");
messageConsumer = session.createConsumer(agentMeasurementTopic);
break;
case PROBE_MEASUREMENT:
logger.debug("Creating events listener for probes measure events");
messageConsumer = session.createConsumer(probesMeasurementTopic);
break;
case SMI_CHANNEL_EVENT:
logger.debug("Creating events listener for SMI Comunication");
messageConsumer = session.createConsumer(smiChannelRequest);
break;
case SM_CONTROL_EVENT:
logger.debug("Creating events listener for SM Control Comunication");
messageConsumer = session.createConsumer(smControlTopic);
break;
case ADMINISTRATIVE_EVENT:
logger.debug("Creating events listener for Administration Communication");
messageConsumer = session.createConsumer(administrativeRequest);
break;
case FSM_BUS_EVENT:
logger.debug("Creating events listener for communication between FSM and LCC");
messageConsumer = session.createConsumer(fsmBusTopic);
break;
default :
logger.error("Event type " + eventType + " not supported by this bus mediator.");
throw new Error("Event type " + eventType + " not supported by mediator.");
}
messageConsumer.setMessageListener(new EventsReceiver(busListener, eventType));
if(!busListeners.containsKey(busListener))
busListeners.put(busListener, new ArrayList<MessageConsumer>());
busListeners.get(busListener).add(messageConsumer);
return;
}
public void unregisterEventsReceiver(BusListener busListener) {
List<MessageConsumer> messageConsumers = busListeners.remove(busListener);
if(messageConsumers == null)
return;
for(MessageConsumer messageConsumer : messageConsumers)
try {
messageConsumer.close();
} catch (JMSException ex) {
logger.error("JMS Exception caught when closing message consumer", ex);
}
}
public void closeJMSSession() {
if(!open || closed)
return;
for(BusListener busListener : busListeners.keySet())
unregisterEventsReceiver(busListener);
busListeners.clear();
if(session != null) {
logger.info("Clossing session");
try{
session.close();
} catch(JMSException ex) {
logger.error("JMS Exception caught when clossing session", ex);
}
}
if(connection != null) {
logger.info("Clossing connection with bus");
try {
connection.close();
} catch(JMSException ex) {
logger.error("JMS Exception caught when clossing session", ex);
}
}
open = false; closed = true;
}
@Override
protected void finalize() {
closeJMSSession();
}
}
class EventsReceiver implements MessageListener {
private static Logger logger = Logger.getLogger(EventsReceiver.class);
private BusListener busListener = null;
private EventType eventType = null;
public EventsReceiver(BusListener busListener, EventType eventType) {
this.busListener = busListener;
this.eventType = eventType;
}
public void onMessage(Message message) {
if(message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage)message;
try {
if(objectMessage.getObject() instanceof Event) {
Event event = (Event)objectMessage.getObject();
if(event.getEventType() == eventType)
busListener.onEvent(event);
else
logger.error("Received event is of type " + event.getEventType() +
" not of expected type " + eventType);
} else
logger.error("Message does not contain an Event");
} catch (JMSException ex) {
logger.error("JMSException when extracting ObjectMessage instance from message", ex);
}
} else
logger.error("Message is not instance of ObjectMessage");
}
}