/* * ALMA - Atacama Large Millimiter Array (c) European Southern Observatory, 2010 * * 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.acs.alarmsystemprofiler.document.flood; import java.util.Vector; import cern.laser.client.data.Alarm; import alma.acs.alarmsystemprofiler.engine.AlarmCategoryListener; /** * An alarm flood begins when the flow of annunciated alarms if greater then 10 alarms in * 10 minutes and finish when the flow is less then 5 alarm in 10 minutes. * <P> * Objects of this class records a flood. * <P> * When the object is created, it starts a Thread to count each minute and for each * minute the important value is the number of received alarms to recognize if * a flood starts or finish. * <P> * The alarm counted in this context are the annunciated alarms i.e. * <UL> * <LI>alarms active * <LI>alarms not reduced * </UL> * @author acaproni * */ public class AlarmFlood implements Runnable, AlarmCategoryListener { /** * The alarm registered every minute * @author acaproni * */ private class AlarmPerMinute { public final long startTime; public long numOfAlarms; /** * Contructor * * @param time The start time */ public AlarmPerMinute(long time) { this.startTime=time; numOfAlarms=0; } } /** * The counter with the alarms received in the last 10 minute * <P> * The alarm of the oldest minute are int head, the newest in the tail. */ private final Vector<AlarmPerMinute> counter = new Vector<AlarmFlood.AlarmPerMinute>(10); /** * An alarm flood starts when the number of alarms per 10 minutes * is greater or equal to this value */ private static final int STARTALARMFLOOD=10; /** * An alarm flood finishes when the number of alarms per 10 minutes * is less then this value */ private static final int ENDALARMFLOOD=5; /** * The time (in millisecond) when the flood started. * <P> * This is the time of the beginning of the first minute when the flood started. * <code>startTimeOfFlood</code> signals if a flood started. */ private long startTimeOfFlood=0; /** * The time (in millisec) when the flood finished * <P> * This is the time of the beginning of the last minute when the flood finished. */ private long endTimeOfFlood=0; /** * The number of alarms in flood */ private int alarmsInFlood=0; /** * The thread */ private final Thread thread; /** * Signal the thread to terminate */ private boolean stopped=false; /** * The container that owns this object * (used to refresh the content of the table) */ private FloodContainer container; /** * Constructor * @param container The container that owns this object */ public AlarmFlood(FloodContainer container) { this.container=container; for (int t=0; t<10; t++) { counter.add(t, null); } thread=new Thread(this,"AlarmFlood"); thread.setDaemon(true); thread.start(); } /** * The counter of the actual minute */ private AlarmPerMinute actualCounter; /** * The length of a this flood in msec. * * @return The length of the flood. * It is a negative number, if a flood started but it is not yet finished */ public long lengthOfFlood() { if (endTimeOfFlood==0) { return System.currentTimeMillis()-startTimeOfFlood; } return endTimeOfFlood-startTimeOfFlood; } /** * Stop counting */ public void stop() { stopped=true; thread.interrupt(); } /** * The thread check every minute the state of the flood and * terminates when the flood finishes. */ @Override public void run() { while (!stopped) { synchronized (this) { actualCounter=new AlarmPerMinute(System.currentTimeMillis()); while (counter.size()>10) { counter.remove(0); } counter.add(actualCounter); } try { Thread.sleep(60*1000); } catch (InterruptedException ie) { continue; } // Check flood if (checkFlood()) { // The flood has finished: exit break; } } container.doneFlood(); System.out.println("Thread terminated"); } /** * Check the state of the flood * * @return <code>true</code> if the flood finished */ private synchronized boolean checkFlood() { // The alarms in the past 10 minutes int alarms=0; for (int t=0; t<10; t++) { if (counter.get(t)!=null) { System.out.println("Alarm at min "+t+": "+counter.get(t).numOfAlarms); alarms+=counter.get(t).numOfAlarms; } } System.out.println("Alarms in the last 10 minutes: "+alarms); // Check if a new flood started if (startTimeOfFlood==0) { // Flood not started if (alarms<STARTALARMFLOOD) { System.out.println("No flood started yet"); return false; } // The flood started right now // // The start time is in the first element in counter // that is not null int idx=-1; for (int t=0; t<10; t++) { if (counter.get(t)!=null) { idx=t; break; } } if (idx==-1) { // Impossible! throw new IllegalStateException("Index is -1!"); } startTimeOfFlood=counter.get(idx).startTime; endTimeOfFlood=0; alarmsInFlood=alarms; System.out.println("Flood started NOW"); return false; } // Check if the current flood just finished if (endTimeOfFlood!=0) { // The flood has already finished return false; } if (alarms>ENDALARMFLOOD) { System.out.println("No flood ended yet"); // Not yet finished return false; } // flood finished now // Get the time of the last sample AlarmPerMinute temp=null; for (int t=9; t>=0 && temp==null; t++) { temp=counter.get(t); } if (temp==null) { throw new IllegalStateException("This point should never be null!!!"); } endTimeOfFlood=temp.startTime; System.out.println("Flood finished NOW"); return true; } /** * A new alarm has been received. * * @param alarm The alarm */ @Override public synchronized void onAlarm(Alarm alarm) { if (!alarm.getStatus().isActive()) { return; } if (alarm.getStatus().isReduced()) { return; } if (!alarm.getStatus().isReduced()) { actualCounter.numOfAlarms++; } if (startTimeOfFlood>0 && endTimeOfFlood==0) { alarmsInFlood++; } } /** * Getter */ public long getStartTimeOfFlood() { return startTimeOfFlood; } /** * Getter */ public long getEndTimeOfFlood() { return endTimeOfFlood; } /** * Getter */ public int getAlarmsInFlood() { return alarmsInFlood; } /** * * @return <code>true</code> if a flood started */ public boolean isFloodStarted() { return startTimeOfFlood!=0; } /** * * @return <code>true</code> if the flood finished * A value of <code>false</code> means that a flood has not finished yet * but it could as well be that it never started. */ public boolean isFloodFinished() { return endTimeOfFlood!=0; } }