1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.common;
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
31
32
33
34
35
36
37
38 public abstract class AbstractIoAcceptor
39 extends AbstractIoService implements IoAcceptor {
40
41 private final List<SocketAddress> defaultLocalAddresses =
42 new ArrayList<SocketAddress>();
43 private final List<SocketAddress> unmodifiableDefaultLocalAddresses =
44 Collections.unmodifiableList(defaultLocalAddresses);
45 private final Set<SocketAddress> boundAddresses =
46 new HashSet<SocketAddress>();
47
48 private boolean disconnectOnUnbind = true;
49
50
51
52
53
54
55 protected final Object bindLock = new Object();
56
57 protected AbstractIoAcceptor(IoSessionConfig sessionConfig) {
58 super(sessionConfig);
59 defaultLocalAddresses.add(null);
60 }
61
62 public SocketAddress getLocalAddress() {
63 Set<SocketAddress> localAddresses = getLocalAddresses();
64 if (localAddresses.isEmpty()) {
65 return null;
66 } else {
67 return localAddresses.iterator().next();
68 }
69 }
70
71 public final Set<SocketAddress> getLocalAddresses() {
72 Set<SocketAddress> localAddresses = new HashSet<SocketAddress>();
73 synchronized (bindLock) {
74 localAddresses.addAll(boundAddresses);
75 }
76 return localAddresses;
77 }
78
79 public SocketAddress getDefaultLocalAddress() {
80 if (defaultLocalAddresses.isEmpty()) {
81 return null;
82 }
83 return defaultLocalAddresses.iterator().next();
84 }
85
86 public final void setDefaultLocalAddress(SocketAddress localAddress) {
87 setDefaultLocalAddresses(localAddress);
88 }
89
90 public final List<SocketAddress> getDefaultLocalAddresses() {
91 return unmodifiableDefaultLocalAddresses;
92 }
93
94 public final void setDefaultLocalAddresses(List<? extends SocketAddress> localAddresses) {
95 if (localAddresses == null) {
96 throw new NullPointerException("localAddresses");
97 }
98 setDefaultLocalAddresses((Iterable<? extends SocketAddress>) localAddresses);
99 }
100
101 public final void setDefaultLocalAddresses(Iterable<? extends SocketAddress> localAddresses) {
102 if (localAddresses == null) {
103 throw new NullPointerException("localAddresses");
104 }
105
106 synchronized (bindLock) {
107 if (!boundAddresses.isEmpty()) {
108 throw new IllegalStateException(
109 "localAddress can't be set while the acceptor is bound.");
110 }
111
112 Collection<SocketAddress> newLocalAddresses =
113 new ArrayList<SocketAddress>();
114 for (SocketAddress a: localAddresses) {
115 checkAddressType(a);
116 newLocalAddresses.add(a);
117 }
118
119 if (newLocalAddresses.isEmpty()) {
120 throw new IllegalArgumentException("empty localAddresses");
121 }
122
123 this.defaultLocalAddresses.clear();
124 this.defaultLocalAddresses.addAll(newLocalAddresses);
125 }
126 }
127
128 public final void setDefaultLocalAddresses(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) {
129 if (otherLocalAddresses == null) {
130 otherLocalAddresses = new SocketAddress[0];
131 }
132
133 Collection<SocketAddress> newLocalAddresses =
134 new ArrayList<SocketAddress>(otherLocalAddresses.length + 1);
135
136 newLocalAddresses.add(firstLocalAddress);
137 for (SocketAddress a: otherLocalAddresses) {
138 newLocalAddresses.add(a);
139 }
140
141 setDefaultLocalAddresses(newLocalAddresses);
142 }
143
144 public final boolean isCloseOnDeactivation() {
145 return disconnectOnUnbind;
146 }
147
148 public final void setCloseOnDeactivation(boolean disconnectClientsOnUnbind) {
149 this.disconnectOnUnbind = disconnectClientsOnUnbind;
150 }
151
152 public final void bind() throws IOException {
153 bind(getDefaultLocalAddresses());
154 }
155
156 public final void bind(SocketAddress localAddress) throws IOException {
157 if (localAddress == null) {
158 throw new NullPointerException("localAddress");
159 }
160
161 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(1);
162 localAddresses.add(localAddress);
163 bind(localAddresses);
164 }
165
166 public final void bind(
167 SocketAddress firstLocalAddress,
168 SocketAddress... otherLocalAddresses) throws IOException {
169 if (firstLocalAddress == null) {
170 throw new NullPointerException("firstLocalAddress");
171 }
172 if (otherLocalAddresses == null) {
173 throw new NullPointerException("otherLocalAddresses");
174 }
175
176 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>();
177 localAddresses.add(firstLocalAddress);
178 Collections.addAll(localAddresses, otherLocalAddresses);
179 bind(localAddresses);
180 }
181
182 public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
183 if (isDisposing()) {
184 throw new IllegalStateException("Already disposed.");
185 }
186 if (localAddresses == null) {
187 throw new NullPointerException("localAddresses");
188 }
189
190 List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
191 for (SocketAddress a: localAddresses) {
192 checkAddressType(a);
193 localAddressesCopy.add(a);
194 }
195 if (localAddressesCopy.isEmpty()) {
196 throw new IllegalArgumentException("localAddresses is empty.");
197 }
198
199 boolean activate = false;
200 synchronized (bindLock) {
201 if (boundAddresses.isEmpty()) {
202 activate = true;
203 }
204
205 if (getHandler() == null) {
206 throw new IllegalStateException("handler is not set.");
207 }
208
209 try {
210 boundAddresses.addAll(bind0(localAddressesCopy));
211 } catch (IOException e) {
212 throw e;
213 } catch (RuntimeException e) {
214 throw e;
215 } catch (Throwable e) {
216 throw new RuntimeIoException(
217 "Failed to bind to: " + getLocalAddresses(), e);
218 }
219 }
220
221 if (activate) {
222 getListeners().fireServiceActivated();
223 }
224 }
225
226 public final void unbind() {
227 unbind(getLocalAddresses());
228 }
229
230 public final void unbind(SocketAddress localAddress) {
231 if (localAddress == null) {
232 throw new NullPointerException("localAddress");
233 }
234
235 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(1);
236 localAddresses.add(localAddress);
237 unbind(localAddresses);
238 }
239
240 public final void unbind(SocketAddress firstLocalAddress,
241 SocketAddress... otherLocalAddresses) {
242 if (firstLocalAddress == null) {
243 throw new NullPointerException("firstLocalAddress");
244 }
245 if (otherLocalAddresses == null) {
246 throw new NullPointerException("otherLocalAddresses");
247 }
248
249 List<SocketAddress> localAddresses = new ArrayList<SocketAddress>();
250 localAddresses.add(firstLocalAddress);
251 Collections.addAll(localAddresses, otherLocalAddresses);
252 unbind(localAddresses);
253 }
254
255 public final void unbind(Iterable<? extends SocketAddress> localAddresses) {
256 if (localAddresses == null) {
257 throw new NullPointerException("localAddresses");
258 }
259
260 boolean deactivate = false;
261 synchronized (bindLock) {
262 if (boundAddresses.isEmpty()) {
263 return;
264 }
265
266 List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
267 int specifiedAddressCount = 0;
268 for (SocketAddress a: localAddresses) {
269 specifiedAddressCount ++;
270 if (a != null && boundAddresses.contains(a)) {
271 localAddressesCopy.add(a);
272 }
273 }
274 if (specifiedAddressCount == 0) {
275 throw new IllegalArgumentException("localAddresses is empty.");
276 }
277
278 if (!localAddressesCopy.isEmpty()) {
279 try {
280 unbind0(localAddressesCopy);
281 } catch (RuntimeException e) {
282 throw e;
283 } catch (Throwable e) {
284 throw new RuntimeIoException(
285 "Failed to unbind from: " + getLocalAddresses(), e);
286 }
287
288 boundAddresses.removeAll(localAddressesCopy);
289 if (boundAddresses.isEmpty()) {
290 deactivate = true;
291 }
292 }
293 }
294
295 if (deactivate) {
296 getListeners().fireServiceDeactivated();
297 }
298 }
299
300
301
302
303
304 protected abstract Set<SocketAddress> bind0(
305 List<? extends SocketAddress> localAddresses) throws Exception;
306
307
308
309
310 protected abstract void unbind0(
311 List<? extends SocketAddress> localAddresses) throws Exception;
312
313 @Override
314 public String toString() {
315 TransportMetadata m = getTransportMetadata();
316 return '(' + m.getProviderName() + ' ' + m.getName() + " acceptor: " +
317 (isActive()?
318 "localAddress(es): " + getLocalAddresses() +
319 ", managedSessionCount: " + getManagedSessionCount() :
320 "not bound") + ')';
321 }
322
323 private void checkAddressType(SocketAddress a) {
324 if (a != null &&
325 !getTransportMetadata().getAddressType().isAssignableFrom(
326 a.getClass())) {
327 throw new IllegalArgumentException("localAddress type: "
328 + a.getClass().getSimpleName() + " (expected: "
329 + getTransportMetadata().getAddressType().getSimpleName() + ")");
330 }
331 }
332
333 protected static class AcceptorOperationFuture extends ServiceOperationFuture {
334 private final List<SocketAddress> localAddresses;
335
336 public AcceptorOperationFuture(List<? extends SocketAddress> localAddresses) {
337 this.localAddresses = new ArrayList<SocketAddress>(localAddresses);
338 }
339
340 public final List<SocketAddress> getLocalAddresses() {
341 return Collections.unmodifiableList(localAddresses);
342 }
343 }
344 }