/* * @@COPYRIGHT@@ */ package com.cosylab.acs.maci.manager; import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import com.cosylab.acs.maci.ClientInfo; import com.cosylab.acs.maci.HandleHelper; import com.cosylab.acs.maci.RemoteTimeoutException; import com.cosylab.acs.maci.RemoteTransientException; import alma.acs.alarmsystem.source.AlarmSource; import alma.alarmsystem.source.ACSFaultState; /** * Implementation of ping task executed by <code>java.util.Timer</class>. * * Manager pings its clients (both GUI clients, as well as Containers) repeatedly to verify that they still exist. * The return value of <code>Client#ping()</code> can be either "true", indicating that everything is OK with the client, * or "false", indicating that client is malfunctioning. * * If <code>RemoteTransientException</code> or <code>RemoteTimeoutException</code> exception is thrown, the Manager should retry the ping several times, * and only then shall the client be assumed to be malfunctioning. * If another exception is thrown, the client may be immediately assumed to be malfunctioning. * Once the client is found to be malfunctioning, the Manager makes an implicit logout of the client. * * @author Matej Sekoranja (matej.sekoranja@cosylab.com) * @version @@VERSION@@ */ public class PingTimerTask extends TimerTask { /** * Maximum number of consequential code>RemoteTransientException</code> * exception catches logging the client out. */ private static final int MAX_TRANSIENT_COUNT = 3; /** * Counter for consequential <code>RemoteTransientException</code> * exception catches to <code>Client#ping</code> method. */ private int transientCount; /** * Manager to which the client is logged in. */ private ManagerImpl manager; /** * Monitored client's info. */ private ClientInfo clientInfo; /** * Logger. */ private Logger logger; /** * Alarm System Interface. */ private AlarmSource alarmSource; /** * Constructs a ping task which monitors client's state. * @param manager manager to which the client is logged in * @param logger logger. * @param clientInfo info of the client to be monitored * @param alarmSource interface to send alarms * @param activeAlarm set of active alarms */ public PingTimerTask(ManagerImpl manager, Logger logger, ClientInfo clientInfo, AlarmSource alarmSource) { super(); assert (manager != null); assert (logger != null); assert (clientInfo != null); this.manager = manager; this.logger = logger; this.clientInfo = clientInfo; this.alarmSource = alarmSource; this.transientCount = 0; } /** * Terminates this task and logs the client out. */ private void logout() { // do not throw any exceptions here... try { // cancel this task cancel(); // and logout manager.logout(clientInfo.getHandle()); } catch (Throwable th) { // noop } } /** * @see java.lang.Runnable#run() */ public void run() { try { logger.finest("Invoking ping on "+HandleHelper.toString(clientInfo.getHandle())+"]."); // malfunctioning client check if (clientInfo.getClient().ping() == false) { logger.info("Client '"+clientInfo.getName()+"' ["+HandleHelper.toString(clientInfo.getHandle())+"] announced itself as malfunctioning."); // An alarm is raised for those clients that define an alarm interface raise_alarm(clientInfo.getName()); logout(); } // reset alarm state, if neccesary clear_alarm(clientInfo.getName()); // reset transientCount to zero transientCount = 0; } catch (RemoteTransientException rte) { //logger.log(Level.INFO, "Invoking client '"+clientInfo.getName()+"' ["+HandleHelper.toString(clientInfo.getHandle())+"] ping method thrown transient exception.", rte); // client not reachable transientCount++; if (transientCount >= MAX_TRANSIENT_COUNT) { logger.info("Client '"+clientInfo.getName()+"' ["+HandleHelper.toString(clientInfo.getHandle())+"] is unreachable, logging it out."); // An alarm is raised for those clients that define an alarm interface raise_alarm(clientInfo.getName()); logout(); } } catch (RemoteTimeoutException rtoe) { //logger.log(Level.INFO, "Invoking client '"+clientInfo.getName()+"' ["+HandleHelper.toString(clientInfo.getHandle())+"] ping method thrown timeout exception.", rtoe); // client not reachable transientCount++; if (transientCount >= MAX_TRANSIENT_COUNT) { logger.info("Client '"+clientInfo.getName()+"' ["+HandleHelper.toString(clientInfo.getHandle())+"] ping method timed-out several times, logging it out."); // An alarm is raised for those clients that define an alarm interface raise_alarm(clientInfo.getName()); logout(); } } catch (Throwable ex) { logger.log(Level.INFO, "Invoking client '"+clientInfo.getName()+"' ping method thrown an exception, logging it out.", ex); //logger.info("Invoking client '"+clientInfo.getName()+"' ping method threw an unknown exception, logging it out."); // An alarm is raised for those clients that define an alarm interface raise_alarm(clientInfo.getName()); // malfunctioning client logout(); } } /** * Returns a single-line rendition of this instance into text. * * @return internal state of this instance */ public String toString() { StringBuffer sbuff = new StringBuffer(); sbuff.append("PingTimerTask = { "); sbuff.append("manager = '"); sbuff.append(manager); sbuff.append(", clientInfo = '"); sbuff.append(clientInfo); sbuff.append(", transientCount = '"); sbuff.append(transientCount); sbuff.append("' }"); return new String(sbuff); } // ALARM SYSTEM codes protected final static String FAULT_FAMILY = "Manager"; protected final static int FAULT_CODE = 1; /** * Raise alarm. * * @param faultMember */ private void raise_alarm(String faultMember) { if (!manager.hasActiveAlarm(clientInfo.getName())) send_alarm(faultMember, true); } /** * Clear alarm. * * @param faultMember */ private void clear_alarm(String faultMember) { if (manager.hasActiveAlarm(clientInfo.getName())) send_alarm(faultMember, false); } /** * Convenience method for send_alarm with given state. * * @param faultMember * @param state */ private void send_alarm(String faultMember, boolean raise) { // if no alarm system initialized ignore if (alarmSource == null) { return; } try { alarmSource.setAlarm(FAULT_FAMILY, faultMember, FAULT_CODE, raise); // save alarm state if (raise) { manager.alarmRaised(faultMember); } else { manager.alarmCleared(faultMember); } } catch (Throwable th) { // do nothing, alarm did not work } } }