package org.jcon.test;

import org.jcon.util.DataLib;
import org.jcon.util.GenLib;

/**
 * Test best robust timeout approach, try for reusable.
 * java org.jcon.test.TestTimeout
 * <p>
 * Test shows that threads "pile up" if timeout occurs.
 * This appears to be unavoidable unless Thread.stop() is
 * used, which causes problems.
 *
 * @author Jack Harich
 */
public class TestTimeout implements Runnable {

//---------- Private Fields ------------------------------
private long      timeout = 3000;
private boolean   running;
private int       performResult;
private String    performInputData;
private Exception performException;

private static final int FAILURE = -1;

//---------- Initialization ------------------------------
/**
* Runs the test, pausing for command input. Enter "quit"
* to end the test, nothing to use current timeout, or
* enter a new timeout in milliseconds. The initial
* timeout is 3000. The task sleeps for 5000 ms before
* completing. Thus the default is the task times out.
*/
public static void main(String args[]) {
    new TestTimeout().start();    
}    
//---------- Public Methods ------------------------------
public void start() {
    // This should timeout if delayed, such as server down
    print(" ------ Starting test");
    String command = "";
    while(! command.equalsIgnoreCase("Quit")) {
        if (DataLib.isInt(command)) timeout = Integer.valueOf(command).intValue();
        
        int result = perform("TestData");
        print(" - Result = " + result + ", timeout = " + timeout);
        
        command = GenLib.readInputLine("Enter command: ");   
    }
    print(" ------ Test complete");
}
// *** May want to balk if running... to avoid further threads and probable timeouts
public int perform(String inputData) {
    // Init thread data
    performInputData = inputData;
    performException = null;
    
    // Start thread to do the work
    Thread thread = new Thread(this);
    thread.start();
    
    // Join thread when terminated or times out
    try {
        thread.join(timeout);
    } catch(InterruptedException ex) {
        ex.printStackTrace(); // Should never happen           
        return FAILURE;
    }
    // Process result
    if (thread.isAlive()) {
        // Timed out - How to safely destroy thread?????
        // ***thread.interrupt();
        running = false;
        return FAILURE; // Or throw exception
    } else if (performException != null) {
        performException.printStackTrace();
        return FAILURE;
    } else {
        // Okay
        return performResult;        
    }
}    
//---------- Runnable Implementation ---------------------
public void run() {
    running = true;
    try {
        print(" - Starting task with: " + performInputData);
        // Simulate overly long task
        Thread.currentThread().sleep(5000);
        
        // ***if (Thread.currentThread().isInterrupted()) {
        if (! running) {
            // Don't do anymore work
        } else {
            // Do more work
            performResult = 10;
        }
    } catch(Exception ex) {
        performException = ex;
    }
    print(".run() - Leave");
}    
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("TestTimeout" + text);
}

} // End class
