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