1
16
17 package io.netty.bootstrap;
18
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.ChannelFutureListener;
22 import io.netty.channel.ChannelHandler;
23 import io.netty.channel.ChannelOption;
24 import io.netty.channel.ChannelPromise;
25 import io.netty.channel.DefaultChannelPromise;
26 import io.netty.channel.EventLoop;
27 import io.netty.channel.EventLoopGroup;
28 import io.netty.channel.ReflectiveChannelFactory;
29 import io.netty.util.AttributeKey;
30 import io.netty.util.concurrent.EventExecutor;
31 import io.netty.util.concurrent.GlobalEventExecutor;
32 import io.netty.util.internal.ObjectUtil;
33 import io.netty.util.internal.SocketUtils;
34 import io.netty.util.internal.StringUtil;
35 import io.netty.util.internal.logging.InternalLogger;
36
37 import java.net.InetAddress;
38 import java.net.InetSocketAddress;
39 import java.net.SocketAddress;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.LinkedHashMap;
43 import java.util.Map;
44 import java.util.concurrent.ConcurrentHashMap;
45
46
53 public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
54 @SuppressWarnings("unchecked")
55 static final Map.Entry<ChannelOption<?>, Object>[] EMPTY_OPTION_ARRAY = new Map.Entry[0];
56 @SuppressWarnings("unchecked")
57 static final Map.Entry<AttributeKey<?>, Object>[] EMPTY_ATTRIBUTE_ARRAY = new Map.Entry[0];
58
59 volatile EventLoopGroup group;
60 @SuppressWarnings("deprecation")
61 private volatile ChannelFactory<? extends C> channelFactory;
62 private volatile SocketAddress localAddress;
63
64
65
66 private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
67 private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
68 private volatile ChannelHandler handler;
69
70 AbstractBootstrap() {
71
72 }
73
74 AbstractBootstrap(AbstractBootstrap<B, C> bootstrap) {
75 group = bootstrap.group;
76 channelFactory = bootstrap.channelFactory;
77 handler = bootstrap.handler;
78 localAddress = bootstrap.localAddress;
79 synchronized (bootstrap.options) {
80 options.putAll(bootstrap.options);
81 }
82 attrs.putAll(bootstrap.attrs);
83 }
84
85
89 public B group(EventLoopGroup group) {
90 ObjectUtil.checkNotNull(group, "group");
91 if (this.group != null) {
92 throw new IllegalStateException("group set already");
93 }
94 this.group = group;
95 return self();
96 }
97
98 @SuppressWarnings("unchecked")
99 private B self() {
100 return (B) this;
101 }
102
103
108 public B channel(Class<? extends C> channelClass) {
109 return channelFactory(new ReflectiveChannelFactory<C>(
110 ObjectUtil.checkNotNull(channelClass, "channelClass")
111 ));
112 }
113
114
117 @Deprecated
118 public B channelFactory(ChannelFactory<? extends C> channelFactory) {
119 ObjectUtil.checkNotNull(channelFactory, "channelFactory");
120 if (this.channelFactory != null) {
121 throw new IllegalStateException("channelFactory set already");
122 }
123
124 this.channelFactory = channelFactory;
125 return self();
126 }
127
128
135 @SuppressWarnings({ "unchecked", "deprecation" })
136 public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
137 return channelFactory((ChannelFactory<C>) channelFactory);
138 }
139
140
143 public B localAddress(SocketAddress localAddress) {
144 this.localAddress = localAddress;
145 return self();
146 }
147
148
151 public B localAddress(int inetPort) {
152 return localAddress(new InetSocketAddress(inetPort));
153 }
154
155
158 public B localAddress(String inetHost, int inetPort) {
159 return localAddress(SocketUtils.socketAddress(inetHost, inetPort));
160 }
161
162
165 public B localAddress(InetAddress inetHost, int inetPort) {
166 return localAddress(new InetSocketAddress(inetHost, inetPort));
167 }
168
169
173 public <T> B option(ChannelOption<T> option, T value) {
174 ObjectUtil.checkNotNull(option, "option");
175 synchronized (options) {
176 if (value == null) {
177 options.remove(option);
178 } else {
179 options.put(option, value);
180 }
181 }
182 return self();
183 }
184
185
189 public <T> B attr(AttributeKey<T> key, T value) {
190 ObjectUtil.checkNotNull(key, "key");
191 if (value == null) {
192 attrs.remove(key);
193 } else {
194 attrs.put(key, value);
195 }
196 return self();
197 }
198
199
203 public B validate() {
204 if (group == null) {
205 throw new IllegalStateException("group not set");
206 }
207 if (channelFactory == null) {
208 throw new IllegalStateException("channel or channelFactory not set");
209 }
210 return self();
211 }
212
213
218 @Override
219 @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
220 public abstract B clone();
221
222
225 public ChannelFuture register() {
226 validate();
227 return initAndRegister();
228 }
229
230
233 public ChannelFuture bind() {
234 validate();
235 SocketAddress localAddress = this.localAddress;
236 if (localAddress == null) {
237 throw new IllegalStateException("localAddress not set");
238 }
239 return doBind(localAddress);
240 }
241
242
245 public ChannelFuture bind(int inetPort) {
246 return bind(new InetSocketAddress(inetPort));
247 }
248
249
252 public ChannelFuture bind(String inetHost, int inetPort) {
253 return bind(SocketUtils.socketAddress(inetHost, inetPort));
254 }
255
256
259 public ChannelFuture bind(InetAddress inetHost, int inetPort) {
260 return bind(new InetSocketAddress(inetHost, inetPort));
261 }
262
263
266 public ChannelFuture bind(SocketAddress localAddress) {
267 validate();
268 return doBind(ObjectUtil.checkNotNull(localAddress, "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.registered();
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 = config().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
367 public B handler(ChannelHandler handler) {
368 this.handler = ObjectUtil.checkNotNull(handler, "handler");
369 return self();
370 }
371
372
377 @Deprecated
378 public final EventLoopGroup group() {
379 return group;
380 }
381
382
386 public abstract AbstractBootstrapConfig<B, C> config();
387
388 final Map.Entry<ChannelOption<?>, Object>[] newOptionsArray() {
389 synchronized (options) {
390 return options.entrySet().toArray(EMPTY_OPTION_ARRAY);
391 }
392 }
393
394 final Map<ChannelOption<?>, Object> options0() {
395 return options;
396 }
397
398 final Map<AttributeKey<?>, Object> attrs0() {
399 return attrs;
400 }
401
402 final SocketAddress localAddress() {
403 return localAddress;
404 }
405
406 @SuppressWarnings("deprecation")
407 final ChannelFactory<? extends C> channelFactory() {
408 return channelFactory;
409 }
410
411 final ChannelHandler handler() {
412 return handler;
413 }
414
415 final Map<ChannelOption<?>, Object> options() {
416 synchronized (options) {
417 return copiedMap(options);
418 }
419 }
420
421 final Map<AttributeKey<?>, Object> attrs() {
422 return copiedMap(attrs);
423 }
424
425 static <K, V> Map<K, V> copiedMap(Map<K, V> map) {
426 if (map.isEmpty()) {
427 return Collections.emptyMap();
428 }
429 return Collections.unmodifiableMap(new HashMap<K, V>(map));
430 }
431
432 static void setAttributes(Channel channel, Map.Entry<AttributeKey<?>, Object>[] attrs) {
433 for (Map.Entry<AttributeKey<?>, Object> e: attrs) {
434 @SuppressWarnings("unchecked")
435 AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
436 channel.attr(key).set(e.getValue());
437 }
438 }
439
440 static void setChannelOptions(
441 Channel channel, Map.Entry<ChannelOption<?>, Object>[] options, InternalLogger logger) {
442 for (Map.Entry<ChannelOption<?>, Object> e: options) {
443 setChannelOption(channel, e.getKey(), e.getValue(), logger);
444 }
445 }
446
447 @SuppressWarnings("unchecked")
448 private static void setChannelOption(
449 Channel channel, ChannelOption<?> option, Object value, InternalLogger logger) {
450 try {
451 if (!channel.config().setOption((ChannelOption<Object>) option, value)) {
452 logger.warn("Unknown channel option '{}' for channel '{}'", option, channel);
453 }
454 } catch (Throwable t) {
455 logger.warn(
456 "Failed to set channel option '{}' with value '{}' for channel '{}'", option, value, channel, t);
457 }
458 }
459
460 @Override
461 public String toString() {
462 StringBuilder buf = new StringBuilder()
463 .append(StringUtil.simpleClassName(this))
464 .append('(').append(config()).append(')');
465 return buf.toString();
466 }
467
468 static final class PendingRegistrationPromise extends DefaultChannelPromise {
469
470
471
472 private volatile boolean registered;
473
474 PendingRegistrationPromise(Channel channel) {
475 super(channel);
476 }
477
478 void registered() {
479 registered = true;
480 }
481
482 @Override
483 protected EventExecutor executor() {
484 if (registered) {
485
486
487
488 return super.executor();
489 }
490
491 return GlobalEventExecutor.INSTANCE;
492 }
493 }
494 }
495