3131
3232package org .scijava .console ;
3333
34+ import java .io .OutputStream ;
3435import java .io .PrintStream ;
3536import java .util .ArrayList ;
3637import java .util .LinkedList ;
3738
39+ import org .scijava .Context ;
40+ import org .scijava .console .OutputEvent .Source ;
3841import org .scijava .log .LogService ;
3942import org .scijava .plugin .AbstractHandlerService ;
4043import org .scijava .plugin .Parameter ;
4144import org .scijava .plugin .Plugin ;
4245import org .scijava .service .Service ;
46+ import org .scijava .thread .ThreadService ;
47+ import org .scijava .thread .ThreadService .ThreadContext ;
4348
4449/**
4550 * Default service for managing interaction with the console.
@@ -52,10 +57,14 @@ public class DefaultConsoleService extends
5257 ConsoleService
5358{
5459
60+ @ Parameter
61+ private ThreadService threadService ;
62+
5563 @ Parameter
5664 private LogService log ;
5765
5866 private MultiPrintStream sysout , syserr ;
67+ private OutputStreamReporter out , err ;
5968
6069 /** List of listeners for {@code stdout} and {@code stderr} output. */
6170 private ArrayList <OutputListener > listeners ;
@@ -124,6 +133,14 @@ public Class<LinkedList<String>> getType() {
124133 return (Class ) LinkedList .class ;
125134 }
126135
136+ // -- Disposable methods --
137+
138+ @ Override
139+ public void dispose () {
140+ if (out != null ) sysout .getParent ().removeOutputStream (out );
141+ if (err != null ) syserr .getParent ().removeOutputStream (err );
142+ }
143+
127144 // -- Helper methods - lazy initialization --
128145
129146 /** Initializes {@link #listeners} and related data structures. */
@@ -132,8 +149,13 @@ private synchronized void initListeners() {
132149
133150 sysout = multiPrintStream (System .out );
134151 if (System .out != sysout ) System .setOut (sysout );
152+ out = new OutputStreamReporter (Source .STDOUT );
153+ sysout .getParent ().addOutputStream (out );
154+
135155 syserr = multiPrintStream (System .err );
136156 if (System .err != syserr ) System .setErr (syserr );
157+ err = new OutputStreamReporter (Source .STDERR );
158+ syserr .getParent ().addOutputStream (err );
137159
138160 listeners = new ArrayList <OutputListener >();
139161 }
@@ -145,4 +167,50 @@ private MultiPrintStream multiPrintStream(final PrintStream ps) {
145167 return new MultiPrintStream (ps );
146168 }
147169
170+ // -- Helper classes --
171+
172+ /**
173+ * An output stream that publishes its output to the {@link OutputListener}s
174+ * of its associated {@link ConsoleService}.
175+ */
176+ private class OutputStreamReporter extends OutputStream {
177+
178+ /** Source of the output stream; i.e., {@code stdout} or {@code stderr}. */
179+ private final Source source ;
180+
181+ public OutputStreamReporter (final Source source ) {
182+ this .source = source ;
183+ }
184+
185+ // -- OutputStream methods --
186+
187+ @ Override
188+ public void write (final int b ) {
189+ final ThreadContext relevance = getRelevance ();
190+ if (relevance == ThreadContext .OTHER ) return ; // different context
191+ publish (relevance , "" + b );
192+ }
193+
194+ @ Override
195+ public void write (final byte [] buf , final int off , final int len ) {
196+ final ThreadContext relevance = getRelevance ();
197+ if (relevance == ThreadContext .OTHER ) return ; // different context
198+ publish (relevance , new String (buf , off , len ));
199+ }
200+
201+ // -- Helper methods --
202+
203+ private ThreadContext getRelevance () {
204+ return threadService .getThreadContext (Thread .currentThread ());
205+ }
206+
207+ private void publish (final ThreadContext relevance , final String output ) {
208+ final Context context = getContext ();
209+ final boolean contextual = relevance == ThreadContext .SAME ;
210+ final OutputEvent event =
211+ new OutputEvent (context , source , output , contextual );
212+ notifyListeners (event );
213+ }
214+ }
215+
148216}
0 commit comments