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:
011: private int ticketNumber;
012:
013: public CommandRunner commandRunner;
014:
015: private SocketDoner doner;
016:
017: public boolean connectionEstablished = false;
018:
019: private Thread timeoutThread;
020:
021: private Thread earlyTerminationThread;
022:
023: public CommandRunningFitClient(FitClientListener listener,
024: String command, int port, SocketDealer dealer)
025: throws Exception {
026: super (listener);
027: ticketNumber = dealer.seekingSocket(this );
028: commandRunner = new CommandRunner(command + " localhost "
029: + port + " " + ticketNumber, "");
030: }
031:
032: public void start() throws Exception {
033: try {
034: commandRunner.start();
035:
036: timeoutThread = new Thread(new TimeoutRunnable(),
037: "FitClient timeout");
038: timeoutThread.start();
039: earlyTerminationThread = new Thread(
040: new EarlyTerminationRunnable(),
041: "FitClient early termination");
042: earlyTerminationThread.start();
043: waitForConnection();
044: } catch (Exception e) {
045: listener.exceptionOccurred(e);
046: }
047: }
048:
049: public void acceptSocketFrom(SocketDoner doner) throws Exception {
050: this .doner = doner;
051: acceptSocket(doner.donateSocket());
052: connectionEstablished = true;
053:
054: synchronized (this ) {
055: notify();
056: }
057: }
058:
059: void setTicketNumber(int ticketNumber) {
060: this .ticketNumber = ticketNumber;
061: }
062:
063: public boolean isSuccessfullyStarted() {
064: return fitSocket != null;
065: }
066:
067: private void waitForConnection() throws InterruptedException {
068: while (fitSocket == null) {
069: Thread.sleep(100);
070: checkForPulse();
071: }
072: }
073:
074: public void join() throws Exception {
075: try {
076: commandRunner.join();
077: super .join();
078: if (doner != null)
079: doner.finishedWithSocket();
080: killVigilantThreads();
081: } catch (InterruptedException e) {
082: }
083: }
084:
085: public void kill() throws Exception {
086: super .kill();
087: killVigilantThreads();
088: commandRunner.kill();
089: }
090:
091: private void killVigilantThreads() {
092: if (timeoutThread != null)
093: timeoutThread.interrupt();
094: if (earlyTerminationThread != null)
095: earlyTerminationThread.interrupt();
096: }
097:
098: public void exceptionOccurred(Exception e) {
099: commandRunner.exceptionOccurred(e);
100: super .exceptionOccurred(e);
101: }
102:
103: class TimeoutRunnable implements Runnable {
104: long timeSlept = 0;
105:
106: public void run() {
107: try {
108: Thread.sleep(TIMEOUT);
109: synchronized (CommandRunningFitClient.this ) {
110: if (fitSocket == null) {
111: CommandRunningFitClient.this .notify();
112: listener
113: .exceptionOccurred(new Exception(
114: "FitClient: communication socket was not received on time."));
115: }
116: }
117: } catch (InterruptedException e) {
118: // ok
119: }
120: }
121: }
122:
123: class EarlyTerminationRunnable implements Runnable {
124: public void run() {
125: try {
126: commandRunner.process.waitFor();
127: synchronized (CommandRunningFitClient.this ) {
128: if (!connectionEstablished) {
129: CommandRunningFitClient.this .notify();
130: listener
131: .exceptionOccurred(new Exception(
132: "FitClient: external process terminated before a connection could be established."));
133: }
134: }
135: } catch (InterruptedException e) {
136: // ok
137: }
138: }
139: }
140: }
|