1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.bootstrap;
18
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelException;
21 import io.netty.channel.ChannelFuture;
22 import io.netty.channel.ChannelFutureListener;
23 import io.netty.channel.ChannelHandler;
24 import io.netty.channel.ChannelOption;
25 import io.netty.channel.ChannelPromise;
26 import io.netty.channel.DefaultChannelPromise;
27 import io.netty.channel.EventLoop;
28 import io.netty.channel.EventLoopGroup;
29 import io.netty.util.internal.SocketUtils;
30 import io.netty.util.AttributeKey;
31 import io.netty.util.concurrent.EventExecutor;
32 import io.netty.util.concurrent.GlobalEventExecutor;
33 import io.netty.util.internal.StringUtil;
34 import io.netty.util.internal.logging.InternalLogger;
35
36 import java.net.InetAddress;
37 import java.net.InetSocketAddress;
38 import java.net.SocketAddress;
39 import java.util.LinkedHashMap;
40 import java.util.Map;
41
42
43
44
45
46
47
48
49 public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
50
51 volatile EventLoopGroup group;
52 private volatile ChannelFactory<? extends C> channelFactory;
53 private volatile SocketAddress localAddress;
54 private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
55 private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
56 private volatile ChannelHandler handler;
57
58 AbstractBootstrap() {
59
60 }
61
62 AbstractBootstrap(AbstractBootstrap<B, C> bootstrap) {
63 group = bootstrap.group;
64 channelFactory = bootstrap.channelFactory;
65 handler = bootstrap.handler;
66 localAddress = bootstrap.localAddress;
67 synchronized (bootstrap.options) {
68 options.putAll(bootstrap.options);
69 }
70 synchronized (bootstrap.attrs) {
71 attrs.putAll(bootstrap.attrs);
72 }
73 }
74
75
76
77
78
79 public B group(EventLoopGroup group) {
80 if (group == null) {
81 throw new NullPointerException("group");
82 }
83 if (this.group != null) {
84 throw new IllegalStateException("group set already");
85 }
86 this.group = group;
87 return self();
88 }
89
90 @SuppressWarnings("unchecked")
91 private B self() {
92 return (B) this;
93 }
94
95
96
97
98
99
100 public B channel(Class<? extends C> channelClass) {
101 if (channelClass == null) {
102 throw new NullPointerException("channelClass");
103 }
104 return channelFactory(new BootstrapChannelFactory<C>(channelClass));
105 }
106
107
108
109
110
111
112
113
114 public B channelFactory(ChannelFactory<? extends C> channelFactory) {
115 if (channelFactory == null) {
116 throw new NullPointerException("channelFactory");
117 }
118 if (this.channelFactory != null) {
119 throw new IllegalStateException("channelFactory set already");
120 }
121
122 this.channelFactory = channelFactory;
123 return self();
124 }
125
126
127
128
129
130 public B localAddress(SocketAddress localAddress) {
131 this.localAddress = localAddress;
132 return self();
133 }
134
135
136
137
138 public B localAddress(int inetPort) {
139 return localAddress(new InetSocketAddress(inetPort));
140 }
141
142
143
144
145 public B localAddress(String inetHost, int inetPort) {
146 return localAddress(SocketUtils.socketAddress(inetHost, inetPort));
147 }
148
149
150
151
152 public B localAddress(InetAddress inetHost, int inetPort) {
153 return localAddress(new InetSocketAddress(inetHost, inetPort));
154 }
155
156
157
158
159
160 public <T> B option(ChannelOption<T> option, T value) {
161 if (option == null) {
162 throw new NullPointerException("option");
163 }
164 if (value == null) {
165 synchronized (options) {
166 options.remove(option);
167 }
168 } else {
169 synchronized (options) {
170 options.put(option, value);
171 }
172 }
173 return self();
174 }
175
176
177
178
179
180 public <T> B attr(AttributeKey<T> key, T value) {
181 if (key == null) {
182 throw new NullPointerException("key");
183 }
184 if (value == null) {
185 synchronized (attrs) {
186 attrs.remove(key);
187 }
188 } else {
189 synchronized (attrs) {
190 attrs.put(key, value);
191 }
192 }
193 return self();
194 }
195
196
197
198
199
200 public B validate() {
201 if (group == null) {
202 throw new IllegalStateException("group not set");
203 }
204 if (channelFactory == null) {
205 throw new IllegalStateException("channel or channelFactory not set");
206 }
207 return self();
208 }
209
210
211
212
213
214
215 @Override
216 @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
217 public abstract B clone();
218
219
220
221
222 public ChannelFuture register() {
223 validate();
224 return initAndRegister();
225 }
226
227
228
229
230 public ChannelFuture bind() {
231 validate();
232 SocketAddress localAddress = this.localAddress;
233 if (localAddress == null) {
234 throw new IllegalStateException("localAddress not set");
235 }
236 return doBind(localAddress);
237 }
238
239
240
241
242 public ChannelFuture bind(int inetPort) {
243 return bind(new InetSocketAddress(inetPort));
244 }
245
246
247
248
249 public ChannelFuture bind(String inetHost, int inetPort) {
250 return bind(SocketUtils.socketAddress(inetHost, inetPort));
251 }
252
253
254
255
256 public ChannelFuture bind(InetAddress inetHost, int inetPort) {
257 return bind(new InetSocketAddress(inetHost, inetPort));
258 }
259
260
261
262
263 public ChannelFuture bind(SocketAddress localAddress) {
264 validate();
265 if (localAddress == null) {
266 throw new NullPointerException("localAddress");
267 }
268 return doBind(localAddress);
269 }
270
271 private ChannelFuture doBind(final SocketAddress localAddress) {
272 final ChannelFuture regFuture = initAndRegister();
273 final Channel channel = regFuture.channel();
274 if (regFuture.cause() != null) {
275 return regFuture;
276 }
277
278 if (regFuture.isDone()) {
279
280 ChannelPromise promise = channel.newPromise();
281 doBind0(regFuture, channel, localAddress, promise);
282 return promise;
283 } else {
284
285 final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
286 regFuture.addListener(new ChannelFutureListener() {
287 @Override
288 public void operationComplete(ChannelFuture future) throws Exception {
289 Throwable cause = future.cause();
290 if (cause != null) {
291
292
293 promise.setFailure(cause);
294 } else {
295
296
297 promise.executor = channel.eventLoop();
298
299 doBind0(regFuture, channel, localAddress, promise);
300 }
301 }
302 });
303 return promise;
304 }
305 }
306
307 final ChannelFuture initAndRegister() {
308 Channel channel = null;
309 try {
310 channel = channelFactory().newChannel();
311 init(channel);
312 } catch (Throwable t) {
313 if (channel != null) {
314
315 channel.unsafe().closeForcibly();
316
317 return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
318 }
319
320 return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
321 }
322
323 ChannelFuture regFuture = group().register(channel);
324 if (regFuture.cause() != null) {
325 if (channel.isRegistered()) {
326 channel.close();
327 } else {
328 channel.unsafe().closeForcibly();
329 }
330 }
331
332
333
334
335
336
337
338
339
340
341 return regFuture;
342 }
343
344 abstract void init(Channel channel) throws Exception;
345
346 private static void doBind0(
347 final ChannelFuture regFuture, final Channel channel,
348 final SocketAddress localAddress, final ChannelPromise promise) {
349
350
351
352 channel.eventLoop().execute(new Runnable() {
353 @Override
354 public void run() {
355 if (regFuture.isSuccess()) {
356 channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
357 } else {
358 promise.setFailure(regFuture.cause());
359 }
360 }
361 });
362 }
363
364
365
366
367 public B handler(ChannelHandler handler) {
368 if (handler == null) {
369 throw new NullPointerException("handler");
370 }
371 this.handler = handler;
372 return self();
373 }
374
375 final SocketAddress localAddress() {
376 return localAddress;
377 }
378
379 final ChannelFactory<? extends C> channelFactory() {
380 return channelFactory;
381 }
382
383 final ChannelHandler handler() {
384 return handler;
385 }
386
387
388
389
390 public EventLoopGroup group() {
391 return group;
392 }
393
394 final Map<ChannelOption<?>, Object> options() {
395 return options;
396 }
397
398 final Map<AttributeKey<?>, Object> attrs() {
399 return attrs;
400 }
401
402 static void setChannelOptions(
403 Channel channel, Map<ChannelOption<?>, Object> options, InternalLogger logger) {
404 for (Map.Entry<ChannelOption<?>, Object> e: options.entrySet()) {
405 setChannelOption(channel, e.getKey(), e.getValue(), logger);
406 }
407 }
408
409 static void setChannelOptions(
410 Channel channel, Map.Entry<ChannelOption<?>, Object>[] options, InternalLogger logger) {
411 for (Map.Entry<ChannelOption<?>, Object> e: options) {
412 setChannelOption(channel, e.getKey(), e.getValue(), logger);
413 }
414 }
415
416 @SuppressWarnings("unchecked")
417 private static void setChannelOption(
418 Channel channel, ChannelOption<?> option, Object value, InternalLogger logger) {
419 try {
420 if (!channel.config().setOption((ChannelOption<Object>) option, value)) {
421 logger.warn("Unknown channel option '{}' for channel '{}'", option, channel);
422 }
423 } catch (Throwable t) {
424 logger.warn(
425 "Failed to set channel option '{}' with value '{}' for channel '{}'", option, value, channel, t);
426 }
427 }
428
429 @Override
430 public String toString() {
431 StringBuilder buf = new StringBuilder()
432 .append(StringUtil.simpleClassName(this))
433 .append('(');
434 if (group != null) {
435 buf.append("group: ")
436 .append(StringUtil.simpleClassName(group))
437 .append(", ");
438 }
439 if (channelFactory != null) {
440 buf.append("channelFactory: ")
441 .append(channelFactory)
442 .append(", ");
443 }
444 if (localAddress != null) {
445 buf.append("localAddress: ")
446 .append(localAddress)
447 .append(", ");
448 }
449 synchronized (options) {
450 if (!options.isEmpty()) {
451 buf.append("options: ")
452 .append(options)
453 .append(", ");
454 }
455 }
456 synchronized (attrs) {
457 if (!attrs.isEmpty()) {
458 buf.append("attrs: ")
459 .append(attrs)
460 .append(", ");
461 }
462 }
463 if (handler != null) {
464 buf.append("handler: ")
465 .append(handler)
466 .append(", ");
467 }
468 if (buf.charAt(buf.length() - 1) == '(') {
469 buf.append(')');
470 } else {
471 buf.setCharAt(buf.length() - 2, ')');
472 buf.setLength(buf.length() - 1);
473 }
474 return buf.toString();
475 }
476
477 private static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> {
478 private final Class<? extends T> clazz;
479
480 BootstrapChannelFactory(Class<? extends T> clazz) {
481 this.clazz = clazz;
482 }
483
484 @Override
485 public T newChannel() {
486 try {
487 return clazz.getConstructor().newInstance();
488 } catch (Throwable t) {
489 throw new ChannelException("Unable to create Channel from class " + clazz, t);
490 }
491 }
492
493 @Override
494 public String toString() {
495 return StringUtil.simpleClassName(clazz) + ".class";
496 }
497 }
498
499 private static final class PendingRegistrationPromise extends DefaultChannelPromise {
500
501
502 private volatile EventExecutor executor;
503
504 private PendingRegistrationPromise(Channel channel) {
505 super(channel);
506 }
507
508 @Override
509 protected EventExecutor executor() {
510 EventExecutor executor = this.executor;
511 if (executor != null) {
512
513
514
515 return executor;
516 }
517
518 return GlobalEventExecutor.INSTANCE;
519 }
520 }
521 }