View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.test.remote;
18  
19  import java.io.IOException;
20  import java.net.DatagramSocket;
21  import java.net.ServerSocket;
22  import java.util.NoSuchElementException;
23  import java.util.concurrent.atomic.AtomicInteger;
24  
25  
26  /**
27   * <p>Finds currently available server ports.</p>
28   *
29   * <p>This class is a verbatim copy of AvailablePortFinder from the camel-test component of the Apache Camel project.
30   * </p>
31   *
32   * @see <a href="http://svn.apache.org/viewvc/camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/AvailablePortFinder.java?revision=1137595&view=co">IANA.org</a>
33   */
34  public final class AvailablePortFinder {
35      /**
36       * The minimum server currentMinPort number. Set at 1024 to avoid returning privileged
37       * currentMinPort numbers.
38       */
39      public static final int MIN_PORT_NUMBER = 1024;
40  
41      /**
42       * The maximum server currentMinPort number.
43       */
44      public static final int MAX_PORT_NUMBER = 49151;
45  
46  
47      /**
48       * Incremented to the next lowest available port when getNextAvailable() is called.
49       */
50      private static AtomicInteger currentMinPort = new AtomicInteger(MIN_PORT_NUMBER);
51  
52      /**
53       * Creates a new instance.
54       */
55      private AvailablePortFinder() {
56          // Do nothing
57      }
58  
59      /**
60       * Gets the next available currentMinPort starting at the lowest currentMinPort number. This is the preferred
61       * method to use. The port return is immediately marked in use and doesn't rely on the caller actually opening
62       * the port.
63       *
64       * @throws NoSuchElementException if there are no ports available
65       */
66      public static synchronized int getNextAvailable() {
67          int next = getNextAvailable(currentMinPort.get());
68          currentMinPort.set(next + 1);
69          return next;
70      }
71  
72      /**
73       * Gets the next available currentMinPort starting at a currentMinPort.
74       *
75       * @param fromPort the currentMinPort to scan for availability
76       * @throws NoSuchElementException if there are no ports available
77       */
78      public static synchronized int getNextAvailable(int fromPort) {
79          if (fromPort < currentMinPort.get() || fromPort > MAX_PORT_NUMBER) {
80              throw new IllegalArgumentException("Invalid start currentMinPort: " + fromPort);
81          }
82  
83          for (int i = fromPort; i <= MAX_PORT_NUMBER; i++) {
84              if (available(i)) {
85                  return i;
86              }
87          }
88  
89          throw new NoSuchElementException("Could not find an available currentMinPort above " + fromPort);
90      }
91  
92      /**
93       * Checks to see if a specific currentMinPort is available.
94       *
95       * @param port the currentMinPort to check for availability
96       */
97      public static boolean available(int port) {
98          if (port < currentMinPort.get() || port > MAX_PORT_NUMBER) {
99              throw new IllegalArgumentException("Invalid start currentMinPort: " + port);
100         }
101 
102         ServerSocket ss = null;
103         DatagramSocket ds = null;
104         try {
105             ss = new ServerSocket(port);
106             ss.setReuseAddress(true);
107             ds = new DatagramSocket(port);
108             ds.setReuseAddress(true);
109             return true;
110         } catch (IOException e) {
111             // Do nothing
112         } finally {
113             if (ds != null) {
114                 ds.close();
115             }
116 
117             if (ss != null) {
118                 try {
119                     ss.close();
120                 } catch (IOException e) {
121                     /* should not be thrown */
122                 }
123             }
124         }
125 
126         return false;
127     }
128 }