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.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   * Producer of TCP/IP encoder and decoder.
47   * <br>
48   *
49   * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
50   * @since 3.0.0-M5
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 }