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