1 package org.apache.maven.plugin.surefire.booterclient.output;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.maven.shared.utils.cli.StreamConsumer;
23
24 import java.util.concurrent.LinkedBlockingQueue;
25
26 /**
27 * Knows how to reconstruct *all* the state transmitted over stdout by the forked process.
28 *
29 * @author Kristian Rosenvold
30 */
31 public class ThreadedStreamConsumer
32 implements StreamConsumer
33 {
34
35 private final java.util.concurrent.BlockingQueue<String> items = new LinkedBlockingQueue<String>();
36
37 private static final String poison = "Pioson";
38
39 private final Thread thread;
40
41 private final Pumper pumper;
42
43 static class Pumper
44 implements Runnable
45 {
46 private final java.util.concurrent.BlockingQueue<String> queue;
47
48 private final StreamConsumer target;
49
50 private volatile Throwable throwable;
51
52
53 Pumper( java.util.concurrent.BlockingQueue<String> queue, StreamConsumer target )
54 {
55 this.queue = queue;
56 this.target = target;
57 }
58
59 public void run()
60 {
61 try
62 {
63 String item = queue.take();
64 //noinspection StringEquality
65 while ( item != poison )
66 {
67 target.consumeLine( item );
68 item = queue.take();
69 }
70 }
71 catch ( Throwable t )
72 {
73 // Think about what happens if the producer overruns us and creates an OOME. Not nice.
74 // Maybe limit length of blocking queue
75 this.throwable = t;
76 }
77 }
78
79 public Throwable getThrowable()
80 {
81 return throwable;
82 }
83 }
84
85 public ThreadedStreamConsumer( StreamConsumer target )
86 {
87 pumper = new Pumper( items, target );
88 thread = new Thread( pumper, "ThreadedStreamConsumer" );
89 thread.start();
90 }
91
92 public void consumeLine( String s )
93 {
94 items.add( s );
95 if ( items.size() > 10000 )
96 {
97 try
98 {
99 Thread.sleep( 100 );
100 }
101 catch ( InterruptedException ignore )
102 {
103 }
104 }
105 }
106
107
108 public void close()
109 {
110 try
111 {
112 items.add( poison );
113 thread.join();
114 }
115 catch ( InterruptedException e )
116 {
117 throw new RuntimeException( e );
118 }
119
120 //noinspection ThrowableResultOfMethodCallIgnored
121 if ( pumper.getThrowable() != null )
122 {
123 throw new RuntimeException( pumper.getThrowable() );
124 }
125 }
126 }