/*
* ALMA - Atacama Large Millimiter Array (c) European Southern Observatory, 2007
*
* 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
*
*/
/**
* @author acaproni
* @version $Id: AlarmTableModel.java,v 1.40 2012/10/18 12:30:32 acaproni Exp $
* @since
*/
package alma.acsplugins.alarmsystem.gui.table;
import java.awt.Color;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.JComponent;
import javax.swing.table.AbstractTableModel;
import alma.acs.gui.util.threadsupport.EDTExecutor;
import alma.acs.util.IsoDateFormat;
import alma.acsplugins.alarmsystem.gui.ConnectionListener;
import alma.acsplugins.alarmsystem.gui.toolbar.Toolbar.ComboBoxValues;
import alma.acsplugins.alarmsystem.gui.undocumented.table.UndocAlarmTableModel;
import alma.alarmsystem.clients.AlarmCategoryClient;
import cern.laser.client.data.Alarm;
import cern.laser.client.services.selection.AlarmSelectionListener;
import cern.laser.client.services.selection.LaserHeartbeatException;
import cern.laser.client.services.selection.LaserSelectionException;
import com.cosylab.acs.laser.dao.ACSAlarmCacheImpl;
/**
*
* The table model for the table alarms
*
*/
public class AlarmTableModel extends AbstractTableModel implements AlarmSelectionListener, Runnable {
/**
* The title of each column.
*
* To change the initial order of the columns, change the order of the
* declaration of this enumerated.
*
* @author acaproni
*
*/
public enum AlarmTableColumn {
IS_PARENT("","Parent node flag",true), // The entry hides children because of RR
IS_CHILD("","Child node flag",true), // The entry is reduced
ICON("","Not acknowledged flag",true), // The flag
TIME("Time",null,true),
COMPONENT("Component",null,true),
FAMILY("Family",null,true),
CODE("Code",null,false),
CAUSE("Cause",null,true),
DESCRIPTION("Description",null,true),
ACTION("Action",null,true),
PRIORITY("Priority",null,true),
CONSEQUENCE("Consequence",null,false),
URL("URL",null,false),
CONTACT("Contact",null,false),
EMAIL("email",null,false),
GSM("GSM",null,false),
TRIPLET("Triplet",null,false);
/**
* The title of the column as it appears in the table header
*/
public final String title;
/**
* The title of the column as it appears in the table header popup menu
*/
public final String popupTitle;
/**
* If <code>true</code> the column is shown at startup
*/
public boolean visibleAtStartup;
/**
* Constructor
*
* @param title The name of the column in the table header
* @param popupTitle The name of the column in the popup menu;
* if it is <code>null</code> then it is set to be equal to <code>title</code>
* @param initiallyVisible if <code>true</code> the column is visible at startup
*/
private AlarmTableColumn(String title, String popupTitle, boolean initiallyVisible) {
this.title=title;
this.popupTitle= (popupTitle==null) ? title : popupTitle;
this.visibleAtStartup=initiallyVisible;
}
};
/**
* The label of the priority column of the table
*
* @author acaproni
*
*/
public static enum PriorityLabel {
VERY_HIGH("VERY HIGH",Color.red),
HIGH("HIGH", new Color(255,165,31)),
MEDIUM("MEDIUM",Color.yellow),
LOW("LOW",new Color(188,255,188));
/**
* The description label
*/
public final String description;
/**
* The color of the entry in the alarm table
*/
public final Color color;
/**
* Constructor
*
* @param desc The description
* @param col The color
*/
private PriorityLabel(String desc, Color col) {
description=desc;
color=col;
}
/**
* @return The human readable description of the
* priority
*/
public String toString() {
return description;
}
/**
*
* @param priority The priority
* @return The {@link PriorityLabel} of the given priority
*/
public static PriorityLabel fromPriorityNumber(int priority) {
switch (priority) {
case 0: return VERY_HIGH;
case 1: return HIGH;
case 2: return MEDIUM;
case 3: return LOW;
default:
throw new IndexOutOfBoundsException("Invalid priority");
}
}
/**
* @param n The number of the priority
* @return The description of the priority
*/
public static String fromPriorityDesc(int n) {
return fromPriorityNumber(n).description;
}
}
/**
* The content of the priority columns is composed of the label
* and a reference to the {@link AlarmTableEntry} needed to compare
* two entries and sort.
*
* @author acaproni
*
*/
public class Priority implements Comparable<Priority> {
/**
* The priority
*/
public final int priority;
/**
* It is <code>true</code> if the alarm is active
*/
public final AlarmGUIType type;
public Priority(int priority, AlarmGUIType type) {
this.priority=priority;
this.type=type;
}
@Override
public String toString() {
return PriorityLabel.fromPriorityNumber(priority).toString();
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(Priority o) {
if (o==null) {
throw new NullPointerException();
}
if (priority==o.priority && type==o.type) {
return 0;
}
boolean thisActive=type!=AlarmGUIType.INACTIVE;
boolean oActive=o.type!=AlarmGUIType.INACTIVE;
if (thisActive==oActive) {
// Same types but different priorities
Integer thisInteger=Integer.valueOf(priority);
return thisInteger.compareTo(o.priority);
} else if (thisActive){
return -1;
} else {
return +1;
}
}
}
/**
* The date format
*/
private final SimpleDateFormat dateFormat = new IsoDateFormat();
/**
* The counter for the alarms.
* <P>
* <code>counters</code> is immutable. It is created in the constructor and never modified.
* Can we use a better data structure for that?
*/
private final HashMap<AlarmGUIType, AtomicInteger> counters = new HashMap<AlarmGUIType, AtomicInteger>();
/**
* The listener about the status of the connection
*
* @see <code>onException</code>
*/
private ConnectionListener connectionListener=null;
/**
* The queue of alarms received from the <code>CategoryClient</code> that will be
* injected in the table
*/
private final Map<String, AlarmTableEntry> alarmsToAdd = Collections.synchronizedMap(new HashMap<String, AlarmTableEntry>());
/**
* The boolean to pause the refresh of the table if the user pressed the pause button
*/
private final AtomicBoolean paused=new AtomicBoolean(false);
/**
* Signal the thread to terminate
*/
private final AtomicBoolean terminateThread= new AtomicBoolean(false);
/**
* The model of the table of undocumented alarms
*/
private final UndocAlarmTableModel undocModel;
/**
* Constructor
*
* @param owner The component that owns the table
* @param reduce <code>true</code> if the reduction rules must be applied
* @param panel The <code>AlarmPanel</code>
* @param undocModel) The model of the undocumented table
*/
public AlarmTableModel(JComponent owner, boolean reduce, boolean addInactiveAlarms,UndocAlarmTableModel undocModel) {
if (owner==null) {
throw new IllegalArgumentException("The owner component can't be null");
}
if (undocModel==null) {
throw new IllegalArgumentException("The model of undocumented alarms can't be null");
}
this.owner=owner;
this.applyReductionRules=reduce;
this.addInactiveAlarms=addInactiveAlarms;
this.undocModel=undocModel;
this.items = new AlarmsReductionContainer(MAX_ALARMS);
// Put each alarm type in the has map of the counters
for (AlarmGUIType alarmType: AlarmGUIType.values()) {
counters.put(alarmType, new AtomicInteger());
}
}
/**
* Each received alarm is temporarily stored in the {@link #alarmsToAdd} map so that if it appears more then
* once the last occurrence replaces the old one.
* The thread will get alarms from this map and flush them in the container to updated the table (@see {@link #run()}).
*
* @param alarm The alarm to add to the table.
* @see AlarmSelectionListener
*/
public void onAlarm(Alarm alarm) {
// Check if the alarm is not documented
String undoc=alarm.getStatus().getUserProperties().getProperty(ACSAlarmCacheImpl.alarmServerPropkey);
if (ACSAlarmCacheImpl.undocumentedAlarmProp.equals(undoc)) {
undocModel.onAlarm(alarm);
return;
}
AlarmTableEntry tableEntry = new AlarmTableEntry(alarm);
alarmsToAdd.put(alarm.getAlarmId(), tableEntry);
}
private void dumpAlarm(Alarm alarm) {
System.out.print("Alarm received: <"+alarm.getAlarmId()+">");
if (alarm.getStatus().isActive()) {
System.out.println("\tACTIVE");
} else {
System.out.println("\tTERMINATE");
}
System.out.println("\tisNodeChild="+alarm.isNodeChild()+". isNodeParent="+alarm.isNodeParent());
System.out.println("\tisMultiplicityChild="+alarm.isMultiplicityChild()+". isMultiplicityParent="+alarm.isMultiplicityParent());
System.out.println("\tismasked="+alarm.getStatus().isMasked()+", isReduced="+alarm.getStatus().isReduced());
System.out.println("\tsource timestamp = "+alarm.getStatus().getSourceTimestamp());
System.out.println("\tsystem timestamp = "+alarm.getStatus().getSystemTimestamp());
}
/**
* @param alarm The alarm to add
*/
private void addAlarm(AlarmTableEntry alarm) {
if (alarm==null) {
throw new IllegalArgumentException("The alarm can't be null");
}
if (!alarm.getStatus().isActive() && !addInactiveAlarms) {
// do not add inactive alarms
return;
}
try {
items.add(alarm);
} catch (Exception e) {
System.err.println("Error adding an alarm: "+e.getMessage());
e.printStackTrace(System.err);
return;
}
counters.get(alarm.getAlarmType()).incrementAndGet();
}
/**
* Automatically acknowledge an alarm depending on its
* priority and the selected priority level
*
* @param alarm The alarm to acknowledge if its priority
* if greater the the selected priority level
*/
private void autoAcknowledge(AlarmTableEntry alarm) {
if (alarm==null) {
throw new IllegalArgumentException("The alarm can't be null");
}
if (alarm.getStatus().isActive()) {
throw new IllegalArgumentException("Trying to acknowledge an active alarm");
}
if (autoAckLvl==ComboBoxValues.NONE) {
return;
}
int priority=999999; // Big enough
switch (autoAckLvl) {
case PRIORITY1: {
priority = 1;
break;
}
case PRIORITY2: {
priority = 2;
break;
}
case PRIORITY3: {
priority = 3;
break;
}
}
if (alarm.getPriority()>=priority) {
acknowledge(alarm);
}
}
/**
* Acknowledge an alarm that in this version ends up to removing
* from the table
*
* @param alarm The inactive alarm to acknowledge
*/
public synchronized void acknowledge(AlarmTableEntry alarm) {
if (alarm==null) {
throw new IllegalArgumentException("The alarm can't be null");
}
if (alarm.getStatus().isActive()) {
throw new IllegalArgumentException("Trying to acknowledge an active alarm");
}
// Remove the alarm from the table
try {
items.remove(alarm);
} catch (Exception e) {
System.err.println("Error removing an alarm: "+e.getMessage());
e.printStackTrace(System.err);
return;
}
counters.get(AlarmGUIType.fromAlarm(alarm)).decrementAndGet();
EDTExecutor.instance().execute(new Runnable() {
@Override
public void run() {
fireTableDataChanged();
}
});
}
/**
* Replace an alarm already in the table
*
* @param newAlarm The alarm to put in the table
*/
private void replaceAlarm(AlarmTableEntry newAlarm) {
if (newAlarm==null) {
throw new IllegalArgumentException("The alarm can't be null");
}
AlarmTableEntry oldAlarmEntry = items.get(newAlarm.getAlarmId());
AlarmGUIType oldAlarmType = oldAlarmEntry.getAlarmType();
boolean oldAlarmStatus = oldAlarmEntry.getStatus().isActive();
try {
items.replace(newAlarm); // Trigger a CORBA call
} catch (Exception e) {
System.err.println("Error replacing an alarm: "+e.getMessage());
e.printStackTrace(System.err);
return;
}
if (oldAlarmStatus==newAlarm.getStatus().isActive()) {
return;
}
// Update the counters
counters.get(oldAlarmEntry.getAlarmType()).incrementAndGet();
counters.get(oldAlarmType).decrementAndGet();
if (!newAlarm.getStatus().isActive()) {
// The alarm became INACTIVE
autoAcknowledge(newAlarm);
}
}
/**
* Get exception from the client.
* A message is notified to the listener or written in the
* standard error if the listener is <code>null</code>.
*
* @see AlarmSelectionListener
*/
public void onException(LaserSelectionException e) {
if (connectionListener==null) {
System.err.println("Exception: "+e.getCode());
return;
}
if (e.getCode().equals(LaserHeartbeatException.HEARTBEAT_LOST)) {
connectionListener.heartbeatLost();
} else if (e.getCode().equals(LaserHeartbeatException.HEARTBEAT_RECONNECTED)) {
connectionListener.connected();
} else if (e.getCode().equals(LaserHeartbeatException.CONNECTION_DROPPED)) {
connectionListener.disconnected();
} else if (e.getCode().equals(LaserHeartbeatException.CONNECTION_REESTABILISHED)) {
connectionListener.connected();
} else {
// Unrecognized error code
System.err.println("Exception: "+e.getCode());
e.printStackTrace();
}
}
/**
* The max number of alarms in the table
* When the max has been reach, the oldest alarm is removed
* before adding a new one
*/
public static final int MAX_ALARMS=25000;
/**
* The time interval (seconds) between 2 updates of the
* content of the table
*/
public static final int REFRESH_TIMEINTERVAL=2;
/**
* The owner component (used to show dialog messages)
*/
private JComponent owner;
/**
* The alarms in the table
*/
private AlarmsReductionContainer items=null;
/**
* The executor to schedule the update of the table every {@link #REFRESH_TIMEINTERVAL}
* msecs.
*/
private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
/**
* If <code>true</code> applies the reduction rules hiding reduced alarms
*/
private boolean applyReductionRules;
/**
* This boolean <code>addInactiveAlarms</code> says if the model has to add inactive alarms if
* they are not already in the table.
* <P>
* Normally there is no need to need to add an inactive alarm to the model
* unless we wish to change its state (i.e. we want to replace an active the alarm
* with a terminate alarm).
* However, when we want to show the table for the reductions in the
* apposite dialog then we want to see the dependencies also for inactive alarms.
*/
private final boolean addInactiveAlarms;
/**
* The auto acknowledge level
*/
private volatile ComboBoxValues autoAckLvl = ComboBoxValues.NONE ;
public int getRowCount() {
return items.size(applyReductionRules);
}
public int getColumnCount() {
return AlarmTableColumn.values().length;
}
/**
* Return the alarm shown at the rowIndex row of the table.
*
* @param rowIndex The index of the alarm in the model
* @return the alarm shown at the rowIndex row of the table
*/
public AlarmTableEntry getAlarmAt(int rowIndex) {
return items.get(rowIndex,applyReductionRules);
}
/**
* Return the text to display in a cell as it is read by the alarm
* without any formatting (the table add some formatting for
* example the color)
*
* @param rowIndex The row of the cell
* @param columnIndex The col of the cell
* @return The string to display in the cell
*/
public Object getCellContent(int rowIndex, int columnIndex) {
AlarmTableEntry alarm=getAlarmAt(rowIndex);
AlarmTableColumn col = AlarmTableColumn.values()[columnIndex];
switch (col) {
case TIME: {
synchronized (dateFormat) {
return dateFormat.format(alarm.getStatus().getSourceTimestamp());
}
}
case COMPONENT: {
return alarm.getTriplet().getFaultMember();
}
case CODE: {
return alarm.getTriplet().getFaultCode();
}
case PRIORITY: {
int priority = alarm.getPriority().intValue();
return new Priority(priority,alarm.getAlarmType());
}
case DESCRIPTION: {
return alarm.getProblemDescription();
}
case CAUSE: {
return alarm.getCause();
}
case ACTION: {
return alarm.getAction();
}
case CONSEQUENCE: {
return alarm.getConsequence();
}
case GSM: {
return alarm.getResponsiblePerson().getGsmNumber();
}
case CONTACT: {
return alarm.getResponsiblePerson().getFirstName();
}
case EMAIL: {
return alarm.getResponsiblePerson().getEMail();
}
case URL: {
return alarm.getHelpURL();
}
case TRIPLET: {
return "["+alarm.getTriplet().getFaultFamily()+", "+alarm.getTriplet().getFaultMember()+", "+alarm.getTriplet().getFaultCode()+"]";
}
case FAMILY: {
return alarm.getTriplet().getFaultFamily();
}
default: {
return "N/A";
}
}
}
/**
* Set the auto acknowledge level
* i.e. All the inactive alarms having a level equal or lower
* the the passed level automatically disappear from the table
* (i.e. with no user intervention)
*
* @param lvl The new auto acknowledge level
*/
public void setAutoAckLevel(ComboBoxValues lvl) {
if (lvl==null) {
throw new IllegalArgumentException("The level can't be null");
}
autoAckLvl=lvl;
// Remove from the model al lthe alarms whose priority is equal
// or lower then the passed level.
if (lvl!=ComboBoxValues.NONE) {
autoAckAlarms(lvl.guiType);
}
}
/**
* @see javax.swing.table.AbstractTableModel
*/
public Object getValueAt(int rowIndex, int columnIndex) {
return getCellContent(rowIndex, columnIndex);
}
@Override
public String getColumnName(int col) {
return AlarmTableColumn.values()[col].title;
}
/**
* The model needs to know that class of the PRIORITY
* column in order to sort by priority (otherwise
* the table sorts for the displayed string).
*
* @see javax.swing.table.AbstractTableModel#getColumnClass(int)
*/
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex==AlarmTableColumn.PRIORITY.ordinal()) {
return Priority.class;
}
return super.getColumnClass(columnIndex);
}
/**
* Return the alarm whose content fills the given row
*
* @param row The number of the row showing the alarm
* @return The alarm shown in the row
*/
public AlarmTableEntry getRowAlarm(int row) {
return getRowEntry(row);
}
/**
* Return the entry the given row
*
* @param row The number of the row showing the alarm
* @return The entry
*/
public AlarmTableEntry getRowEntry(int row) {
return items.get(row,applyReductionRules);
}
/**
*
* @param row Return true if the alarm is new
*/
public boolean isRowAlarmNew(int row) {
return items.get(row,applyReductionRules).isNew();
}
/**
* Return the counter for the given alarm type
*
* @param type The type of the alarm
* @return The counter for the alarm type
*/
public AtomicInteger getAlarmCounter(AlarmGUIType type) {
if (type==null) {
throw new IllegalArgumentException("The alarm type can't be null");
}
return counters.get(type);
}
/**
* The user pressed one mouse button over a row
*/
public void alarmSelected(final int row) {
items.get(row,applyReductionRules).alarmSeen();
EDTExecutor.instance().execute(new Runnable() {
@Override
public void run() {
fireTableRowsUpdated(row, row);
}
});
}
/**
* Remove all the inactive alarms of a given type
* delegating to the AlarmsContainer.
* If the type is <code>INACTIVE</code> all inactive alarms are deleted
* regardless of their priority
*
* @param type The type of the inactive alarms
*
* @see AlarmsContainer.removeInactiveAlarms
*/
public synchronized void removeInactiveAlarms(AlarmGUIType type) {
if (type==null) {
throw new IllegalArgumentException("The type can't be null");
}
int removed=0;
try {
removed=items.removeInactiveAlarms(type);
} catch (Exception e) {
System.out.println("Error removing inactive alarms "+e.getMessage());
e.printStackTrace(System.err);
}
if (removed>0) {
for (int t=0; t<removed; t++) {
counters.get(AlarmGUIType.INACTIVE).decrementAndGet();
}
EDTExecutor.instance().execute(new Runnable() {
@Override
public void run() {
fireTableDataChanged();
}
});
}
}
/**
* Auto-acknowledge the terminated alarms is priority is equal or lower then the
* passed priority.
* <P>
* This method delegates to {@link #removeInactiveAlarms(AlarmGUIType)} but it is
* called for each priority equal or lower then the passed priority.
*
* @param priority
* @return
*/
public synchronized void autoAckAlarms(AlarmGUIType type) {
if (type==null) {
throw new IllegalArgumentException("The type can't be null");
}
if (type==AlarmGUIType.PRIORITY_0 || type==AlarmGUIType.INACTIVE) {
throw new IllegalArgumentException("Invalid alarm type to auto-acknowledge: "+type);
}
for (int t=type.ordinal(); t<=AlarmGUIType.PRIORITY_3.ordinal(); t++) {
removeInactiveAlarms(AlarmGUIType.values()[t]);
}
}
/**
* Set the connection listener
*
* @param listener The listener
*/
public void setConnectionListener(ConnectionListener listener) {
connectionListener=listener;
}
/**
* Enable/disable the applying of reduction rules in the table.
* <P>
* by applying reduction rules, the table will not show reduced alarms.
*
* @param reduce if <code>true</code> apply the reduction rules hiding reduced alarms;
* if <code>reduce</code> is <code>false</code> all the alarms are shown
* by the table independently of the reduction rules
*/
public void applyReductions(boolean reduce) {
applyReductionRules=reduce;
EDTExecutor.instance().execute(new Runnable() {
@Override
public void run() {
fireTableDataChanged();
}
});
}
/**
* Set the <code>CategoryClient</code> in the <code>AlarmsContainer</code>
*
* @param client The <code>CategoryCLient</code>; it can be <code>null</code>.
*/
public void setCategoryClient(AlarmCategoryClient client) {
items.setCategoryClient(client);
}
/**
* Get the <code>CategoryClient</code> from the <code>AlarmsContainer</code>
*
* @param client The <code>CategoryCLient</code>; it can be <code>null</code>.
*/
public AlarmCategoryClient getCategoryClient() {
return items.getCategoryClient();
}
/**
* Clear the content of the model
*/
public synchronized void clear() {
items.clear();
}
/**
* Pause/un-pause the update of the table
* <P>
* If it is paused then the alarms received in <code>onAlarm</code>
* are not added in the model but queued until the application is unpaused.
*
* @param pause if <code>true</code> no new alarms are added in the table
*/
public void pause(boolean pause) {
paused.set(pause);
}
/**
* The thread refreshes the content of the table at a fixed rate.
* It is the {@link #executor} that schedules the execution of this thread
* at {@link #REFRESH_TIMEINTERVAL} ({@value #REFRESH_TIMEINTERVAL}) msecs.
* <P>
* The thread flushes all the alarms from the {@link #alarmsToAdd} vector
* in the table before firing the event to refresh the content of the table.
*/
@Override
public void run() {
// Nothing to do if the user pressed the pause button or there are
// now new alarms
if (paused.get() || alarmsToAdd.isEmpty()) {
return;
}
// The alarms to add/update in the table
AlarmTableEntry[] alarms;
synchronized (alarmsToAdd) {
alarms=new AlarmTableEntry[alarmsToAdd.size()];
alarmsToAdd.values().toArray(alarms);
alarmsToAdd.clear();
}
EDTExecutor.instance().execute(new Runnable() {
public void run() {
for (int t=0; t<alarms.length && !terminateThread.get(); t++) {
AlarmTableEntry alarm=alarms[t];
if (items.contains(alarm.getAlarmId())) {
replaceAlarm(alarm);
} else {
synchronized (items) {
// Enough room for the new alarm? If not remove the oldest
if (items.size(applyReductionRules)==MAX_ALARMS) {
AlarmTableEntry removedAlarm=null;
try {
removedAlarm = items.removeOldest(); // Remove the last one
} catch (Exception e) {
System.err.println("Error removing the oldest alarm: "+e.getMessage());
e.printStackTrace(System.err);
return;
}
counters.get(removedAlarm.getAlarmType()).decrementAndGet();
}
addAlarm(alarm);
}
}
}
fireTableDataChanged();
}
});
// Debug messages: enable to investigate reductions
// System.out.println("Adding "+alarm.getIdentifier());
// System.out.println("\tMultiplicity parent: "+alarm.isMultiplicityParent());
// System.out.println("\tMultiplicity child: "+alarm.isMultiplicityChild());
// System.out.println("\tNode parent: "+alarm.isNodeParent());
// System.out.println("\tNodechild: "+alarm.isNodeChild());
// System.out.println("Status:");
// System.out.println("\t\tMasked: "+alarm.getStatus().isMasked());
// System.out.println("\t\tReduced: "+alarm.getStatus().isReduced());
// System.out.println("\t\tActive: "+alarm.getStatus().isActive());
}
/**
* Start the thread.
*
*/
public void start() {
// Ask the executor to schedule the update of the table
executor.scheduleWithFixedDelay(this, 1, REFRESH_TIMEINTERVAL, TimeUnit.SECONDS);
}
/**
* Terminate the thread and free the resources.
*/
public void close() {
executor.shutdownNow();
terminateThread.set(true);
}
/**
* Check if the container has alarm not yet acknowledged.
*
* @return -1 if there are not alarm to acknowledge;
* the highest priority of the alarm to acknowledge
* @see alma.acsplugins.alarmsystem.gui.table.AlarmsContainer#hasNotAckAlarms()
*/
public int hasNotAckAlarms() {
try {
return items.hasNotAckAlarms(applyReductionRules);
} catch (Throwable t) {
System.err.println("Error getting the highest priority of the alarms to ACK from the conatainer:"+t.getMessage());
t.printStackTrace();
return -1;
}
}
}