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 }