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 }