/* * Copyright 2007 Wishnu Prasetya. * * This file is part of T2. * T2 is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License (GPL) as published by the * Free Software Foundation; either version 3 of the License, or any * later version. * * T2 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. * * A copy of the GNU General Public License can be found in T2 distribution. * If it is missing, see http://www.gnu.org/licenses. */ package Sequenic.T2.Engines; import java.io.*; /** * This is an abstract class for an 'engine' (just a fancy name for 'program') * that can be run with a time out. When a time out is set, the engine will be * run on its own separate thread. Upon time-out this thread is 'terminated'. * Furthermore, exception (actually "Error") thrown in the engine's thread * will be passed on to the main thread for possible reporting. * *

Currently our approach to terminate the engine's thread is by using * the 'stop()' method, which is officially depracated. */ abstract public class EngineWithTimeOut implements Runnable { /** * Timeout duration. When non-negative, the engine will be started in a * separate thread, which will be killed after the specified time-out * duration. If the duration is negative, then no time-out is set. * *

The default is = 20.000 ms (20 seconds). */ public int timeOutPeriod = 20000; /** * This is a reference to the 'main' thread that create the engine, so that * the main thread can be awaken from its sleep if the engine finishes * before the time-out. */ public Thread mainThread = null; /** * This is used to save error thrown when the engine is run on a separate thread. */ public Error errorThrownInEngineSeparateThread = null; /** * An ouput-stream to send messages to. The default is just System.out. */ public PrintStream out = System.out; /** * This is the method that should implement the engine's main loop. * Normally this method should deal with the ThreadDeath exception * which is thrown when the engine is killed. */ abstract public void mainloop(); /** * This just wrap the mainloop {@link mainloop} in the run method so that we * can latter run it in a separate thread, so that we can kill it after * timeout. */ public void run() { errorThrownInEngineSeparateThread = null ; try { mainloop(); } catch (Error e) { errorThrownInEngineSeparateThread = e; //println(">>>1 " + errorThrownInEngineSeparateThread) ; } finally { // end of main loop, re-awaken the main thread, if one is set: if (mainThread != null) { mainThread.interrupt(); } } } /** * This will run the {@link mainloop} in a separate thread. * Timeout, if set, will be engaged. */ public void timedRun() { if (timeOutPeriod <= 0) { // No time-out is set. Just run and return: run(); return; } // Else, when time-out is set: mainThread = Thread.currentThread(); Thread E_thread = new Thread(this); boolean timeOutExpire = false ; // run the engine main loop in a separate thread, then wait // for the specified time: E_thread.start(); try { Thread.sleep(timeOutPeriod); timeOutExpire = true ; // Time-out has expired; kill the engine: E_thread.stop(); } catch (InterruptedException e) { } finally { // Wait a bit until the engine's thread dies: try { E_thread.join() ; } catch (Exception e) { } } //println(".........") ; //println(">>>2 " + errorThrownInEngineSeparateThread) ; // re-throwing exception that possibly thrown by the engine: if (timeOutExpire) { println("!! A time-out of "+ timeOutPeriod + " ms may have killed the engine..."); } if (errorThrownInEngineSeparateThread != null) { //println(">>>3 " + errorThrownInEngineSeparateThread) ; if (! (errorThrownInEngineSeparateThread instanceof ThreadDeath)) throw errorThrownInEngineSeparateThread; } } /** * Just a help method. */ void println(String s) { out.println(s); } }