1   /*
2    * Copyright 2005-2011 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ws.transport.support;
18  
19  import java.io.IOException;
20  import java.net.InetSocketAddress;
21  import java.net.ServerSocket;
22  import java.util.Random;
23  
24  import org.springframework.util.Assert;
25  
26  /**
27   * Utility class that finds free BSD ports for use in testing scenario's.
28   *
29   * @author Ben Hale
30   * @author Arjen Poutsma
31   */
32  public abstract class FreePortScanner {
33  
34      private static final int MIN_SAFE_PORT = 1024;
35  
36      private static final int MAX_PORT = 65535;
37  
38      private static final Random random = new Random();
39  
40      /**
41       * Returns the number of a free port in the default range.
42       */
43      public static int getFreePort() {
44          return getFreePort(MIN_SAFE_PORT, MAX_PORT);
45      }
46  
47      /**
48       * Returns the number of a free port in the given range.
49       */
50      public static int getFreePort(int minPort, int maxPort) {
51          Assert.isTrue(minPort > 0, "'minPort' must be larger than 0");
52          Assert.isTrue(maxPort > minPort, "'maxPort' must be larger than minPort");
53          int portRange = maxPort - minPort;
54          int candidatePort;
55          int searchCounter = 0;
56          do {
57              if (++searchCounter > portRange) {
58                  throw new IllegalStateException(
59                          String.format("There were no ports available in the range %d to %d", minPort, maxPort));
60              }
61              candidatePort = getRandomPort(minPort, portRange);
62          }
63          while (!isPortAvailable(candidatePort));
64  
65          return candidatePort;
66      }
67  
68      private static int getRandomPort(int minPort, int portRange) {
69          return minPort + random.nextInt(portRange);
70      }
71  
72      private static boolean isPortAvailable(int port) {
73          ServerSocket serverSocket;
74          try {
75              serverSocket = new ServerSocket();
76          }
77          catch (IOException ex) {
78              throw new IllegalStateException("Unable to create ServerSocket.", ex);
79          }
80  
81          try {
82              InetSocketAddress sa = new InetSocketAddress(port);
83              serverSocket.bind(sa);
84              return true;
85          }
86          catch (IOException ex) {
87              return false;
88          }
89          finally {
90              try {
91                  serverSocket.close();
92              }
93              catch (IOException ex) {
94                  // ignore
95              }
96          }
97      }
98  
99  }