1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.bootstrap;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelConfig;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.ChannelFutureListener;
22 import io.netty.channel.ChannelHandler;
23 import io.netty.channel.ChannelHandlerContext;
24 import io.netty.channel.ChannelInboundHandlerAdapter;
25 import io.netty.channel.ChannelInitializer;
26 import io.netty.channel.ChannelOption;
27 import io.netty.channel.ChannelPipeline;
28 import io.netty.channel.EventLoopGroup;
29 import io.netty.channel.ServerChannel;
30 import io.netty.util.AttributeKey;
31 import io.netty.util.internal.ObjectUtil;
32 import io.netty.util.internal.logging.InternalLogger;
33 import io.netty.util.internal.logging.InternalLoggerFactory;
34
35 import java.util.Collection;
36 import java.util.LinkedHashMap;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.TimeUnit;
41
42
43
44
45
46 public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
47
48 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
49
50
51
52 private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
53 private final Map<AttributeKey<?>, Object> childAttrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
54 private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
55 private volatile EventLoopGroup childGroup;
56 private volatile ChannelHandler childHandler;
57
58 public ServerBootstrap() { }
59
60 private ServerBootstrap(ServerBootstrap bootstrap) {
61 super(bootstrap);
62 childGroup = bootstrap.childGroup;
63 childHandler = bootstrap.childHandler;
64 synchronized (bootstrap.childOptions) {
65 childOptions.putAll(bootstrap.childOptions);
66 }
67 childAttrs.putAll(bootstrap.childAttrs);
68 }
69
70
71
72
73 @Override
74 public ServerBootstrap group(EventLoopGroup group) {
75 return group(group, group);
76 }
77
78
79
80
81
82
83
84
85
86 public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
87 super.group(parentGroup);
88 if (this.childGroup != null) {
89 throw new IllegalStateException("childGroup set already");
90 }
91 this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
92 return this;
93 }
94
95
96
97
98
99
100 public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
101 ObjectUtil.checkNotNull(childOption, "childOption");
102 synchronized (childOptions) {
103 if (value == null) {
104 childOptions.remove(childOption);
105 } else {
106 childOptions.put(childOption, value);
107 }
108 }
109 return this;
110 }
111
112
113
114
115
116 public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
117 ObjectUtil.checkNotNull(childKey, "childKey");
118 if (value == null) {
119 childAttrs.remove(childKey);
120 } else {
121 childAttrs.put(childKey, value);
122 }
123 return this;
124 }
125
126
127
128
129 public ServerBootstrap childHandler(ChannelHandler childHandler) {
130 this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
131 return this;
132 }
133
134 @Override
135 void init(Channel channel) throws Throwable {
136 setChannelOptions(channel, newOptionsArray(), logger);
137 setAttributes(channel, newAttributesArray());
138
139 ChannelPipeline p = channel.pipeline();
140
141 final EventLoopGroup currentChildGroup = childGroup;
142 final ChannelHandler currentChildHandler = childHandler;
143 final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
144 final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
145 final Collection<ChannelInitializerExtension> extensions = getInitializerExtensions();
146
147 p.addLast(new ChannelInitializer<Channel>() {
148 @Override
149 public void initChannel(final Channel ch) {
150 final ChannelPipeline pipeline = ch.pipeline();
151 ChannelHandler handler = config.handler();
152 if (handler != null) {
153 pipeline.addLast(handler);
154 }
155
156 ch.eventLoop().execute(new Runnable() {
157 @Override
158 public void run() {
159 pipeline.addLast(new ServerBootstrapAcceptor(
160 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs,
161 extensions));
162 }
163 });
164 }
165 });
166 if (!extensions.isEmpty() && channel instanceof ServerChannel) {
167 ServerChannel serverChannel = (ServerChannel) channel;
168 for (ChannelInitializerExtension extension : extensions) {
169 try {
170 extension.postInitializeServerListenerChannel(serverChannel);
171 } catch (Exception e) {
172 logger.warn("Exception thrown from postInitializeServerListenerChannel", e);
173 }
174 }
175 }
176 }
177
178 @Override
179 public ServerBootstrap validate() {
180 super.validate();
181 if (childHandler == null) {
182 throw new IllegalStateException("childHandler not set");
183 }
184 if (childGroup == null) {
185 logger.warn("childGroup is not set. Using parentGroup instead.");
186 childGroup = config.group();
187 }
188 return this;
189 }
190
191 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
192
193 private final EventLoopGroup childGroup;
194 private final ChannelHandler childHandler;
195 private final Entry<ChannelOption<?>, Object>[] childOptions;
196 private final Entry<AttributeKey<?>, Object>[] childAttrs;
197 private final Runnable enableAutoReadTask;
198 private final Collection<ChannelInitializerExtension> extensions;
199
200 ServerBootstrapAcceptor(
201 final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
202 Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs,
203 Collection<ChannelInitializerExtension> extensions) {
204 this.childGroup = childGroup;
205 this.childHandler = childHandler;
206 this.childOptions = childOptions;
207 this.childAttrs = childAttrs;
208 this.extensions = extensions;
209
210
211
212
213
214
215 enableAutoReadTask = new Runnable() {
216 @Override
217 public void run() {
218 channel.config().setAutoRead(true);
219 }
220 };
221 }
222
223 @Override
224 @SuppressWarnings("unchecked")
225 public void channelRead(ChannelHandlerContext ctx, Object msg) {
226 final Channel child = (Channel) msg;
227
228 child.pipeline().addLast(childHandler);
229
230 try {
231 setChannelOptions(child, childOptions, logger);
232 } catch (Throwable cause) {
233 forceClose(child, cause);
234 return;
235 }
236 setAttributes(child, childAttrs);
237
238 if (!extensions.isEmpty()) {
239 for (ChannelInitializerExtension extension : extensions) {
240 try {
241 extension.postInitializeServerChildChannel(child);
242 } catch (Exception e) {
243 logger.warn("Exception thrown from postInitializeServerChildChannel", e);
244 }
245 }
246 }
247
248 try {
249 childGroup.register(child).addListener(new ChannelFutureListener() {
250 @Override
251 public void operationComplete(ChannelFuture future) throws Exception {
252 if (!future.isSuccess()) {
253 forceClose(child, future.cause());
254 }
255 }
256 });
257 } catch (Throwable t) {
258 forceClose(child, t);
259 }
260 }
261
262 private static void forceClose(Channel child, Throwable t) {
263 child.unsafe().closeForcibly();
264 logger.warn("Failed to register an accepted channel: {}", child, t);
265 }
266
267 @Override
268 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
269 final ChannelConfig config = ctx.channel().config();
270 if (config.isAutoRead()) {
271
272
273 config.setAutoRead(false);
274 ctx.channel().eventLoop().schedule(enableAutoReadTask, 1, TimeUnit.SECONDS);
275 }
276
277
278 ctx.fireExceptionCaught(cause);
279 }
280 }
281
282 @Override
283 @SuppressWarnings("CloneDoesntCallSuperClone")
284 public ServerBootstrap clone() {
285 return new ServerBootstrap(this);
286 }
287
288
289
290
291
292
293
294 @Deprecated
295 public EventLoopGroup childGroup() {
296 return childGroup;
297 }
298
299 final ChannelHandler childHandler() {
300 return childHandler;
301 }
302
303 final Map<ChannelOption<?>, Object> childOptions() {
304 synchronized (childOptions) {
305 return copiedMap(childOptions);
306 }
307 }
308
309 final Map<AttributeKey<?>, Object> childAttrs() {
310 return copiedMap(childAttrs);
311 }
312
313 @Override
314 public final ServerBootstrapConfig config() {
315 return config;
316 }
317 }