View Javadoc

1   /*
2    * $Id: FreePortFinder.java 22017 2011-05-27 20:28:27Z pablo.kraan $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.tck.junit4.rule;
12  
13  import java.io.IOException;
14  import java.net.ServerSocket;
15  import java.util.HashSet;
16  import java.util.Set;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  
21  /**
22   * Finds available port numbers in a specified range.
23   */
24  public class FreePortFinder
25  {
26  
27      protected final Log logger = LogFactory.getLog(getClass());
28  
29      protected final int minPortNumber;
30      protected final int maxPortNumber;
31  
32      private Set<Integer> selectedPorts = new HashSet<Integer>();
33  
34      public FreePortFinder(int minPortNumber, int maxPortNumber)
35      {
36          this.minPortNumber = minPortNumber;
37          this.maxPortNumber = maxPortNumber;
38      }
39  
40      public synchronized Integer find()
41      {
42          for (int port = minPortNumber; port < maxPortNumber; port++)
43          {
44              if (selectedPorts.contains(port))
45              {
46                  continue;
47              }
48  
49              if (isPortFree(port))
50              {
51                  if (logger.isDebugEnabled())
52                  {
53                      logger.debug("Found free port: " + port);
54                  }
55  
56                  selectedPorts.add(port);
57                  return port;
58              }
59          }
60  
61          throw new IllegalStateException("Unable to find an available port");
62      }
63  
64      /**
65       * Indicates that the port is free from the point of view of the caller.
66       * <p/>
67       * Checks that the port was released, if it was not, then it would be
68       * marked as in use, so no other client receives the same port again.
69       *
70       * @param port the port number to release.
71       */
72      public synchronized void releasePort(int port)
73      {
74          if (isPortFree(port))
75          {
76              selectedPorts.remove(port);
77          }
78          else
79          {
80              if (logger.isInfoEnabled())
81              {
82                  logger.info(String.format("Port %d was is not correctly released", port));
83              }
84          }
85      }
86  
87      /**
88       * Check and log is a given port is available
89       *
90       * @param port the port number to check
91       * @return true if the port is available, false otherwise
92       */
93      public boolean isPortFree(int port)
94      {
95          boolean portIsFree = true;
96  
97          ServerSocket server = null;
98          try
99          {
100             server = new ServerSocket(port);
101         }
102         catch (IOException e)
103         {
104             portIsFree = false;
105         }
106         finally
107         {
108             if (server != null)
109             {
110                 try
111                 {
112                     server.close();
113                 }
114                 catch (IOException e)
115                 {
116                     // ignore
117                 }
118             }
119         }
120 
121         return portIsFree;
122     }
123 }