blob: 6e7ebb1c15ea2dfa4c1c8a6e3d9067ed7c5312da [file] [log] [blame]
package org.eclipse.debug.internal.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IStreamListener;
import org.eclipse.debug.core.model.IStreamMonitor;
/**
* Monitors the output stream of a system process and notifies
* listeners of additions to the stream.
*
* The output stream monitor reads system out (or err) via
* and input stream.
*/
public class OutputStreamMonitor implements IStreamMonitor {
/**
* The stream being monitored (connected system out or err).
*/
private InputStream fStream;
/**
* A collection of listeners
*/
private ListenerList fListeners= new ListenerList(1);
/**
* The local copy of the stream contents
*/
private StringBuffer fContents;
/**
* The thread which reads from the stream
*/
private Thread fThread;
/**
* The size of the read buffer
*/
private static final int BUFFER_SIZE= 8192;
/**
* Whether or not this monitor has been killed.
* When the monitor is killed, it stops reading
* from the stream immediately.
*/
private boolean fKilled= false;
/**
* Creates an output stream monitor on the
* given stream (connected to system out or err).
*/
public OutputStreamMonitor(InputStream stream) {
fStream= stream;
fContents= new StringBuffer();
}
/**
* @see IStreamMonitor#addListener(IStreamListener)
*/
public void addListener(IStreamListener listener) {
fListeners.add(listener);
}
/**
* Causes the monitor to close all
* communications between it and the
* underlying stream by waiting for the thread to terminate.
*/
protected void close() {
if (fThread != null) {
Thread thread= fThread;
fThread= null;
try {
thread.join();
} catch (InterruptedException ie) {
}
fListeners.removeAll();
}
}
/**
* Notifies the listeners that text has
* been appended to the stream.
*/
private void fireStreamAppended(String text) {
if (text == null)
return;
Object[] copiedListeners= fListeners.getListeners();
for (int i= 0; i < copiedListeners.length; i++) {
((IStreamListener) copiedListeners[i]).streamAppended(text, this);
}
}
/**
* @see IStreamMonitor#getContents()
*/
public String getContents() {
return fContents.toString();
}
/**
* Continually reads from the stream.
* <p>
* This method, along with the <code>startReading</code>
* method is used to allow <code>OutputStreamMonitor</code>
* to implement <code>Runnable</code> without publicly
* exposing a <code>run</code> method.
*/
private void read() {
byte[] bytes= new byte[BUFFER_SIZE];
int read = 0;
while (read >= 0) {
try {
if (fKilled) {
break;
}
read= fStream.read(bytes);
if (read > 0) {
String text= new String(bytes, 0, read);
fContents.append(text);
fireStreamAppended(text);
}
} catch (IOException ioe) {
DebugPlugin.log(ioe);
return;
} catch (NullPointerException e) {
// killing the stream monitor while reading can cause an NPE
// when reading from the stream
if (!fKilled || fThread != null) {
DebugPlugin.log(e);
}
return;
}
}
try {
fStream.close();
} catch (IOException e) {
DebugPlugin.log(e);
}
}
protected void kill() {
fKilled= true;
}
/**
* @see IStreamMonitor#removeListener(IStreamListener)
*/
public void removeListener(IStreamListener listener) {
fListeners.remove(listener);
}
/**
* Starts a thread which reads from the stream
*/
protected void startMonitoring() {
if (fThread == null) {
fThread= new Thread(new Runnable() {
public void run() {
read();
}
}, DebugCoreMessages.getString("OutputStreamMonitor.label")); //$NON-NLS-1$
fThread.start();
}
}
}