View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.channel;
17  
18  import io.netty5.bootstrap.Bootstrap;
19  import io.netty5.bootstrap.ServerBootstrap;
20  import io.netty5.util.internal.logging.InternalLogger;
21  import io.netty5.util.internal.logging.InternalLoggerFactory;
22  
23  /**
24   * A special {@link ChannelHandler} which offers an easy way to initialize a {@link Channel} once it was
25   * registered to its {@link EventLoop}.
26   *
27   * Implementations are most often used in the context of {@link Bootstrap#handler(ChannelHandler)} ,
28   * {@link ServerBootstrap#handler(ChannelHandler)} and {@link ServerBootstrap#childHandler(ChannelHandler)} to
29   * setup the {@link ChannelPipeline} of a {@link Channel}.
30   *
31   * <pre>
32   *
33   * public class MyChannelInitializer extends {@link ChannelInitializer} {
34   *     public void initChannel({@link Channel} channel) {
35   *         channel.pipeline().addLast("myHandler", new MyHandler());
36   *     }
37   * }
38   *
39   * {@link ServerBootstrap} bootstrap = ...;
40   * ...
41   * bootstrap.childHandler(new MyChannelInitializer());
42   * ...
43   * </pre>
44   * Be aware that this class is marked as {@link #isSharable()} and so the implementation must be safe to be re-used.
45   *
46   * @param <C>   A sub-type of {@link Channel}
47   */
48  public abstract class ChannelInitializer<C extends Channel> implements ChannelHandler {
49  
50      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);
51  
52      @Override
53      public boolean isSharable() {
54          return true;
55      }
56  
57      /**
58       * This method will be called once the {@link Channel} was registered. After the method returns this instance
59       * will be removed from the {@link ChannelPipeline} of the {@link Channel}.
60       *
61       * @param ch            the {@link Channel} which was registered.
62       * @throws Exception    is thrown if an error occurs. In that case it will be handled by
63       *                      {@link #channelExceptionCaught(ChannelHandlerContext, Throwable)} which will by
64       *                      default close the {@link Channel}.
65       */
66      protected abstract void initChannel(C ch) throws Exception;
67  
68      /**
69       * Handle the {@link Throwable} by logging and closing the {@link Channel}. Sub-classes may override this.
70       */
71      @Override
72      public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
73          if (logger.isWarnEnabled()) {
74              logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), cause);
75          }
76          ctx.close();
77      }
78  
79      /**
80       * {@inheritDoc} If override this method ensure you call super!
81       */
82      @SuppressWarnings("unchecked")
83      @Override
84      public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
85          try {
86              initChannel((C) ctx.channel());
87          } catch (Throwable cause) {
88              // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
89              // We do so to prevent multiple calls to initChannel(...).
90              channelExceptionCaught(ctx, cause);
91          } finally {
92              if (!ctx.isRemoved()) {
93                  ctx.pipeline().remove(this);
94              }
95          }
96      }
97  }