1 package org.apache.maven.lifecycle.internal;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.PrintStream;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.Set;
31
32
33
34
35
36
37
38
39
40 @SuppressWarnings( { "SynchronizationOnLocalVariableOrMethodParameter" } )
41 public class ThreadOutputMuxer
42 {
43 private final Iterator<ProjectSegment> projects;
44
45 private final ThreadLocal<ProjectSegment> projectBuildThreadLocal = new ThreadLocal<ProjectSegment>();
46
47 private final Map<ProjectSegment, ByteArrayOutputStream> streams =
48 new HashMap<ProjectSegment, ByteArrayOutputStream>();
49
50 private final Map<ProjectSegment, PrintStream> printStreams = new HashMap<ProjectSegment, PrintStream>();
51
52 private final ByteArrayOutputStream defaultOutputStreamForUnknownData = new ByteArrayOutputStream();
53
54 private final PrintStream defaultPringStream = new PrintStream( defaultOutputStreamForUnknownData );
55
56 private final Set<ProjectSegment> completedBuilds = Collections.synchronizedSet( new HashSet<ProjectSegment>() );
57
58 private volatile ProjectSegment currentBuild;
59
60 private final PrintStream originalSystemOUtStream;
61
62 private final ConsolePrinter printer;
63
64
65
66
67
68 class ConsolePrinter
69 implements Runnable
70 {
71 public volatile boolean running;
72
73 private final ProjectBuildList projectBuildList;
74
75 ConsolePrinter( ProjectBuildList projectBuildList )
76 {
77 this.projectBuildList = projectBuildList;
78 }
79
80 public void run()
81 {
82 running = true;
83 for ( ProjectSegment projectBuild : projectBuildList )
84 {
85 final PrintStream projectStream = printStreams.get( projectBuild );
86 ByteArrayOutputStream projectOs = streams.get( projectBuild );
87
88 do
89 {
90 synchronized ( projectStream )
91 {
92 try
93 {
94 projectStream.wait( 100 );
95 }
96 catch ( InterruptedException e )
97 {
98 throw new RuntimeException( e );
99 }
100 try
101 {
102 projectOs.writeTo( originalSystemOUtStream );
103 }
104 catch ( IOException e )
105 {
106 throw new RuntimeException( e );
107 }
108
109 projectOs.reset();
110 }
111 }
112 while ( !completedBuilds.contains( projectBuild ) );
113 }
114 running = false;
115 }
116
117
118
119
120
121 public void waitUntilRunning( boolean expect )
122 {
123 while ( !running == expect )
124 {
125 try
126 {
127 Thread.sleep( 10 );
128 }
129 catch ( InterruptedException e )
130 {
131 throw new RuntimeException( e );
132 }
133 }
134 }
135 }
136
137 public ThreadOutputMuxer( ProjectBuildList segmentChunks, PrintStream originalSystemOut )
138 {
139 projects = segmentChunks.iterator();
140 for ( ProjectSegment segmentChunk : segmentChunks )
141 {
142 final ByteArrayOutputStream value = new ByteArrayOutputStream();
143 streams.put( segmentChunk, value );
144 printStreams.put( segmentChunk, new PrintStream( value ) );
145 }
146 setNext();
147 this.originalSystemOUtStream = originalSystemOut;
148 System.setOut( new ThreadBoundPrintStream( this.originalSystemOUtStream ) );
149 printer = new ConsolePrinter( segmentChunks );
150 new Thread( printer ).start();
151 printer.waitUntilRunning( true );
152 }
153
154 public void close()
155 {
156 printer.waitUntilRunning( false );
157 System.setOut( this.originalSystemOUtStream );
158 }
159
160 private void setNext()
161 {
162 currentBuild = projects.hasNext() ? projects.next() : null;
163 }
164
165 private boolean ownsRealOutputStream( ProjectSegment projectBuild )
166 {
167 return projectBuild.equals( currentBuild );
168 }
169
170 private PrintStream getThreadBoundPrintStream()
171 {
172 ProjectSegment threadProject = projectBuildThreadLocal.get();
173 if ( threadProject == null )
174 {
175 return defaultPringStream;
176 }
177 if ( ownsRealOutputStream( threadProject ) )
178 {
179 return originalSystemOUtStream;
180 }
181 return printStreams.get( threadProject );
182 }
183
184 public void associateThreadWithProjectSegment( ProjectSegment projectBuild )
185 {
186 projectBuildThreadLocal.set( projectBuild );
187 }
188
189 public void setThisModuleComplete( ProjectSegment projectBuild )
190 {
191 completedBuilds.add( projectBuild );
192 PrintStream stream = printStreams.get( projectBuild );
193 synchronized ( stream )
194 {
195 stream.notifyAll();
196 }
197 disconnectThreadFromProject();
198 }
199
200 private void disconnectThreadFromProject()
201 {
202 projectBuildThreadLocal.remove();
203 }
204
205 private class ThreadBoundPrintStream
206 extends PrintStream
207 {
208
209 public ThreadBoundPrintStream( PrintStream systemOutStream )
210 {
211 super( systemOutStream );
212 }
213
214 private PrintStream getOutputStreamForCurrentThread()
215 {
216 return getThreadBoundPrintStream();
217 }
218
219 @Override
220 public void println()
221 {
222 final PrintStream currentStream = getOutputStreamForCurrentThread();
223 synchronized ( currentStream )
224 {
225 currentStream.println();
226 currentStream.notifyAll();
227 }
228 }
229
230 @Override
231 public void print( char c )
232 {
233 final PrintStream currentStream = getOutputStreamForCurrentThread();
234 synchronized ( currentStream )
235 {
236 currentStream.print( c );
237 currentStream.notifyAll();
238 }
239 }
240
241 @Override
242 public void println( char x )
243 {
244 final PrintStream currentStream = getOutputStreamForCurrentThread();
245 synchronized ( currentStream )
246 {
247 currentStream.println( x );
248 currentStream.notifyAll();
249 }
250 }
251
252 @Override
253 public void print( double d )
254 {
255 final PrintStream currentStream = getOutputStreamForCurrentThread();
256 synchronized ( currentStream )
257 {
258 currentStream.print( d );
259 currentStream.notifyAll();
260 }
261 }
262
263 @Override
264 public void println( double x )
265 {
266 final PrintStream currentStream = getOutputStreamForCurrentThread();
267 synchronized ( currentStream )
268 {
269 currentStream.println( x );
270 currentStream.notifyAll();
271 }
272 }
273
274 @Override
275 public void print( float f )
276 {
277 final PrintStream currentStream = getOutputStreamForCurrentThread();
278 synchronized ( currentStream )
279 {
280 currentStream.print( f );
281 currentStream.notifyAll();
282 }
283 }
284
285 @Override
286 public void println( float x )
287 {
288 final PrintStream currentStream = getOutputStreamForCurrentThread();
289 synchronized ( currentStream )
290 {
291 currentStream.println( x );
292 currentStream.notifyAll();
293 }
294 }
295
296 @Override
297 public void print( int i )
298 {
299 final PrintStream currentStream = getOutputStreamForCurrentThread();
300 synchronized ( currentStream )
301 {
302 currentStream.print( i );
303 currentStream.notifyAll();
304 }
305 }
306
307 @Override
308 public void println( int x )
309 {
310 final PrintStream currentStream = getOutputStreamForCurrentThread();
311 synchronized ( currentStream )
312 {
313 currentStream.println( x );
314 currentStream.notifyAll();
315 }
316 }
317
318 @Override
319 public void print( long l )
320 {
321 final PrintStream currentStream = getOutputStreamForCurrentThread();
322 synchronized ( currentStream )
323 {
324 currentStream.print( l );
325 currentStream.notifyAll();
326 }
327 }
328
329 @Override
330 public void println( long x )
331 {
332 final PrintStream currentStream = getOutputStreamForCurrentThread();
333 synchronized ( currentStream )
334 {
335 currentStream.print( x );
336 currentStream.notifyAll();
337 }
338 }
339
340 @Override
341 public void print( boolean b )
342 {
343 final PrintStream currentStream = getOutputStreamForCurrentThread();
344 synchronized ( currentStream )
345 {
346 currentStream.print( b );
347 currentStream.notifyAll();
348 }
349 }
350
351 @Override
352 public void println( boolean x )
353 {
354 final PrintStream currentStream = getOutputStreamForCurrentThread();
355 synchronized ( currentStream )
356 {
357 currentStream.print( x );
358 currentStream.notifyAll();
359 }
360 }
361
362 @Override
363 public void print( char s[] )
364 {
365 final PrintStream currentStream = getOutputStreamForCurrentThread();
366 synchronized ( currentStream )
367 {
368 currentStream.print( s );
369 currentStream.notifyAll();
370 }
371 }
372
373 @Override
374 public void println( char x[] )
375 {
376 final PrintStream currentStream = getOutputStreamForCurrentThread();
377 synchronized ( currentStream )
378 {
379 currentStream.print( x );
380 currentStream.notifyAll();
381 }
382 }
383
384 @Override
385 public void print( Object obj )
386 {
387 final PrintStream currentStream = getOutputStreamForCurrentThread();
388 synchronized ( currentStream )
389 {
390 currentStream.print( obj );
391 currentStream.notifyAll();
392 }
393 }
394
395 @Override
396 public void println( Object x )
397 {
398 final PrintStream currentStream = getOutputStreamForCurrentThread();
399 synchronized ( currentStream )
400 {
401 currentStream.println( x );
402 currentStream.notifyAll();
403 }
404 }
405
406 @Override
407 public void print( String s )
408 {
409 final PrintStream currentStream = getOutputStreamForCurrentThread();
410 synchronized ( currentStream )
411 {
412 currentStream.print( s );
413 currentStream.notifyAll();
414 }
415 }
416
417 @Override
418 public void println( String x )
419 {
420 final PrintStream currentStream = getOutputStreamForCurrentThread();
421 synchronized ( currentStream )
422 {
423 currentStream.println( x );
424 currentStream.notifyAll();
425 }
426 }
427
428 @Override
429 public void write( byte b[], int off, int len )
430 {
431 final PrintStream currentStream = getOutputStreamForCurrentThread();
432 synchronized ( currentStream )
433 {
434 currentStream.write( b, off, len );
435 currentStream.notifyAll();
436 }
437 }
438
439 @Override
440 public void close()
441 {
442 getOutputStreamForCurrentThread().close();
443 }
444
445 @Override
446 public void flush()
447 {
448 getOutputStreamForCurrentThread().flush();
449 }
450
451 @Override
452 public void write( int b )
453 {
454 final PrintStream currentStream = getOutputStreamForCurrentThread();
455 synchronized ( currentStream )
456 {
457 currentStream.write( b );
458 currentStream.notifyAll();
459 }
460 }
461
462 @Override
463 public void write( byte b[] )
464 throws IOException
465 {
466 final PrintStream currentStream = getOutputStreamForCurrentThread();
467 synchronized ( currentStream )
468 {
469 currentStream.write( b );
470 currentStream.notifyAll();
471 }
472 }
473 }
474 }