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