View Javadoc

1   package org.apache.maven.surefire.report;
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 java.util.concurrent.LinkedBlockingQueue;
23  import org.apache.maven.surefire.util.internal.ByteBuffer;
24  
25  /**
26   * Transfers further processing of the request to a different thread,
27   * returning immediately to calling code.
28   * Deals with system.out/err from single-threaded processes.
29   * <p/>
30   */
31  public class AsynchRunListener
32      implements RunListener, ConsoleOutputReceiver, ConsoleLogger
33  {
34      private final LinkedBlockingQueue blockingQueue = new LinkedBlockingQueue();
35  
36      private final Processor processor;
37  
38      private final RunListener target;
39  
40      private final ConsoleOutputReceiver consoleOutputReceiver;
41  
42      private final Thread asynchRunListener;
43  
44      static class Processor
45          implements Runnable
46      {
47          private final LinkedBlockingQueue blockingQueue;
48  
49          private volatile InterruptedException exception;
50  
51          Processor( LinkedBlockingQueue blockingQueue )
52          {
53              this.blockingQueue = blockingQueue;
54          }
55  
56          public void run()
57          {
58              try
59              {
60                  Runnable take;
61                  take = (Runnable) blockingQueue.take();
62                  while ( take != poison )
63                  {
64                      take.run();
65                      take = (Runnable) blockingQueue.take();
66                  }
67              }
68              catch ( InterruptedException e )
69              {
70                  this.exception = e;
71              }
72          }
73  
74          public InterruptedException getException()
75          {
76              return exception;
77          }
78      }
79  
80      public AsynchRunListener( RunListener target, String role )
81      {
82          this.processor = new Processor( blockingQueue );
83          this.target = target;
84          consoleOutputReceiver = (ConsoleOutputReceiver) target;
85          asynchRunListener = new Thread( processor, "AsynchRunListener" + role );
86          asynchRunListener.start();
87      }
88  
89      public void testSetStarting( final ReportEntry report )
90      {
91          blockingQueue.add( new Runnable()
92          {
93              public void run()
94              {
95                  target.testSetStarting( report );
96              }
97          } );
98      }
99  
100     public void testSetCompleted( final ReportEntry report )
101     {
102         blockingQueue.add( new Runnable()
103         {
104             public void run()
105             {
106                 target.testSetCompleted( report );
107             }
108         } );
109     }
110 
111     public void testStarting( final ReportEntry report )
112     {
113         blockingQueue.add( new Runnable()
114         {
115             public void run()
116             {
117                 target.testStarting( report );
118             }
119         } );
120     }
121 
122     public void testSucceeded( final ReportEntry report )
123     {
124         blockingQueue.add( new Runnable()
125         {
126             public void run()
127             {
128                 target.testSucceeded( report );
129             }
130         } );
131     }
132 
133     public void testAssumptionFailure( final ReportEntry report )
134     {
135         blockingQueue.add( new Runnable()
136         {
137             public void run()
138             {
139                 target.testAssumptionFailure( report );
140             }
141         } );
142 
143     }
144 
145     public void testError( final ReportEntry report )
146     {
147         blockingQueue.add( new Runnable()
148         {
149             public void run()
150             {
151                 target.testError( report );
152             }
153         } );
154     }
155 
156     public void testFailed( final ReportEntry report )
157     {
158         blockingQueue.add( new Runnable()
159         {
160             public void run()
161             {
162                 target.testFailed( report );
163             }
164         } );
165     }
166 
167     public void testSkipped( final ReportEntry report )
168     {
169         blockingQueue.add( new Runnable()
170         {
171             public void run()
172             {
173                 target.testSkipped( report );
174             }
175         } );
176     }
177 
178     static class JoinableTestOutput
179         implements Runnable
180     {
181         final byte[] buf;
182 
183         final int off;
184 
185         final int len;
186 
187         final boolean stdout;
188 
189         private final ConsoleOutputReceiver consoleOutputReceiver;
190 
191         JoinableTestOutput( final byte[] buf, final int off, final int len, final boolean stdout,
192                             ConsoleOutputReceiver consoleOutputReceiver )
193         {
194             this.buf = ByteBuffer.copy( buf, off, len );
195             this.off = 0;
196             this.len = len;
197             this.stdout = stdout;
198             this.consoleOutputReceiver = consoleOutputReceiver;
199         }
200 
201         public void run()
202         {
203             consoleOutputReceiver.writeTestOutput( buf, off, len, stdout );
204         }
205 
206         public JoinableTestOutput append( JoinableTestOutput other )
207         {
208             byte[] combined = ByteBuffer.join( buf, this.off, this.len, other.buf, other.off, other.len );
209             return new JoinableTestOutput( combined, 0, combined.length, stdout, consoleOutputReceiver );
210         }
211 
212     }
213 
214     public void writeTestOutput( final byte[] buf, final int off, final int len, final boolean stdout )
215     {
216         blockingQueue.add( new JoinableTestOutput( buf, off, len, stdout, consoleOutputReceiver ) );
217     }
218 
219     public void info( final String message )
220     {
221         blockingQueue.add( new Runnable()
222         {
223             public void run()
224             {
225                 ( (ConsoleLogger) consoleOutputReceiver ).info( message );
226             }
227         } );
228     }
229 
230     private static final Runnable poison = new Runnable()
231     {
232         public void run()
233         {
234         }
235     };
236 
237     public void close()
238         throws ReporterException
239     {
240         try
241         {
242             blockingQueue.add( poison );
243             asynchRunListener.join();
244             final InterruptedException exception = processor.getException();
245             if ( exception != null )
246             {
247                 throw exception;
248             }
249         }
250         catch ( InterruptedException e )
251         {
252             throw new ReporterException( "When waiting", e );
253         }
254 
255     }
256 }