1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.commons.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.Iterator;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.Random;
30 import java.util.Set;
31 import java.util.StringTokenizer;
32 import org.xnap.commons.settings.PortRangeValidator;
33
34 /***
35 * Provides a data container for port ranges. All methods make sure
36 * that only valid ports are added.
37 *
38 * @see org.xnap.commons.settings.PortRangeValidator
39 */
40 public class PortRange {
41
42 public static final int MIN_PORT = 1;
43 public static final int MAX_PORT = 65535;
44
45 /***
46 * The set of valid ports.
47 */
48 private Set<Integer> list = new LinkedHashSet<Integer>();
49
50 public PortRange(int first, int last)
51 {
52 add(first, last);
53 }
54
55 public PortRange(String range)
56 {
57 add(range);
58 }
59
60 public PortRange()
61 {
62 }
63
64 /***
65 * Adds all ports that are <code>first</code> <= port <= <code>last</code>.
66 */
67 public void add(int first, int last)
68 {
69 if (first < MIN_PORT || first > MAX_PORT) {
70 throw new IllegalArgumentException();
71 }
72 if (last < MIN_PORT || last > MAX_PORT) {
73 throw new IllegalArgumentException();
74 }
75 if (first > last) {
76 throw new IllegalArgumentException("first must be smaller than or equal to last (" + first + ">" + last + ")");
77 }
78
79 for (int i = first; i <= last; i++) {
80 list.add(i);
81 }
82 }
83
84 /***
85 * Adds <code>port</code> to the range.
86 */
87 public void add(int port)
88 {
89 if (port < MIN_PORT || port > MAX_PORT) {
90 throw new IllegalArgumentException();
91 }
92
93 list.add(new Integer(port));
94 }
95
96 /***
97 * Adds a range as a string.
98 *
99 * @see PortRangeValidator
100 */
101 public void add(String range)
102 {
103 StringTokenizer t = new StringTokenizer(range, ";");
104 while (t.hasMoreTokens()) {
105 String ports = t.nextToken().trim();
106
107 if (ports.length() == 0) {
108 continue;
109 }
110
111 try {
112 if (ports.indexOf("-") != -1) {
113 StringTokenizer u = new StringTokenizer(ports, "-");
114 if (u.countTokens() == 2) {
115 add(Integer.parseInt(u.nextToken()),
116 Integer.parseInt(u.nextToken()));
117 }
118 }
119 else {
120 add(Integer.parseInt(ports));
121 }
122 }
123 catch (NumberFormatException e) {
124 }
125 }
126 }
127
128 /***
129 * Tries to bind random ports from the range and returns the
130 * {@link ServerSocket} object if successful.
131 *
132 * @return null, if no port could be bound
133 */
134 public ServerSocket bindRandom()
135 {
136
137 for (Iterator<Integer> it = randomIterator(); it.hasNext();) {
138 try {
139 return new ServerSocket(it.next());
140 }
141 catch (IOException e) {
142 }
143 }
144
145 return null;
146 }
147
148 /***
149 * Returns true, if port is in the range.
150 */
151 public boolean contains(int port)
152 {
153 return list.contains(new Integer(port));
154 }
155
156 /***
157 * Returns a random port from the range.
158 *
159 * @param defaultPort a default port
160 * @return default, if range is empty
161 */
162 public int getRandom(int defaultPort)
163 {
164 if (size() > 0) {
165 List<Integer> copy = new ArrayList<Integer>(list);
166 int index = (new Random()).nextInt(copy.size());
167 return copy.get(index);
168 }
169
170 return defaultPort;
171 }
172
173 /***
174 * Returns an iterator over all contained ports.
175 */
176 public Iterator<Integer> iterator()
177 {
178 return list.iterator();
179 }
180
181 /***
182 * Returns an iterator over a shuffeled instance.
183 */
184 public Iterator<Integer> randomIterator()
185 {
186 List<Integer> copy = new ArrayList<Integer>(list);
187 Collections.shuffle(copy);
188 return copy.iterator();
189 }
190
191 /***
192 * Returns the number of ports.
193 */
194 public int size()
195 {
196 return list.size();
197 }
198
199 /***
200 * Returns an ordered string representation.
201 */
202 public String toString()
203 {
204 StringBuilder sb = new StringBuilder();
205
206 List<Integer> copy = new ArrayList<Integer>(list);
207 Collections.sort(copy);
208
209 int start = 0;
210 int last = -1;
211 for (Iterator<Integer> it = copy.iterator(); it.hasNext();) {
212 int current = it.next();
213 if (last == -1) {
214 start = current;
215 }
216 else if (current - last > 1) {
217 sb.append(start);
218 if (start != last) {
219 sb.append("-");
220 sb.append(last);
221 }
222 sb.append(";");
223 start = current;
224 }
225 last = current;
226 }
227
228 if (last != -1) {
229 sb.append(start);
230 if (start != last) {
231 sb.append("-");
232 sb.append(last);
233 }
234 sb.append(";");
235 }
236
237
238 return (sb.length() > 0) ? sb.substring(0, sb.length() - 1) : "";
239 }
240
241 }
242
243