View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.net;
19  
20  import com.google.common.base.Supplier;
21  import java.io.Closeable;
22  import java.io.IOException;
23  import java.net.InetAddress;
24  import java.net.InetSocketAddress;
25  import java.net.ServerSocket;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  /**
30   * Utility to generate a bound socket. Useful testing for BindException.
31   * Use one of the Constructors to create an instance of this class. On creation it will have put
32   * up a ServerSocket on a random port. Get the port it is bound to using {@link #getPort()}. In
33   * your test, then try to start a Server using same port to generate a BindException. Call
34   * {@link #close()} when done to shut down the Socket.
35   */
36  public final class BoundSocketMaker implements Closeable {
37    private static final Log LOG = LogFactory.getLog(BoundSocketMaker.class);
38    private final ServerSocket socket;
39  
40    private BoundSocketMaker() {
41      this.socket = null;
42    }
43  
44    public BoundSocketMaker(Supplier<Integer> randomPortMaker) {
45      this(InetAddress.getLoopbackAddress().getHostName(), randomPortMaker);
46    }
47  
48    public BoundSocketMaker(final String hostname, Supplier<Integer> randomPortMaker) {
49      this.socket = get(hostname, randomPortMaker);
50    }
51  
52    public int getPort() {
53      return this.socket.getLocalPort();
54    }
55  
56    /**
57     * @return Returns a bound socket; be sure to close when done.
58     */
59    private ServerSocket get(String hostname, Supplier<Integer> randomPortMaker) {
60      ServerSocket ss = null;
61      int port = -1;
62      while (true) {
63        port = randomPortMaker.get();
64        try {
65          ss = new ServerSocket();
66          ss.bind(new InetSocketAddress(hostname, port));
67          break;
68        } catch (IOException ioe) {
69          LOG.warn("Failed bind", ioe);
70          try {
71            ss.close();
72          } catch (IOException ioe2) {
73            LOG.warn("FAILED CLOSE of failed bind socket", ioe2);
74          }
75        }
76      }
77      return ss;
78    }
79  
80    @Override public void close() throws IOException {
81      if (this.socket != null) {
82        this.socket.close();
83      }
84    }
85  }