package javax.slee.management;
import java.util.HashMap;
import java.util.Iterator;
import javax.management.Notification;
import javax.management.NotificationFilter;
/**
* A notification filter that supresses equivalent {@link AlarmNotification}s
* until a specified number have occurred within a specified time period. Once
* the threshold has been reached, the next equivalent alarm notification is allowed
* through the filter, and the cycle restarts. The cycle also restarts if the time
* period from the first notification expires without a notification being sent.
* This filter can be used to suppress alarms that occur and then clear up spontaneously.
* <p>
* Formally: Given a series of duplicate alarm notifications, if
* <code>threshold + 1</code> notification are observed within <code>period</code>
* milliseconds of the first notification, notification number <code>threshold + 1</code>
* is delivered to notification listeners and counting restarts from notification
* number <code>threshold + 2</code>.
* <p>
* Alarm notification equivalence is tested using the {@link AlarmNotification#equals}
* method.
* <p>
* Notifications that are not instances of {@link AlarmNotification} are suppressed
* by this filter.
* <p>
* <i>Note:</i> This filter implementation does not use threads to clear stale timeouts.
* Instead, stale timeouts are cleared on each invocation of {@link #isNotificationEnabled
* isNotificationEnabled}. Methods in this class are also thread-safe.
*/
public class AlarmThresholdFilter implements NotificationFilter {
/**
* Create an <code>AlarmThresholdFilter</code>.
* @param threshold the number of duplicate notifications that must occur within
* the specified time period before the following duplicate notification
* is delivered to notification listeners.
* @param period the period (measured in ms) during which duplicate alarm
* notifications within the threshold number will be discarded.
*/
public AlarmThresholdFilter(int threshold, long period) {
this.threshold = threshold;
this.period = period;
}
/**
* Determine whether the specified notification should be delivered to notification
* listeners using this notification filter.
* @param notification the notification to be sent.
* @return <code>true</code> if the notification should be delivered to notification
* listeners, <code>false</code> otherwise. This method always returns
* <code>false</code> if <code>notification</code> is not an instance of
* {@link AlarmNotification}.
*/
public boolean isNotificationEnabled(Notification notification) {
if (!(notification instanceof AlarmNotification)) return false;
synchronized (knownAlarms) {
clearStaleTimeouts();
NotificationInfo info = (NotificationInfo)knownAlarms.get(notification);
if (info == null) {
// we've not seen this alarm before, or the period has expired since
// the first notification
knownAlarms.put(notification, new NotificationInfo(System.currentTimeMillis()));
return false;
}
if (++info.count == threshold) {
// passed threshold
knownAlarms.remove(notification);
return true;
}
return false;
}
}
// private
private void clearStaleTimeouts() {
Iterator iterator = knownAlarms.values().iterator();
long currentTime = System.currentTimeMillis();
while (iterator.hasNext()) {
NotificationInfo info = (NotificationInfo)iterator.next();
// if period has expired remove reference to the notification
if ((info.firstSeenTime + period) < currentTime) {
iterator.remove();
}
}
}
private final class NotificationInfo {
NotificationInfo(long currentTime) {
this.firstSeenTime = currentTime;
}
final long firstSeenTime;
int count = 0;
}
private final int threshold;
private final long period;
private final HashMap knownAlarms = new HashMap();
}