/* * Copyright (C) 2011 Laurent Caillette * * This program 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 3 of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.novelang.outfit.shell; import java.lang.reflect.UndeclaredThrowableException; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import org.novelang.logger.Logger; import org.novelang.logger.LoggerFactory; import org.novelang.outfit.shell.insider.Insider; /** * Calls {@link org.novelang.outfit.shell.insider.Insider#keepAlive()} at repeated intervals * until {@link #stop()}. * * @author Laurent Caillette */ /*package*/ class HeartbeatSender { private static final Logger LOGGER = LoggerFactory.getLogger( HeartbeatSender.class ) ; private final Thread thread ; public HeartbeatSender( final Insider insider, final Notifiee notifiee, final String processNickname ) { this( insider, notifiee, processNickname, Insider.HEARTBEAT_FATAL_DELAY_MILLISECONDS / 10L ) ; } @SuppressWarnings( { "CallToThreadStartDuringObjectConstruction" } ) public HeartbeatSender( final Insider insider, final Notifiee notifiee, final String processNickname, final long heartbeatPeriodMilliseconds ) { checkNotNull( insider ) ; checkArgument( heartbeatPeriodMilliseconds > 0L ) ; LOGGER.debug( "Initializing for ", processNickname, " with a heartbeat period of ", heartbeatPeriodMilliseconds, " milliseconds..." ) ; final Runnable runnable = new Runnable() { @Override public void run() { /* LOG.info( "Running " + Thread.currentThread().getName() + "for " + processNickname + " with a heartbeat of " + heartbeatPeriodMilliseconds + " milliseconds..." ) ; */ while( true ) { try { Thread.sleep( heartbeatPeriodMilliseconds ) ; } catch( InterruptedException e ) { break; } if( Thread.currentThread().isInterrupted() ) { // Exit from the loop if thread interruption occured while we're not sleeping. break ; } try { insider.keepAlive(); } catch( UndeclaredThrowableException e ) { /* if( e.getCause() instanceof ConnectException ) { LOG.debug( "Could not send heartbeat to " + processNickname + "." ); } else { LOG.error( "Could not send heartbeat to " + processNickname + ".", e ); } */ break ; } } notifiee.onUnreachableProcess() ; } } ; thread = new Thread( runnable, "Heartbeat-" + processNickname ) ; thread.setDaemon( true ) ; thread.start() ; } public void stop() { if( thread.isInterrupted() ) { throw new IllegalStateException( "Thread already interrupted" ) ; } thread.interrupt() ; } public interface Notifiee { void onUnreachableProcess() ; } }