View Javadoc
1   /*
2    * Copyright 2018 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.util.Resource;
19  import io.netty5.util.internal.TypeParameterMatcher;
20  
21  /**
22   * {@link ChannelHandler} which allows to conveniently only handle a specific type of user events.
23   *
24   * For example, here is an implementation which only handle {@link String} user events.
25   *
26   * <pre>
27   *     public class StringEventHandler extends
28   *             {@link SimpleUserEventChannelHandler}&lt;{@link String}&gt; {
29   *
30   *         {@code @Override}
31   *         protected void eventReceived({@link ChannelHandlerContext} ctx, {@link String} evt)
32   *                 throws {@link Exception} {
33   *             System.out.println(evt);
34   *         }
35   *     }
36   * </pre>
37   *
38   * Be aware that depending of the constructor parameters it will release all handled events by passing them to
39   * {@link Resource#dispose(Object)}.
40   */
41  public abstract class SimpleUserEventChannelHandler<I> implements ChannelHandler {
42  
43      private final TypeParameterMatcher matcher;
44      private final boolean autoRelease;
45  
46      /**
47       * see {@link #SimpleUserEventChannelHandler(boolean)} with {@code true} as boolean parameter.
48       */
49      protected SimpleUserEventChannelHandler() {
50          this(true);
51      }
52  
53      /**
54       * Create a new instance which will try to detect the types to match out of the type parameter of the class.
55       *
56       * @param autoRelease   {@code true} if handled events should be released automatically by passing them to
57       *                      {@link Resource#dispose(Object)}.
58       */
59      protected SimpleUserEventChannelHandler(boolean autoRelease) {
60          matcher = TypeParameterMatcher.find(this, SimpleUserEventChannelHandler.class, "I");
61          this.autoRelease = autoRelease;
62      }
63  
64      /**
65       * see {@link #SimpleUserEventChannelHandler(Class, boolean)} with {@code true} as boolean value.
66       */
67      protected SimpleUserEventChannelHandler(Class<? extends I> eventType) {
68          this(eventType, true);
69      }
70  
71      /**
72       * Create a new instance
73       *
74       * @param eventType      The type of events to match
75       * @param autoRelease    {@code true} if handled events should be released automatically by passing them to
76       *                       {@link Resource#dispose(Object)}.
77       */
78      protected SimpleUserEventChannelHandler(Class<? extends I> eventType, boolean autoRelease) {
79          matcher = TypeParameterMatcher.get(eventType);
80          this.autoRelease = autoRelease;
81      }
82  
83      /**
84       * Returns {@code true} if the given user event should be handled. If {@code false} it will be passed to the next
85       * {@link ChannelHandler} in the {@link ChannelPipeline}.
86       */
87      protected boolean acceptEvent(Object evt) throws Exception {
88          return matcher.match(evt);
89      }
90  
91      @Override
92      public final void channelInboundEvent(ChannelHandlerContext ctx, Object evt) throws Exception {
93          boolean release = true;
94          try {
95              if (acceptEvent(evt)) {
96                  @SuppressWarnings("unchecked")
97                  I ievt = (I) evt;
98                  eventReceived(ctx, ievt);
99              } else {
100                 release = false;
101                 ctx.fireChannelInboundEvent(evt);
102             }
103         } catch (Throwable throwable) {
104             if (autoRelease && release) {
105                 try {
106                     Resource.dispose(evt);
107                 } catch (Exception e) {
108                     throwable.addSuppressed(e);
109                 }
110             }
111             throw throwable;
112         }
113         if (autoRelease && release) {
114             Resource.dispose(evt);
115         }
116     }
117 
118     /**
119      * Is called for each user event triggered of type {@link I}.
120      *
121      * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleUserEventChannelHandler} belongs to
122      * @param evt the user event to handle
123      *
124      * @throws Exception is thrown if an error occurred
125      */
126     protected abstract void eventReceived(ChannelHandlerContext ctx, I evt) throws Exception;
127 }