View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.util;
21  
22  import java.io.IOException;
23  import java.net.ServerSocket;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.Random;
29  import java.util.StringTokenizer;
30  
31  /***
32   * Provides a data container for port ranges. All methods make sure
33   * that only valid ports are added.
34   *
35   * @see xnap.util.prefs.PortRangeValidator 
36   */
37  public class PortRange {
38  
39      //--- Constant(s) ---
40  
41      public static final int MIN_PORT = 1;
42      public static final int MAX_PORT = 65535;
43  
44      //--- Data field(s) ---
45  
46      /***
47       * A set of {@link Integer} objects.
48       */
49      private HashSet list = new HashSet();
50  
51      //--- Constructor(s) ---
52      
53      public PortRange(int first, int last) 
54      {
55  		add(first, last);
56      }
57  
58      public PortRange(String range)
59      {
60  		add(range);
61      }
62  
63      public PortRange()
64      {
65      }
66  
67      //--- Method(s) ---
68  
69      /***
70       * Adds all ports that are <code>first</code> <= port <= <code>last</code>.
71       */
72      public void add(int first, int last)
73      {
74  		for (int i = Math.max(first, MIN_PORT); i <= last && i <= MAX_PORT; 
75  			 i++) {
76  			list.add(new Integer(i));
77  		}
78      }
79  
80      /***
81       * Adds <code>port</code> to the range.
82       */
83      public void add(int port)
84      {
85  		if (port >= MIN_PORT && port <= MAX_PORT) {
86  			list.add(new Integer(port));
87  		}
88      }
89  
90      /***
91       * Adds a range as a string.
92       *
93       * @see xnap.util.prefs.PortRangeValidator
94       */
95      public void add(String range)
96      {
97  		StringTokenizer t = new StringTokenizer(range, ";");
98  		while (t.hasMoreTokens()) {
99  			String ports = t.nextToken().trim();
100 
101 			if (ports.length() == 0) {
102 				continue;
103 			}
104 
105 			try {
106 				if (ports.indexOf("-") != -1) {
107 					StringTokenizer u = new StringTokenizer(ports, "-");
108 					if (u.countTokens() == 2) {
109 						add(Integer.parseInt(u.nextToken()),
110 							Integer.parseInt(u.nextToken()));
111 					}
112 				}
113 				else {
114 					add(Integer.parseInt(ports));
115 				}
116 			}
117 			catch (NumberFormatException e) {
118 			}
119 		}
120     }
121 
122     /***
123      * Tries to bind random ports from the range and returns the 
124      * {@link ServerSocket} object if successful. 
125      *
126      * @return null, if no port could be bound
127      */
128     public ServerSocket bindRandom()
129     {
130 		// bind to next free port
131 		for (PortRange.IntIterator i = random(); i.hasNext();) {
132 			try {
133 				return new ServerSocket(i.next());
134 			} 
135 			catch (IOException e) {
136 			}
137 		}
138 
139 		return null;
140     }
141 
142     /***
143      * Returns true, if port is in the range.
144      */
145     public boolean contains(int port)
146     {
147 		return list.contains(new Integer(port));
148     }
149 
150     /***
151      * Returns a random port from the range.
152      *
153      * @param defaultPort a default port
154      * @return default, if range is empty
155      */
156     public int getRandom(int defaultPort)
157     {
158 		if (size() > 0) {
159 			ArrayList copy = new ArrayList(list);
160 			int index = (new Random()).nextInt(copy.size());
161 			return ((Integer)copy.get(index)).intValue();
162 		}
163 	
164 		return defaultPort;
165     }
166     
167     /***
168      * Returns an iterator over all contained ports.
169      */
170     public Iterator iterator()
171     {
172 		return list.iterator();
173     }
174 
175     /***
176      * Returns an iterator over a shuffeled instance.
177      */
178     public IntIterator random()
179     {
180 		ArrayList copy = new ArrayList(list);
181 		Collections.shuffle(copy);
182 		return new IntIterator(copy.iterator());
183     }
184 
185     /***
186      * Returns the number of ports.
187      */
188     public int size()
189     {
190 		return list.size();
191     }
192 
193     /***
194      * Returns an ordered string representation.
195      */
196     public String toString()
197     {
198 		StringBuffer sb = new StringBuffer();
199 
200 		ArrayList copy = new ArrayList(list);
201 		Collections.sort(copy);
202 
203 		int start = 0;
204 		int last = -1;
205 		for (IntIterator i = new IntIterator(copy.iterator()); i.hasNext();) {
206 			int current = i.next();
207 			if (last == -1) {
208 				start = current;
209 			}
210 			else if (current - last > 1) {
211 				sb.append(start);
212 				if (start != last) {
213 					sb.append("-");
214 					sb.append(last);
215 				}
216 				sb.append(";");
217 				start = current;
218 			}
219 			last = current;
220 		}
221 
222 		if (last != -1) {
223 			sb.append(start);
224 			if (start != last) {
225 				sb.append("-");
226 				sb.append(last);
227 			}
228 			sb.append(";");
229 		}	
230 
231 		return sb.toString();
232     }
233 
234     //--- Inner class(es) ---
235 
236     /***
237      * An iterator over Integer objects.
238      */
239     public static class IntIterator
240     {
241 	
242 		Iterator iterator;
243 
244 		public IntIterator(Iterator iterator)
245 		{
246 			this.iterator = iterator;
247 		}
248 	
249 		public boolean hasNext()
250 		{
251 			return iterator.hasNext();
252 		}
253 
254 		public int next()
255 		{
256 			return ((Integer)iterator.next()).intValue();
257 		}
258 	
259 		public void remove()
260 		{
261 			iterator.remove();
262 		}
263 
264     }
265 
266 }
267 
268