Package fitnesse.testsystems.fit

Source Code of fitnesse.testsystems.fit.FitClient

// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.testsystems.fit;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import fit.Counts;
import fit.FitProtocol;
import fitnesse.testsystems.TestSummary;
import util.StreamReader;

public class FitClient implements SocketAccepter {
  private static final Logger LOG = Logger.getLogger(FitClient.class.getName());

  private List<FitClientListener> listeners;
  private Socket fitSocket;
  private OutputStream fitInput;
  private StreamReader fitOutput;

  private volatile int sent = 0;
  private volatile int received = 0;
  private volatile boolean isDoneSending = false;
  private volatile boolean killed = false;
  private Thread fitListeningThread;

  public FitClient() {
    this.listeners = new LinkedList<FitClientListener>();
  }

  public void addFitClientListener(FitClientListener listener) {
    listeners.add(listener);
  }

  public synchronized void acceptSocket(Socket socket) throws IOException, InterruptedException {
    checkForPulse();
    fitSocket = socket;
    fitInput = fitSocket.getOutputStream();
    FitProtocol.writeData("", fitInput);
    fitOutput = new StreamReader(fitSocket.getInputStream());

    fitListeningThread = new Thread(new FitListeningRunnable(), "FitClient fitOutput");
    fitListeningThread.start();
  }

  public void send(String data) throws IOException, InterruptedException {
    checkForPulse();
    FitProtocol.writeData(data, fitInput);
    sent++;
  }

  public void done() throws IOException, InterruptedException {
    checkForPulse();
    FitProtocol.writeSize(0, fitInput);
    isDoneSending = true;
  }

  public void join() {
    if (fitListeningThread != null)
      try {
        fitListeningThread.join();
      } catch (InterruptedException e) {
        LOG.log(Level.FINE, "Wait for join of listening thread interrupted", e);
      }
  }

  public void kill() {
    killed = true;
    if (fitListeningThread != null)
      fitListeningThread.interrupt();
  }

  public synchronized boolean isSuccessfullyStarted() {
    return fitSocket != null;
  }

  protected void checkForPulse() throws InterruptedException {
    if (killed)
      throw new InterruptedException("FitClient was killed");
  }

  private boolean finishedReading() {
    while (stateIndeterminate())
      shortSleep();
    return isDoneSending && received == sent;
  }

  /**
   * @return true if the current state of the transission is indeterminate.
   *         <p/>
   *         When the number of pages sent and recieved is the same, we may be done with the whole job, or we may just
   *         be waiting for FitNesse to send the next page. There's no way to know until FitNesse either calls send, or
   *         done.
   */
  private boolean stateIndeterminate() {
    return (received == sent) && !isDoneSending;
  }

  private void shortSleep() {
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      LOG.log(Level.FINE, "sleep interrupted", e);
    }
  }

  public void exceptionOccurred(Throwable e) {
    for (FitClientListener listener : listeners)
      listener.exceptionOccurred(e);
  }

  private class FitListeningRunnable implements Runnable {
    public void run() {
      listenToFit();
    }


    private void listenToFit() {
      try {
        attemptToListenToFit();
      } catch (Exception e) {
        exceptionOccurred(e);
      }
    }

    private void attemptToListenToFit() throws IOException {
      while (!finishedReading()) {
        int size;
        size = FitProtocol.readSize(fitOutput);
        if (size != 0) {
          String readValue = fitOutput.read(size);
          if (fitOutput.byteCount() < size)
            throw new IOException("I was expecting " + size + " bytes but I only got " + fitOutput.byteCount());
          testOutputChunk(readValue);
        } else {
          Counts counts = FitProtocol.readCounts(fitOutput);
          testComplete(new TestSummary(counts.right, counts.wrong, counts.ignores, counts.exceptions));
          received++;
        }
      }
    }

    private void testComplete(TestSummary summary) throws IOException {
      for (FitClientListener listener : listeners)
        listener.testComplete(summary);
    }

    private void testOutputChunk(String value) throws IOException {
      for (FitClientListener listener : listeners)
        listener.testOutputChunk(value);
    }
  }

}
TOP

Related Classes of fitnesse.testsystems.fit.FitClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.