/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.monitor.alarm;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.ObjectName;
import org.jboss.system.ServiceMBeanSupport;
/**
* AlarmManager
*
* @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
* @version $Revision: 81038 $
*/
public class AlarmManager
{
// Private/Protected Data ----------------------------------------
/** Mediates the related MBean */
protected MBeanImplAccess mbeanImpl;
/** Holds map of maps, each one containing type --> severity mappings */
private Map nameMap;
// Constructors --------------------------------------------------
/**
* CTOR
*
* @param mbeanImpl providing access to notification broadcasting
*/
public AlarmManager(MBeanImplAccess mbeanImpl)
{
this.mbeanImpl = mbeanImpl;
this.nameMap = new HashMap();
}
/**
* CTOR
*
* @param service hosting the AlarmManager
*/
public AlarmManager(final ServiceMBeanSupport service)
{
this(new MBeanImplAccess() {
public ObjectName getMBeanName() { return service.getServiceName(); }
public long getSequenceNumber() { return service.nextNotificationSequenceNumber(); }
public void emitNotification(Notification n) { service.sendNotification(n); }
});
}
// High-level part of the interface used to support Statefull Alarms.
// The sending of the actual AlarmNotifications is done through the
// sendAlarmNotification() method.
/**
* Sets the severity of an Alarm, keyed by its type, without producing
* an AlarmNotification, for the current mbean.
*/
public void setSeverity(String type, int severity)
{
setSeverity(mbeanImpl.getMBeanName(), type, severity);
}
/**
* Sets the severity of an Alarm, keyed by its type, without producing
* an AlarmNotification, for the specified mbean.
*/
public void setSeverity(ObjectName name, String type, int severity)
{
synchronized (this)
{
// find or add TypeMap
Map typeMap = getTypeMap(name);
Severity s = (Severity)typeMap.get(type);
if (s == null)
{
typeMap.put(type, new Severity(severity));
}
else
{
s.severity = severity;
}
}
}
/**
* Gets the severity of an alarm, keyed by its type, for the current mbean.
*/
public int getSeverity(String type)
{
return getSeverity(mbeanImpl.getMBeanName(), type);
}
/**
* Gets the severity of an alarm, keyed by its type, for the specified mbean.
*/
public int getSeverity(ObjectName name, String type)
{
synchronized (this)
{
Map typeMap = (Map)nameMap.get(name);
if (typeMap == null)
{
return Alarm.SEVERITY_NORMAL;
}
else
{
Severity s = (Severity)typeMap.get(type);
if (s == null)
{
return Alarm.SEVERITY_NORMAL;
}
else
{
return s.severity;
}
}
}
}
/**
* Gets the severity of an alarm as a String,
* keyed by its type for the current mbean
*/
public String getSeverityAsString(String type)
{
return getSeverityAsString(mbeanImpl.getMBeanName(), type);
}
/**
* Gets the severity of an alarm as a String,
* keyed by its type for the specified mbean
*/
public String getSeverityAsString(ObjectName name, String type)
{
return Alarm.SEVERITY_STRINGS[getSeverity(name, type)];
}
/**
* Sets the alarm for the current mbean, keyed by its type.
* If severity has changed an AlarmNotification will be thrown.
* The alarmState of the AlarmNotification will be either
* Alarm.STATE_CREATED, Alarm.STATE_CHANGED or Alarm.STATE_CLEARED.
*/
public void setAlarm(String type, int severity, String message, Object userData)
{
setAlarm(mbeanImpl.getMBeanName(), type, severity, message, userData);
}
/**
* Sets the alarm for the specified target mbean, keyed by its type.
* If severity has changed an AlarmNotification will be thrown.
* The alarmState of the AlarmNotification will be either
* Alarm.STATE_CREATED, Alarm.STATE_CHANGED or Alarm.STATE_CLEARED.
*/
public void setAlarm(ObjectName target, String type, int severity, String message, Object userData)
{
Severity s;
synchronized (this)
{
Map typeMap = getTypeMap(target);
s = (Severity)typeMap.get(type);
// if alarm does not exist, add it with a default severity
if (s == null)
{
s = new Severity(Alarm.SEVERITY_NORMAL);
typeMap.put(type, s);
}
}
// There must be a small race condition here if 2 threads
// set the same severity, thus producing duplicate notifications
// Not a big deal...
int oldSeverity = s.severity;
// if the severity has changed, send an AlarmNotification
if (severity != oldSeverity)
{
// store the new severity
s.severity = severity;
if (severity == Alarm.SEVERITY_NORMAL)
{
sendAlarmNotification(
target, type, severity, Alarm.STATE_CLEARED, message, userData);
}
else if (oldSeverity == Alarm.SEVERITY_NORMAL)
{
sendAlarmNotification(
target, type, severity, Alarm.STATE_CREATED, message, userData);
}
else
{
sendAlarmNotification(
target, type, severity, Alarm.STATE_CHANGED, message, userData);
}
}
}
/**
* See set Alarm above
*
* Essentially a helper method that will populate the userData field
* of the Notification with a HashMap, containing a single key/value pair.
*
* Note, that an AlarmNotification will not be emitted if there is no
* severity change.
*/
public void setAlarm(String type, int severity, String message, String key, Object value)
{
setAlarm(mbeanImpl.getMBeanName(), type, severity, message, key, value);
}
/**
* See set Alarm above
*
* Essentially a helper method that will populate the userData field
* of the Notification with a HashMap, containing a single key/value pair.
*
* Note, that an AlarmNotification will not be thrown if there is no
* severity change.
*/
public void setAlarm(ObjectName target, String type, int severity, String message, String key, Object value)
{
HashMap map = new HashMap();
map.put(key, value);
setAlarm(target, type, severity, message, map);
}
// Low-level part of the interface used to generate and send
// various types of notifications, including AlarmNotifications
// corresponding to Stateless Alarms.
/**
* Generates and sends an AlarmNotification.
*
* source, sequenceNumber, timeStamp
* will be automatically filled.
*/
public void sendAlarm(String type, int severity, String message, String key, Object value)
{
sendAlarm(null, type, severity, message, key, value);
}
/**
* Generates and sends an AlarmNotification.
*
* source, sequenceNumber, timeStamp
* will be automatically filled.
*/
public void sendAlarm(ObjectName target, String type, int severity, String message, String key, Object value)
{
HashMap map = new HashMap();
map.put(key, value);
sendAlarm(target, type, severity, message, map);
}
/**
* Generates and sends an AlarmNotification.
*
* source, sequenceNumber, timeStamp
* will be automatically filled.
*/
public void sendAlarm(String type, int severity, String message, Object userData)
{
sendAlarm(null, type, severity, message, userData);
}
/**
* Generates and sends an AlarmNotification.
*
* source, sequenceNumber, timeStamp
* will be automatically filled.
*/
public void sendAlarm(
ObjectName target, String type, int severity, String message, Object userData)
{
sendAlarmNotification(target, type, severity, Alarm.STATE_NONE, message, userData);
}
/**
* Generates and sends an AlarmNotification.
*
* An alarmState of Alarm.STATE_CLEARED forces severity to SEVERITY_NORMAL
*
* source, sequenceNumber, timeStamp
* will be automatically filled.
*/
protected void sendAlarmNotification(
ObjectName target, String type, int severity, int alarmState, String message, Object userData)
{
Notification n = new AlarmNotification(
type,
mbeanImpl.getMBeanName(), // source
target,
severity,
alarmState,
this.mbeanImpl.getSequenceNumber(),
System.currentTimeMillis(),
message
);
n.setUserData(userData);
// send it away
mbeanImpl.emitNotification(n);
}
/**
* Generates and sends an AttributeChangeNotification.
*
* source, sequenceNumber, timeStamp
* will be automatically filled in.
*/
public void sendAttributeChangeNotification(
String type, String message, Object userData,
String attributeName, String attributeType,
Object oldValue, Object newValue)
{
Notification n = new AttributeChangeNotification(
mbeanImpl.getMBeanName(), // source
mbeanImpl.getSequenceNumber(),
System.currentTimeMillis(),
message,
attributeName,
attributeType,
oldValue,
newValue
);
n.setUserData(userData);
// send it away
mbeanImpl.emitNotification(n);
}
/**
* Generates and sends a simple Notification.
*
* source, sequenceNumber, timeStamp
* will be automatically filled in.
*/
public void sendNotification(String type, String message, Object userData)
{
Notification n = new Notification(
type,
mbeanImpl.getMBeanName(), // source
mbeanImpl.getSequenceNumber(),
System.currentTimeMillis(),
message
);
n.setUserData(userData);
// send it away
mbeanImpl.emitNotification(n);
}
/**
* Clear all the stored severities
*
*/
public void clear()
{
synchronized (this)
{
for (Iterator i = nameMap.entrySet().iterator(); i.hasNext(); )
{
Map.Entry entry = (Map.Entry)i.next();
Map typeMap = (Map)entry.getValue();
typeMap.clear();
}
nameMap.clear();
}
}
// Private -------------------------------------------------------
/**
* Return the typeMap for an ObjectName, create it if needed
*/
private Map getTypeMap(ObjectName name)
{
Map typeMap = (Map)nameMap.get(name);
if (typeMap == null)
{
typeMap = new HashMap();
nameMap.put(name, typeMap);
}
return typeMap;
}
// Inner Class ---------------------------------------------------
/**
* Simple Data Holder
*/
private static class Severity
{
public int severity;
public Severity(int severity)
{
this.severity = severity;
}
}
}