View Javadoc
1   package org.apache.maven.surefire.booter.spi;
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.surefire.api.util.internal.WritableBufferedByteChannel;
23  import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
24  
25  import java.io.IOException;
26  import java.nio.ByteBuffer;
27  import java.security.AccessControlException;
28  import java.security.PrivilegedAction;
29  import java.util.concurrent.ScheduledExecutorService;
30  import java.util.concurrent.atomic.AtomicLong;
31  
32  import static java.security.AccessController.doPrivileged;
33  import static java.util.concurrent.Executors.newScheduledThreadPool;
34  import static java.util.concurrent.TimeUnit.MILLISECONDS;
35  import static org.apache.maven.surefire.api.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
36  
37  /**
38   * Default implementation of {@link MasterProcessChannelProcessorFactory}.
39   */
40  public abstract class AbstractMasterProcessChannelProcessorFactory
41      implements MasterProcessChannelProcessorFactory
42  {
43      private static final String STREAM_FLUSHER = "surefire-forkedjvm-stream-flusher";
44      private final ScheduledExecutorService flusher;
45  
46      public AbstractMasterProcessChannelProcessorFactory()
47      {
48          flusher = newScheduledThreadPool( 1, newDaemonThreadFactory( STREAM_FLUSHER ) );
49      }
50  
51      protected void schedulePeriodicFlusher( int delayInMillis, final WritableBufferedByteChannel channel  )
52      {
53          final AtomicLong bufferOverflows = new AtomicLong();
54          flusher.scheduleWithFixedDelay( new Runnable()
55          {
56              @Override
57              public void run()
58              {
59                  long currentBufferOverflows = channel.countBufferOverflows();
60                  // optimization: flush the Channel only if the buffer has not overflew after last period of time
61                  if ( bufferOverflows.get() == currentBufferOverflows )
62                  {
63                      try
64                      {
65                          channel.write( ByteBuffer.allocate( 0 ) );
66                      }
67                      catch ( Exception e )
68                      {
69                          // cannot do anything about this I/O issue
70                      }
71                  }
72                  else
73                  {
74                      bufferOverflows.set( currentBufferOverflows );
75                  }
76              }
77          }, 0L, delayInMillis, MILLISECONDS );
78      }
79  
80      @Override
81      public void close() throws IOException
82      {
83          try
84          {
85              doPrivileged( new PrivilegedAction<Object>()
86                            {
87                                @Override
88                                public Object run()
89                                {
90                                    flusher.shutdown();
91                                    // Do NOT call awaitTermination() due to this would unnecessarily prolong teardown
92                                    // time of the JVM. It is not a critical situation when the JXM exits this daemon
93                                    // thread because the interrupted flusher does not break any business function.
94                                    // All business data is already safely flushed by test events, then by sending BYE
95                                    // event at the exit time and finally by flushEventChannelOnExit() in ForkedBooter.
96                                    return null;
97                                }
98                            }
99              );
100         }
101         catch ( AccessControlException e )
102         {
103             // ignore
104         }
105     }
106 }