1 package org.apache.maven.surefire.booter.spi;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.surefire.api.booter.MasterProcessChannelDecoder;
23 import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
24 import org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory;
25
26 import java.io.IOException;
27 import java.net.InetSocketAddress;
28 import java.net.MalformedURLException;
29 import java.net.SocketOption;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.nio.channels.AsynchronousSocketChannel;
33 import java.util.concurrent.ExecutionException;
34
35 import static java.net.StandardSocketOptions.SO_KEEPALIVE;
36 import static java.net.StandardSocketOptions.SO_REUSEADDR;
37 import static java.net.StandardSocketOptions.TCP_NODELAY;
38 import static java.nio.channels.AsynchronousChannelGroup.withFixedThreadPool;
39 import static java.nio.channels.AsynchronousSocketChannel.open;
40 import static org.apache.maven.surefire.api.util.internal.Channels.newBufferedChannel;
41 import static org.apache.maven.surefire.api.util.internal.Channels.newInputStream;
42 import static org.apache.maven.surefire.api.util.internal.Channels.newOutputStream;
43 import static org.apache.maven.surefire.api.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
44
45
46
47
48
49
50
51
52 public class SurefireMasterProcessChannelProcessorFactory
53 implements MasterProcessChannelProcessorFactory
54 {
55 private volatile AsynchronousSocketChannel clientSocketChannel;
56
57 @Override
58 public boolean canUse( String channelConfig )
59 {
60 return channelConfig.startsWith( "tcp://" );
61 }
62
63 @Override
64 public void connect( String channelConfig ) throws IOException
65 {
66 if ( !canUse( channelConfig ) )
67 {
68 throw new MalformedURLException( "Unknown chanel string " + channelConfig );
69 }
70
71 try
72 {
73 URI uri = new URI( channelConfig );
74 InetSocketAddress hostAddress = new InetSocketAddress( uri.getHost(), uri.getPort() );
75 clientSocketChannel = open( withFixedThreadPool( 2, newDaemonThreadFactory() ) );
76 setTrueOptions( SO_REUSEADDR, TCP_NODELAY, SO_KEEPALIVE );
77 clientSocketChannel.connect( hostAddress ).get();
78 }
79 catch ( URISyntaxException | InterruptedException e )
80 {
81 throw new IOException( e.getLocalizedMessage(), e );
82 }
83 catch ( ExecutionException e )
84 {
85 throw new IOException( e.getLocalizedMessage(), e.getCause() );
86 }
87 }
88
89 @Override
90 public MasterProcessChannelDecoder createDecoder()
91 {
92 return new LegacyMasterProcessChannelDecoder( newBufferedChannel( newInputStream( clientSocketChannel ) ) );
93 }
94
95 @Override
96 public MasterProcessChannelEncoder createEncoder()
97 {
98 return new LegacyMasterProcessChannelEncoder( newBufferedChannel( newOutputStream( clientSocketChannel ) ) );
99 }
100
101 @Override
102 public void close() throws IOException
103 {
104 if ( clientSocketChannel != null && clientSocketChannel.isOpen() )
105 {
106 clientSocketChannel.close();
107 }
108 }
109
110 @SafeVarargs
111 private final void setTrueOptions( SocketOption<Boolean>... options )
112 throws IOException
113 {
114 for ( SocketOption<Boolean> option : options )
115 {
116 if ( clientSocketChannel.supportedOptions().contains( option ) )
117 {
118 clientSocketChannel.setOption( option, true );
119 }
120 }
121 }
122 }