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(Iterable<? extends SocketAddress> localAddresses) throws IOException {
246 if (isDisposing()) {
247 throw new IllegalStateException("Already disposed.");
248 }
249
250 if (localAddresses == null) {
251 throw new IllegalArgumentException("localAddresses");
252 }
253
254 List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
255
256 for (SocketAddress a : localAddresses) {
257 checkAddressType(a);
258 localAddressesCopy.add(a);
259 }
260
261 if (localAddressesCopy.isEmpty()) {
262 throw new IllegalArgumentException("localAddresses is empty.");
263 }
264
265 boolean activate = false;
266 synchronized (bindLock) {
267 synchronized (boundAddresses) {
268 if (boundAddresses.isEmpty()) {
269 activate = true;
270 }
271 }
272
273 if (getHandler() == null) {
274 throw new IllegalStateException("handler is not set.");
275 }
276
277 try {
278 Set<SocketAddress> addresses = bindInternal(localAddressesCopy);
279
280 synchronized (boundAddresses) {
281 boundAddresses.addAll(addresses);
282 }
283 } catch (IOException e) {
284 throw e;
285 } catch (RuntimeException e) {
286 throw e;
287 } catch (Throwable e) {
288 throw new RuntimeIoException("Failed to bind to: " + getLocalAddresses(), e);
289 }
290 }
291
292 if (activate) {
293 getListeners().fireServiceActivated();
294 }
295 }
296
297
298
299
300 public final void unbind() {
301 unbind(getLocalAddresses());
302 }
303
304
305
306
307 public final void unbind(SocketAddress localAddress) {
308 if (localAddress == null) {
309 throw new IllegalArgumentException("localAddress");
310 }
311
312 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(1);
313 localAddresses.add(localAddress);
314 unbind(localAddresses);
315 }
316
317
318
319
320 public final void unbind(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) {
321 if (firstLocalAddress == null) {
322 throw new IllegalArgumentException("firstLocalAddress");
323 }
324 if (otherLocalAddresses == null) {
325 throw new IllegalArgumentException("otherLocalAddresses");
326 }
327
328 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>();
329 localAddresses.add(firstLocalAddress);
330 Collections.addAll(localAddresses, otherLocalAddresses);
331 unbind(localAddresses);
332 }
333
334
335
336
337 public final void unbind(Iterable<? extends SocketAddress> localAddresses) {
338 if (localAddresses == null) {
339 throw new IllegalArgumentException("localAddresses");
340 }
341
342 boolean deactivate = false;
343 synchronized (bindLock) {
344 synchronized (boundAddresses) {
345 if (boundAddresses.isEmpty()) {
346 return;
347 }
348
349 List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
350 int specifiedAddressCount = 0;
351
352 for (SocketAddress a : localAddresses) {
353 specifiedAddressCount++;
354
355 if ((a != null) && boundAddresses.contains(a)) {
356 localAddressesCopy.add(a);
357 }
358 }
359
360 if (specifiedAddressCount == 0) {
361 throw new IllegalArgumentException("localAddresses is empty.");
362 }
363
364 if (!localAddressesCopy.isEmpty()) {
365 try {
366 unbind0(localAddressesCopy);
367 } catch (RuntimeException e) {
368 throw e;
369 } catch (Throwable e) {
370 throw new RuntimeIoException("Failed to unbind from: " + getLocalAddresses(), e);
371 }
372
373 boundAddresses.removeAll(localAddressesCopy);
374
375 if (boundAddresses.isEmpty()) {
376 deactivate = true;
377 }
378 }
379 }
380 }
381
382 if (deactivate) {
383 getListeners().fireServiceDeactivated();
384 }
385 }
386
387
388
389
390
391 protected abstract Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception;
392
393
394
395
396 protected abstract void unbind0(List<? extends SocketAddress> localAddresses) throws Exception;
397
398 @Override
399 public String toString() {
400 TransportMetadata m = getTransportMetadata();
401 return '('
402 + m.getProviderName()
403 + ' '
404 + m.getName()
405 + " acceptor: "
406 + (isActive() ? "localAddress(es): " + getLocalAddresses() + ", managedSessionCount: "
407 + getManagedSessionCount() : "not bound") + ')';
408 }
409
410 private void checkAddressType(SocketAddress a) {
411 if (a != null && !getTransportMetadata().getAddressType().isAssignableFrom(a.getClass())) {
412 throw new IllegalArgumentException("localAddress type: " + a.getClass().getSimpleName() + " (expected: "
413 + getTransportMetadata().getAddressType().getSimpleName() + ")");
414 }
415 }
416
417 public static class AcceptorOperationFuture extends ServiceOperationFuture {
418 private final List<SocketAddress> localAddresses;
419
420 public AcceptorOperationFuture(List<? extends SocketAddress> localAddresses) {
421 this.localAddresses = new ArrayList<SocketAddress>(localAddresses);
422 }
423
424 public final List<SocketAddress> getLocalAddresses() {
425 return Collections.unmodifiableList(localAddresses);
426 }
427
428
429
430
431 public String toString() {
432 StringBuilder sb = new StringBuilder();
433
434 sb.append("Acceptor operation : ");
435
436 if (localAddresses != null) {
437 boolean isFirst = true;
438
439 for (SocketAddress address : localAddresses) {
440 if (isFirst) {
441 isFirst = false;
442 } else {
443 sb.append(", ");
444 }
445
446 sb.append(address);
447 }
448 }
449 return sb.toString();
450 }
451 }
452 }