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