/*
* $Id: HeartbeatHelper.java,v 1.8 2011/04/13 15:45:42 acaproni Exp $
*
* $Date: 2011/04/13 15:45:42 $
* $Revision: 1.8 $
* $Author: acaproni $
*
* Copyright CERN, All Rights Reserved.
*/
package cern.laser.client.impl.services.selection;
import java.util.Timer;
import java.util.TimerTask;
import javax.jms.Message;
import org.apache.log4j.Logger;
import org.omg.CORBA.ORB;
import alma.acs.container.ContainerServicesBase;
import alma.acs.logging.AcsLogger;
import alma.alarmsystem.CERNAlarmService;
import cern.cmw.mom.pubsub.ExceptionListener;
import cern.cmw.mom.pubsub.MOMException;
import cern.cmw.mom.pubsub.PubSubFactory;
import cern.cmw.mom.pubsub.Subscriber;
import cern.cmw.mom.pubsub.SubscriptionListener;
import cern.laser.client.LaserConnectionException;
import cern.laser.client.LaserException;
import cern.laser.client.impl.common.AlarmServiceSingleton;
import cern.laser.client.services.selection.AlarmSelectionListener;
import cern.laser.client.services.selection.LaserHeartbeatException;
import cern.laser.client.services.selection.LaserSelectionException;
/**
* This class subscribes to the heartbeat from the business layer and verifies that it arrives in time. If it doesn't
* the AlarmSelectionListener is informed. It is a helper class for the AlarmSelectionHandler.
*
* @version $Revision: 1.8 $ $Date: 2011/04/13 15:45:42 $
* @author Katarina Sigerud
*/
class HeartbeatHelper implements ExceptionListener {
private static final Logger LOGGER = Logger.getLogger(HeartbeatHelper.class.getName());
private static final String HEARTBEAT_PROPERTY = "HEARTBEAT";
private static final String SQL_FILTER = "HEARTBEAT = TRUE";
private SubscriptionListener heartbeatListener = null;
private AlarmSelectionListener selectionListener = null;
private Timer timer = null;
private String heartbeatTopic = null;
private long heartbeatFrequency = -1;
private long heartbeatCheckFrequency = -1;
private boolean heartbeatReceived = false;
private long heartbeatReceptionTime = -1;
private Subscriber cmwSubscriber;
private boolean cmwConnected = true;
// The AlarmService component
private CERNAlarmService m_laser;
//
// -- CONSTRUCTORS ------------------------------------------------
//
/**
* @param sessionEJB
* @throws LaserException
* @throws LaserException
* @throws LaserConnectionException
*
*/
public HeartbeatHelper(AlarmSelectionListener selectionListener, ORB orb, AcsLogger logger) throws LaserException {
this.selectionListener = selectionListener;
try {
this.m_laser = AlarmServiceSingleton.getInstance(orb,logger);
heartbeatFrequency = m_laser.getHeartbeatFrequency();
heartbeatTopic = m_laser.getHeartbeatTopic();
heartbeatCheckFrequency = heartbeatFrequency / 2;
initHeartbeatCheck();
} catch (Exception e) {
throw new LaserException("unable to setup heartbeat check", e);
}
}
//
// -- PUBLIC METHODS ----------------------------------------------
//
public void startHeartbeatCheck() throws LaserException {
if (timer == null) {
LOGGER.info("Alarm Heartbeat client check frequency : " + heartbeatCheckFrequency + " milliseconds");
LOGGER.info("starting heartbeat check...");
timer = new Timer();
timer.schedule(createHeartbeatTimerTask(), heartbeatCheckFrequency, heartbeatCheckFrequency);
LOGGER.info("started heartbeat check");
}
}
public void stopHeartbeatCheck() throws LaserException {
if (timer != null) {
LOGGER.info("stopping heartbeat check...");
timer.cancel();
timer = null;
heartbeatTopic = null;
heartbeatFrequency = -1;
heartbeatCheckFrequency = -1;
LOGGER.info("stopped heartbeat check");
}
if (cmwSubscriber != null) {
cmwSubscriber.close();
cmwSubscriber = null;
}
}
//
// -- implements ExceptionListener ---------------------------------
//
/*
* (non-Javadoc)
*
* @see cern.cmw.mom.pubsub.ExceptionListener#onException(cern.cmw.mom.pubsub.MOMException)
*/
public void onException(MOMException e) {
if (e.testException(MOMException.CONNECTION_LOST_EXCEPTION)) {
cmwConnected = false;
if (selectionListener != null) {
selectionListener.onException(new LaserSelectionException(LaserSelectionException.CONNECTION_DROPPED));
}
} else {
if (e.testException(MOMException.CONNECTION_RECOVERED_EXCEPTION)) {
cmwConnected = true;
if (selectionListener != null) {
selectionListener.onException(new LaserSelectionException(LaserSelectionException.CONNECTION_REESTABILISHED));
}
}
}
}
//
// -- PRIVATE METHODS ---------------------------------------------
//
/**
* @throws LaserException
* @throws LaserConnectionException
*/
private void initHeartbeatCheck() throws LaserException, LaserConnectionException {
if (selectionListener != null) {
try {
setHeartbeatReceived(true);
resetHeartbeatReceptionTime();
getSubscriber().subscribe(heartbeatTopic, getHeartbeatListener(), SQL_FILTER);
} catch (Exception e1) {
new LaserException("unable to subscribe to topic " + heartbeatTopic, e1);
}
}
}
private SubscriptionListener getHeartbeatListener() {
if (heartbeatListener == null) {
heartbeatListener = new SubscriptionListener() {
public void onMessage(Message msg) {
try {
resetHeartbeatReceptionTime();
} catch (Exception e) {
LOGGER.warn("error on message in heartbeat subscription", e);
}
}
};
}
return heartbeatListener;
}
private TimerTask createHeartbeatTimerTask() {
return new TimerTask() {
public void run() {
try {
checkHeartbeat();
} catch (Exception e) {
LOGGER.error("heartbeat check failed", e);
}
}
};
}
private void checkHeartbeat() {
if (LOGGER.isDebugEnabled()) LOGGER.debug("checking heartbeat reception...");
long now = System.currentTimeMillis();
long heartbeatWaitTime = now - getHeartbeatReceptionTime();
if (heartbeatWaitTime > heartbeatFrequency) {
if (isHeartbeatReceived()) {
if (selectionListener != null) {
selectionListener.onException(new LaserHeartbeatException(LaserHeartbeatException.HEARTBEAT_LOST));
}
setHeartbeatReceived(false);
}
} else {
if (!isHeartbeatReceived()) {
if (selectionListener != null) {
selectionListener.onException(new LaserHeartbeatException(LaserHeartbeatException.HEARTBEAT_RECONNECTED));
}
setHeartbeatReceived(true);
}
}
if (LOGGER.isDebugEnabled()) LOGGER.debug("heartbeat reception checked (wait time " + heartbeatWaitTime + ")");
}
private synchronized void resetHeartbeatReceptionTime() {
heartbeatReceptionTime = System.currentTimeMillis();
}
private synchronized long getHeartbeatReceptionTime() {
return heartbeatReceptionTime;
}
private synchronized void setHeartbeatReceived(boolean value) {
heartbeatReceived = value;
}
private synchronized boolean isHeartbeatReceived() {
return heartbeatReceived;
}
private Subscriber getSubscriber() throws LaserException {
try {
if (cmwSubscriber == null) {
cmwSubscriber = PubSubFactory.subscriber();
cmwSubscriber.setExceptionListener(this);
}
} catch (Exception e) {
throw new LaserException("unable to create the CMW subscriber", e);
}
return cmwSubscriber;
}
}