1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.core.service;
21
22 import java.io.IOException;
23 import java.net.SocketAddress;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.concurrent.Executor;
31 import java.util.concurrent.Executors;
32
33 import org.apache.mina.core.RuntimeIoException;
34 import org.apache.mina.core.session.IoSession;
35 import org.apache.mina.core.session.IoSessionConfig;
36
37
38
39
40
41
42
43 public abstract class AbstractIoAcceptor extends AbstractIoService implements IoAcceptor {
44
45 private final List<SocketAddress> defaultLocalAddresses = new ArrayList<SocketAddress>();
46
47 private final List<SocketAddress> unmodifiableDefaultLocalAddresses = Collections
48 .unmodifiableList(defaultLocalAddresses);
49
50 private final Set<SocketAddress> boundAddresses = new HashSet<SocketAddress>();
51
52 private boolean disconnectOnUnbind = true;
53
54
55
56
57
58
59 protected final Object bindLock = new Object();
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 protected AbstractIoAcceptor(IoSessionConfig sessionConfig, Executor executor) {
76 super(sessionConfig, executor);
77 defaultLocalAddresses.add(null);
78 }
79
80
81
82
83 public SocketAddress getLocalAddress() {
84 Set<SocketAddress> localAddresses = getLocalAddresses();
85 if (localAddresses.isEmpty()) {
86 return null;
87 }
88
89 return localAddresses.iterator().next();
90 }
91
92
93
94
95 public final Set<SocketAddress> getLocalAddresses() {
96 Set<SocketAddress> localAddresses = new HashSet<SocketAddress>();
97
98 synchronized (boundAddresses) {
99 localAddresses.addAll(boundAddresses);
100 }
101
102 return localAddresses;
103 }
104
105
106
107
108 public SocketAddress getDefaultLocalAddress() {
109 if (defaultLocalAddresses.isEmpty()) {
110 return null;
111 }
112 return defaultLocalAddresses.iterator().next();
113 }
114
115
116
117
118 public final void setDefaultLocalAddress(SocketAddress localAddress) {
119 setDefaultLocalAddresses(localAddress);
120 }
121
122
123
124
125 public final List<SocketAddress> getDefaultLocalAddresses() {
126 return unmodifiableDefaultLocalAddresses;
127 }
128
129
130
131
132
133 public final void setDefaultLocalAddresses(List<? extends SocketAddress> localAddresses) {
134 if (localAddresses == null) {
135 throw new IllegalArgumentException("localAddresses");
136 }
137 setDefaultLocalAddresses((Iterable<? extends SocketAddress>) localAddresses);
138 }
139
140
141
142
143 public final void setDefaultLocalAddresses(Iterable<? extends SocketAddress> localAddresses) {
144 if (localAddresses == null) {
145 throw new IllegalArgumentException("localAddresses");
146 }
147
148 synchronized (bindLock) {
149 synchronized (boundAddresses) {
150 if (!boundAddresses.isEmpty()) {
151 throw new IllegalStateException("localAddress can't be set while the acceptor is bound.");
152 }
153
154 Collection<SocketAddress> newLocalAddresses = new ArrayList<SocketAddress>();
155
156 for (SocketAddress a : localAddresses) {
157 checkAddressType(a);
158 newLocalAddresses.add(a);
159 }
160
161 if (newLocalAddresses.isEmpty()) {
162 throw new IllegalArgumentException("empty localAddresses");
163 }
164
165 this.defaultLocalAddresses.clear();
166 this.defaultLocalAddresses.addAll(newLocalAddresses);
167 }
168 }
169 }
170
171
172
173
174
175 public final void setDefaultLocalAddresses(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) {
176 if (otherLocalAddresses == null) {
177 otherLocalAddresses = new SocketAddress[0];
178 }
179
180 Collection<SocketAddress> newLocalAddresses = new ArrayList<SocketAddress>(otherLocalAddresses.length + 1);
181
182 newLocalAddresses.add(firstLocalAddress);
183 for (SocketAddress a : otherLocalAddresses) {
184 newLocalAddresses.add(a);
185 }
186
187 setDefaultLocalAddresses(newLocalAddresses);
188 }
189
190
191
192
193 public final boolean isCloseOnDeactivation() {
194 return disconnectOnUnbind;
195 }
196
197
198
199
200 public final void setCloseOnDeactivation(boolean disconnectClientsOnUnbind) {
201 this.disconnectOnUnbind = disconnectClientsOnUnbind;
202 }
203
204
205
206
207 public final void bind() throws IOException {
208 bind(getDefaultLocalAddresses());
209 }
210
211
212
213
214 public final void bind(SocketAddress localAddress) throws IOException {
215 if (localAddress == null) {
216 throw new IllegalArgumentException("localAddress");
217 }
218
219 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(1);
220 localAddresses.add(localAddress);
221 bind(localAddresses);
222 }
223
224
225
226
227 public final void bind(SocketAddress... addresses) throws IOException {
228 if ((addresses == null) || (addresses.length == 0)) {
229 bind(getDefaultLocalAddresses());
230 return;
231 }
232
233 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(2);
234
235 for (SocketAddress address : addresses) {
236 localAddresses.add(address);
237 }
238
239 bind(localAddresses);
240 }
241
242
243
244
245 public final void bind(SocketAddress firstLocalAddress, SocketAddress... addresses) throws IOException {
246 if (firstLocalAddress == null) {
247 bind(getDefaultLocalAddresses());
248 }
249
250 if ((addresses == null) || (addresses.length == 0)) {
251 bind(getDefaultLocalAddresses());
252 return;
253 }
254
255 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(2);
256 localAddresses.add(firstLocalAddress);
257
258 for (SocketAddress address : addresses) {
259 localAddresses.add(address);
260 }
261
262 bind(localAddresses);
263 }
264
265
266
267
268 public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
269 if (isDisposing()) {
270 throw new IllegalStateException("Already disposed.");
271 }
272
273 if (localAddresses == null) {
274 throw new IllegalArgumentException("localAddresses");
275 }
276
277 List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
278
279 for (SocketAddress a : localAddresses) {
280 checkAddressType(a);
281 localAddressesCopy.add(a);
282 }
283
284 if (localAddressesCopy.isEmpty()) {
285 throw new IllegalArgumentException("localAddresses is empty.");
286 }
287
288 boolean activate = false;
289 synchronized (bindLock) {
290 synchronized (boundAddresses) {
291 if (boundAddresses.isEmpty()) {
292 activate = true;
293 }
294 }
295
296 if (getHandler() == null) {
297 throw new IllegalStateException("handler is not set.");
298 }
299
300 try {
301 Set<SocketAddress> addresses = bindInternal(localAddressesCopy);
302
303 synchronized (boundAddresses) {
304 boundAddresses.addAll(addresses);
305 }
306 } catch (IOException e) {
307 throw e;
308 } catch (RuntimeException e) {
309 throw e;
310 } catch (Throwable e) {
311 throw new RuntimeIoException("Failed to bind to: " + getLocalAddresses(), e);
312 }
313 }
314
315 if (activate) {
316 getListeners().fireServiceActivated();
317 }
318 }
319
320
321
322
323 public final void unbind() {
324 unbind(getLocalAddresses());
325 }
326
327
328
329
330 public final void unbind(SocketAddress localAddress) {
331 if (localAddress == null) {
332 throw new IllegalArgumentException("localAddress");
333 }
334
335 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(1);
336 localAddresses.add(localAddress);
337 unbind(localAddresses);
338 }
339
340
341
342
343 public final void unbind(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) {
344 if (firstLocalAddress == null) {
345 throw new IllegalArgumentException("firstLocalAddress");
346 }
347 if (otherLocalAddresses == null) {
348 throw new IllegalArgumentException("otherLocalAddresses");
349 }
350
351 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>();
352 localAddresses.add(firstLocalAddress);
353 Collections.addAll(localAddresses, otherLocalAddresses);
354 unbind(localAddresses);
355 }
356
357
358
359
360 public final void unbind(Iterable<? extends SocketAddress> localAddresses) {
361 if (localAddresses == null) {
362 throw new IllegalArgumentException("localAddresses");
363 }
364
365 boolean deactivate = false;
366 synchronized (bindLock) {
367 synchronized (boundAddresses) {
368 if (boundAddresses.isEmpty()) {
369 return;
370 }
371
372 List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
373 int specifiedAddressCount = 0;
374
375 for (SocketAddress a : localAddresses) {
376 specifiedAddressCount++;
377
378 if ((a != null) && boundAddresses.contains(a)) {
379 localAddressesCopy.add(a);
380 }
381 }
382
383 if (specifiedAddressCount == 0) {
384 throw new IllegalArgumentException("localAddresses is empty.");
385 }
386
387 if (!localAddressesCopy.isEmpty()) {
388 try {
389 unbind0(localAddressesCopy);
390 } catch (RuntimeException e) {
391 throw e;
392 } catch (Throwable e) {
393 throw new RuntimeIoException("Failed to unbind from: " + getLocalAddresses(), e);
394 }
395
396 boundAddresses.removeAll(localAddressesCopy);
397
398 if (boundAddresses.isEmpty()) {
399 deactivate = true;
400 }
401 }
402 }
403 }
404
405 if (deactivate) {
406 getListeners().fireServiceDeactivated();
407 }
408 }
409
410
411
412
413
414 protected abstract Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception;
415
416
417
418
419 protected abstract void unbind0(List<? extends SocketAddress> localAddresses) throws Exception;
420
421 @Override
422 public String toString() {
423 TransportMetadata m = getTransportMetadata();
424 return '('
425 + m.getProviderName()
426 + ' '
427 + m.getName()
428 + " acceptor: "
429 + (isActive() ? "localAddress(es): " + getLocalAddresses() + ", managedSessionCount: "
430 + getManagedSessionCount() : "not bound") + ')';
431 }
432
433 private void checkAddressType(SocketAddress a) {
434 if (a != null && !getTransportMetadata().getAddressType().isAssignableFrom(a.getClass())) {
435 throw new IllegalArgumentException("localAddress type: " + a.getClass().getSimpleName() + " (expected: "
436 + getTransportMetadata().getAddressType().getSimpleName() + ")");
437 }
438 }
439
440 public static class AcceptorOperationFuture extends ServiceOperationFuture {
441 private final List<SocketAddress> localAddresses;
442
443 public AcceptorOperationFuture(List<? extends SocketAddress> localAddresses) {
444 this.localAddresses = new ArrayList<SocketAddress>(localAddresses);
445 }
446
447 public final List<SocketAddress> getLocalAddresses() {
448 return Collections.unmodifiableList(localAddresses);
449 }
450
451
452
453
454 public String toString() {
455 StringBuilder sb = new StringBuilder();
456
457 sb.append("Acceptor operation : ");
458
459 if (localAddresses != null) {
460 boolean isFirst = true;
461
462 for (SocketAddress address : localAddresses) {
463 if (isFirst) {
464 isFirst = false;
465 } else {
466 sb.append(", ");
467 }
468
469 sb.append(address);
470 }
471 }
472 return sb.toString();
473 }
474 }
475 }