/*
ALMA - Atacama Large Millimiter Array
* Copyright (c) European Southern Observatory, 2013
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package alma.alarmsystem.clients.alarm;
import java.util.Collection;
import java.util.Collections;
import java.util.Vector;
import alma.alarmsystem.clients.alarm.AlarmStatistics.AlarmStatField;
import cern.laser.client.data.Alarm;
import cern.laser.client.services.selection.AlarmSelectionListener;
import cern.laser.client.services.selection.LaserSelectionException;
/**
* The container of alarm category listener.
* <BR>
* {@link AlarmListenersContainer} owns 2 lists of listeners: one for the alarms
* and another one for the statistics.
*
* <P>When finished using this object, {@link #close()} must be called
* to free the resources
*
* @author acaproni
* @since ACS-12.2
*/
public class AlarmListenersContainer {
/**
* Objects of {@link AlarmListener} are immutable and composed
* of a listener and a filter based on the triplet.
* <P>
* If the filter is <code>null</code> then no filtering is applied.
*
* @author acaproni
* @since ACS-12.2
*/
public final class AlarmListener {
/**
* The listener of alarms and exceptions
*/
public final AlarmSelectionListener listener;
/**
* The filtering based on the triplets.
*/
public final AlarmFilter filter;
/**
* Constructor
*
* @param listener The not <code>null</code> listener of alarms and exceptions
* @param filter The filter for the alarms (if <code>null</code> no filters is applied)
*/
public AlarmListener(AlarmSelectionListener listener, AlarmFilter filter) {
if (listener==null) {
throw new IllegalArgumentException("The listener can't be null");
}
this.listener=listener;
this.filter=filter;
}
}
/**
* Signal that the object has been closed
*/
private volatile boolean closed=false;
/**
* The container of alarms and exceptions listeners
*/
private final Collection<AlarmListener> alarmListeners = Collections.synchronizedCollection(new Vector<AlarmListener>());
/**
* The container of astatistics listeners
*/
private final Collection<AlarmCategoryStatListener> statListeners = Collections.synchronizedCollection(new Vector<AlarmCategoryStatListener>());
/**
* Add a listener of alarms
*
* @param listener The listener of alarms and exceptions
* @return <code>true</code> if this collection changed as a result of the call
*/
public boolean addAlarmListener(AlarmListener listener) {
if (listener==null) {
throw new IllegalArgumentException("The listener can't be null");
}
if (closed) {
return false;
}
return alarmListeners.add(listener);
}
/**
* Add a new lister to be notified for alarms and exceptions
*
* @param listener The not <code>null</code> listener of alarms and exceptions
* @param filter The filter for the alarms (if <code>null</code> no filters is applied)
* @return The {@link AlarmListener} stored in the container
* or <code>null</code> if the lister has not been added to the container
*/
public AlarmListener addAlarmListener(AlarmSelectionListener listener, AlarmFilter filter) {
if (listener==null) {
throw new IllegalArgumentException("The listener can't be null");
}
AlarmListener ret = new AlarmListener(listener,filter);
if (this.addAlarmListener(ret)) {
return ret;
} else {
return null;
}
}
/**
* Add a new unfiltered lister to be notified for alarms and exceptions
*
* @param listener The not <code>null</code> listener of alarms and exceptions
* @return The {@link AlarmListener} stored in the container
* or <code>null</code> if the lister has not been added to the container
*/
public AlarmListener addAlarmListener(AlarmSelectionListener listener) {
if (listener==null) {
throw new IllegalArgumentException("The listener can't be null");
}
return this.addAlarmListener(listener, null);
}
/**
* Remove a lister from the container
*
* @param listenerToRemove The not <code>null</code> listener to remove from the container
* @return <code>true</cod>true if an element was removed as a result of this call
*/
public boolean removeAlarmListener(AlarmListener listenerToRemove) {
if (listenerToRemove==null) {
throw new IllegalArgumentException("The listener can't be null");
}
return alarmListeners.remove(listenerToRemove);
}
/**
* Close the object an free the resources
*/
public void close() {
closed=true;
alarmListeners.clear();
statListeners.clear();
}
/**
* Deliver the alarm to the listeners of the container
* whose filter matches with the triplet of the alarm.
*
* @param alarm The not <code>null</code> alarm to forward to the listeners
*/
public void dispatchAlarm(Alarm alarm) {
if (alarm==null) {
throw new IllegalArgumentException("A null alarm can't be delivered to listeners");
}
synchronized (alarmListeners) {
for (AlarmListener l: alarmListeners) {
if (l.filter==null) {
// no filtering
l.listener.onAlarm(alarm);
} else {
String ff=alarm.getTriplet().getFaultFamily();
String fm=alarm.getTriplet().getFaultMember();
Integer fc=alarm.getTriplet().getFaultCode();
if (l.filter.matches(ff, fm, fc)) {
l.listener.onAlarm(alarm);
}
}
if (closed) {
return;
}
}
}
}
/**
* Deliver the exception to the listeners of the container
* whose filter matches with the triplet of the alarm.
*
* @param exception The not <code>null</code> exception to forward to the listeners
*/
public void dispatchException(LaserSelectionException exception) {
if (exception==null) {
throw new IllegalArgumentException("A null exception can't be delivered to listeners");
}
synchronized (alarmListeners) {
for (AlarmListener l: alarmListeners) {
l.listener.onException(exception);
if (closed) {
return;
}
}
}
}
/**
* Add a listener to be notified about statistics
*
* @param listener The not <code>null</code> listener to be notified
* @return <code>true</code> if this collection changed as a result of the call
*/
public boolean addStatsListener(AlarmCategoryStatListener listener) {
if (listener==null) {
throw new IllegalArgumentException("The listener can't be null");
}
if (closed) {
return false;
}
return statListeners.add(listener);
}
/**
* Remove a lister of statistics from the container
*
* @param listenerToRemove The not <code>null</code> listener to remove from the container
* @return <code>true</cod>true if an element was removed as a result of this call
*/
public boolean removeStatListener(AlarmCategoryStatListener listenerToRemove) {
if (listenerToRemove==null) {
throw new IllegalArgumentException("The listener can't be null");
}
return statListeners.remove(listenerToRemove);
}
/**
* Deliver the statistics to the listeners.
*
* @param exception The not <code>null</code> exception to forward to the listeners
*/
public void dispatchStatistics(AlarmStatistics stats) {
if (stats==null) {
throw new IllegalArgumentException("A null AlarmStatistics can't be delivered to listeners");
}
synchronized (statListeners) {
for (AlarmCategoryStatListener l: statListeners) {
l.activationAlarmsStats(
stats.getStatValue(AlarmStatField.ACTIVE),
stats.getStatValue(AlarmStatField.PRI1),
stats.getStatValue(AlarmStatField.PRI2),
stats.getStatValue(AlarmStatField.PRI3),
stats.getStatValue(AlarmStatField.PRI4));
l.reductionAlarmsStat(
stats.getStatValue(AlarmStatField.REDUCED),
stats.getStatValue(AlarmStatField.MASKED),
stats.getStatValue(AlarmStatField.MULTIPLICITY_PARENT),
stats.getStatValue(AlarmStatField.NODE_PARENT),
stats.getStatValue(AlarmStatField.MULTIPLICITY_CHILD),
stats.getStatValue(AlarmStatField.NODE_CHILD));
if (closed) {
return;
}
}
}
}
public int getAlarmListenersSize() {
return alarmListeners.size();
}
public int getStatListenersSize() {
return statListeners.size();
}
}