/*
* StreamCruncher: Copyright (c) 2006-2008, Ashwin Jayaprakash. All Rights Reserved.
* Contact: ashwin {dot} jayaprakash {at} gmail {dot} com
* Web: http://www.StreamCruncher.com
*
* This file is part of StreamCruncher.
*
* StreamCruncher 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.
*
* StreamCruncher 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 StreamCruncher. If not, see <http://www.gnu.org/licenses/>.
*/
package streamcruncher.util;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import streamcruncher.boot.Registry;
/*
* Author: Ashwin Jayaprakash Date: Jan 16, 2006 Time: 10:22:48 PM
*/
public abstract class ManagedJob implements UncaughtExceptionHandler {
public static final long STOP_JOB_WAIT_MSECS_BEFORE_INTERRUPT = 10000;
protected final ThreadFactory threadFactory;
protected final boolean restartOnException;
protected volatile Thread currentThread;
/**
* Restarts on Exception.
*
* @param threadFactory
* @see #ManagedJob(ThreadFactory, boolean)
*/
public ManagedJob(ThreadFactory threadFactory) {
this(threadFactory, true);
}
/**
* @param threadFactory
* @param restartOnException
*/
public ManagedJob(ThreadFactory threadFactory, boolean restartOnException) {
this.threadFactory = threadFactory;
this.restartOnException = restartOnException;
}
// -----------------------
public void startJob() {
Runnable runnable = new Runnable() {
public void run() {
ManagedJob.this.performJob();
}
};
currentThread = threadFactory.newThread(runnable);
currentThread.setUncaughtExceptionHandler(this);
currentThread.start();
}
protected abstract void performJob();
/**
* <b>Note:</b> Must return immediately.
*/
protected abstract void requestStop();
/**
* Invokes {@link #requestStop()} and waits for
* {@link #STOP_JOB_WAIT_MSECS_BEFORE_INTERRUPT} before interrupting the
* Thread.
*
* @throws InterruptedException
*/
public void stopJob() throws InterruptedException {
requestStop();
while (currentThread != null && currentThread.isAlive()) {
currentThread.join(STOP_JOB_WAIT_MSECS_BEFORE_INTERRUPT);
requestStop();
try {
currentThread.interrupt();
}
catch (RuntimeException e) {
Logger logger = Registry.getImplFor(LoggerManager.class).getLogger(
ManagedJob.class.getName());
logger.log(Level.SEVERE, "Job interruption failed", e);
}
}
}
// -----------------------
public void uncaughtException(Thread thread, Throwable throwable) {
Logger logger = Registry.getImplFor(LoggerManager.class).getLogger(
ManagedJob.class.getName());
logger.log(Level.SEVERE, "Thread death: " + thread.getName(), throwable);
// -----------------------
currentThread = null;
if (restartOnException) {
startJob();
}
}
}