KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > core > OutputStreamMonitor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.debug.internal.core;
12
13
14 import java.io.BufferedInputStream JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.io.InputStream JavaDoc;
17
18 import org.eclipse.core.runtime.ISafeRunnable;
19 import org.eclipse.core.runtime.ListenerList;
20 import org.eclipse.core.runtime.SafeRunner;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.IStreamListener;
23 import org.eclipse.debug.core.model.IFlushableStreamMonitor;
24
25 /**
26  * Monitors the output stream of a system process and notifies
27  * listeners of additions to the stream.
28  *
29  * The output stream monitor reads system out (or err) via
30  * and input stream.
31  */

32 public class OutputStreamMonitor implements IFlushableStreamMonitor {
33     /**
34      * The stream being monitored (connected system out or err).
35      */

36     private InputStream JavaDoc fStream;
37
38     /**
39      * A collection of listeners
40      */

41     private ListenerList fListeners= new ListenerList();
42     
43     /**
44      * Whether content is being buffered
45      */

46     private boolean fBuffered = true;
47
48     /**
49      * The local copy of the stream contents
50      */

51     private StringBuffer JavaDoc fContents;
52
53     /**
54      * The thread which reads from the stream
55      */

56     private Thread JavaDoc fThread;
57
58     /**
59      * The size of the read buffer
60      */

61     private static final int BUFFER_SIZE= 8192;
62
63     /**
64      * Whether or not this monitor has been killed.
65      * When the monitor is killed, it stops reading
66      * from the stream immediately.
67      */

68     private boolean fKilled= false;
69     
70     private long lastSleep;
71
72     private String JavaDoc fEncoding;
73     
74     /**
75      * Creates an output stream monitor on the
76      * given stream (connected to system out or err).
77      *
78      * @param stream input stream to read from
79      * @param encoding stream encoding or <code>null</code> for system default
80      */

81     public OutputStreamMonitor(InputStream JavaDoc stream, String JavaDoc encoding) {
82         fStream = new BufferedInputStream JavaDoc(stream, 8192);
83         fEncoding = encoding;
84         fContents= new StringBuffer JavaDoc();
85     }
86
87     /* (non-Javadoc)
88      * @see org.eclipse.debug.core.model.IStreamMonitor#addListener(org.eclipse.debug.core.IStreamListener)
89      */

90     public synchronized void addListener(IStreamListener listener) {
91         fListeners.add(listener);
92     }
93
94     /**
95      * Causes the monitor to close all
96      * communications between it and the
97      * underlying stream by waiting for the thread to terminate.
98      */

99     protected void close() {
100         if (fThread != null) {
101             Thread JavaDoc thread= fThread;
102             fThread= null;
103             try {
104                 thread.join();
105             } catch (InterruptedException JavaDoc ie) {
106             }
107             fListeners = new ListenerList();
108         }
109     }
110
111     /**
112      * Notifies the listeners that text has
113      * been appended to the stream.
114      */

115     private void fireStreamAppended(String JavaDoc text) {
116         getNotifier().notifyAppend(text);
117     }
118
119     /* (non-Javadoc)
120      * @see org.eclipse.debug.core.model.IStreamMonitor#getContents()
121      */

122     public synchronized String JavaDoc getContents() {
123         return fContents.toString();
124     }
125
126     /**
127      * Continually reads from the stream.
128      * <p>
129      * This method, along with the <code>startReading</code>
130      * method is used to allow <code>OutputStreamMonitor</code>
131      * to implement <code>Runnable</code> without publicly
132      * exposing a <code>run</code> method.
133      */

134     private void read() {
135         lastSleep = System.currentTimeMillis();
136         long currentTime = lastSleep;
137         byte[] bytes= new byte[BUFFER_SIZE];
138         int read = 0;
139         while (read >= 0) {
140             try {
141                 if (fKilled) {
142                     break;
143                 }
144                 read= fStream.read(bytes);
145                 if (read > 0) {
146                     String JavaDoc text;
147                     if (fEncoding != null) {
148                         text = new String JavaDoc(bytes, 0, read, fEncoding);
149                     } else {
150                         text = new String JavaDoc(bytes, 0, read);
151                     }
152                     synchronized (this) {
153                         if (isBuffered()) {
154                             fContents.append(text);
155                         }
156                         fireStreamAppended(text);
157                     }
158                 }
159             } catch (IOException JavaDoc ioe) {
160                 if (!fKilled) {
161                     DebugPlugin.log(ioe);
162                 }
163                 return;
164             } catch (NullPointerException JavaDoc e) {
165                 // killing the stream monitor while reading can cause an NPE
166
// when reading from the stream
167
if (!fKilled && fThread != null) {
168                     DebugPlugin.log(e);
169                 }
170                 return;
171             }
172             
173             currentTime = System.currentTimeMillis();
174             if (currentTime - lastSleep > 1000) {
175                 lastSleep = currentTime;
176                 try {
177                     Thread.sleep(1); // just give up CPU to maintain UI responsiveness.
178
} catch (InterruptedException JavaDoc e) {
179                 }
180             }
181         }
182         try {
183             fStream.close();
184         } catch (IOException JavaDoc e) {
185             DebugPlugin.log(e);
186         }
187     }
188     
189     protected void kill() {
190         fKilled= true;
191     }
192
193     /* (non-Javadoc)
194      * @see org.eclipse.debug.core.model.IStreamMonitor#removeListener(org.eclipse.debug.core.IStreamListener)
195      */

196     public synchronized void removeListener(IStreamListener listener) {
197         fListeners.remove(listener);
198     }
199
200     /**
201      * Starts a thread which reads from the stream
202      */

203     protected void startMonitoring() {
204         if (fThread == null) {
205             fThread= new Thread JavaDoc(new Runnable JavaDoc() {
206                 public void run() {
207                     read();
208                 }
209             }, DebugCoreMessages.OutputStreamMonitor_label);
210             fThread.setDaemon(true);
211             fThread.setPriority(Thread.MIN_PRIORITY);
212             fThread.start();
213         }
214     }
215     
216     /**
217      * @see org.eclipse.debug.core.model.IFlushableStreamMonitor#setBuffered(boolean)
218      */

219     public synchronized void setBuffered(boolean buffer) {
220         fBuffered = buffer;
221     }
222
223     /**
224      * @see org.eclipse.debug.core.model.IFlushableStreamMonitor#flushContents()
225      */

226     public synchronized void flushContents() {
227         fContents.setLength(0);
228     }
229     
230     /**
231      * @see IFlushableStreamMonitor#isBuffered()
232      */

233     public synchronized boolean isBuffered() {
234         return fBuffered;
235     }
236
237     private ContentNotifier getNotifier() {
238         return new ContentNotifier();
239     }
240     
241     class ContentNotifier implements ISafeRunnable {
242         
243         private IStreamListener fListener;
244         private String JavaDoc fText;
245         
246         /**
247          * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
248          */

249         public void handleException(Throwable JavaDoc exception) {
250             DebugPlugin.log(exception);
251         }
252
253         /**
254          * @see org.eclipse.core.runtime.ISafeRunnable#run()
255          */

256         public void run() throws Exception JavaDoc {
257             fListener.streamAppended(fText, OutputStreamMonitor.this);
258         }
259
260         public void notifyAppend(String JavaDoc text) {
261             if (text == null)
262                 return;
263             fText = text;
264             Object JavaDoc[] copiedListeners= fListeners.getListeners();
265             for (int i= 0; i < copiedListeners.length; i++) {
266                 fListener = (IStreamListener) copiedListeners[i];
267                 SafeRunner.run(this);
268             }
269             fListener = null;
270             fText = null;
271         }
272     }
273 }
274
Popular Tags