001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.components;
004:
005: import fitnesse.responders.run.*;
006:
007: public class CommandRunningFitClient extends FitClient implements
008: SocketSeeker {
009: public static int TIMEOUT = 60000;
010: private static final String SPACE = " ";
011:
012: private int ticketNumber;
013: public CommandRunner commandRunner;
014: private SocketDoner donor;
015: private boolean connectionEstablished = false;
016:
017: private Thread timeoutThread;
018: private Thread earlyTerminationThread;
019:
020: public CommandRunningFitClient(FitClientListener listener,
021: String command, int port, SocketDealer dealer)
022: throws Exception {
023: super (listener);
024: ticketNumber = dealer.seekingSocket(this );
025: String hostName = java.net.InetAddress.getLocalHost()
026: .getHostName();
027: commandRunner = new CommandRunner(command + SPACE + hostName
028: + SPACE + port + SPACE + ticketNumber, "");
029: }
030:
031: public void start() throws Exception {
032: try {
033: commandRunner.start();
034:
035: timeoutThread = new Thread(new TimeoutRunnable(),
036: "FitClient timeout");
037: timeoutThread.start();
038: earlyTerminationThread = new Thread(
039: new EarlyTerminationRunnable(),
040: "FitClient early termination");
041: earlyTerminationThread.start();
042: waitForConnection();
043: } catch (Exception e) {
044: listener.exceptionOccurred(e);
045: }
046: }
047:
048: public void acceptSocketFrom(SocketDoner donor) throws Exception {
049: this .donor = donor;
050: acceptSocket(donor.donateSocket());
051: connectionEstablished = true;
052:
053: synchronized (this ) {
054: notify();
055: }
056: }
057:
058: void setTicketNumber(int ticketNumber) {
059: this .ticketNumber = ticketNumber;
060: }
061:
062: public boolean isSuccessfullyStarted() {
063: return fitSocket != null;
064: }
065:
066: private void waitForConnection() throws InterruptedException {
067: while (fitSocket == null) {
068: Thread.sleep(100);
069: checkForPulse();
070: }
071: }
072:
073: public void join() throws Exception {
074: try {
075: commandRunner.join();
076: super .join();
077: if (donor != null)
078: donor.finishedWithSocket();
079: killVigilantThreads();
080: } catch (InterruptedException e) {
081: }
082: }
083:
084: public void kill() throws Exception {
085: super .kill();
086: killVigilantThreads();
087: commandRunner.kill();
088: }
089:
090: private void killVigilantThreads() {
091: if (timeoutThread != null)
092: timeoutThread.interrupt();
093: if (earlyTerminationThread != null)
094: earlyTerminationThread.interrupt();
095: }
096:
097: public void exceptionOccurred(Exception e) {
098: commandRunner.exceptionOccurred(e);
099: super .exceptionOccurred(e);
100: }
101:
102: private class TimeoutRunnable implements Runnable {
103: long timeSlept = 0;
104:
105: public void run() {
106: try {
107: Thread.sleep(TIMEOUT);
108: synchronized (CommandRunningFitClient.this ) {
109: if (fitSocket == null) {
110: CommandRunningFitClient.this .notify();
111: listener
112: .exceptionOccurred(new Exception(
113: "FitClient: communication socket was not received on time."));
114: }
115: }
116: } catch (InterruptedException e) {
117: // ok
118: }
119: }
120: }
121:
122: private class EarlyTerminationRunnable implements Runnable {
123: public void run() {
124: try {
125: commandRunner.process.waitFor();
126: synchronized (CommandRunningFitClient.this ) {
127: if (!connectionEstablished) {
128: CommandRunningFitClient.this .notify();
129: listener
130: .exceptionOccurred(new Exception(
131: "FitClient: external process terminated before a connection could be established."));
132: }
133: }
134: } catch (InterruptedException e) {
135: // ok
136: }
137: }
138: }
139: }
|