View Javadoc
1   /*
2    * Copyright 2019 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.netty.channel;
17  
18  import io.netty.util.concurrent.FastThreadLocal;
19  import io.netty.util.internal.PlatformDependent;
20  
21  import io.netty.util.internal.logging.InternalLogger;
22  import io.netty.util.internal.logging.InternalLoggerFactory;
23  import java.lang.annotation.ElementType;
24  import java.lang.annotation.Inherited;
25  import java.lang.annotation.Retention;
26  import java.lang.annotation.RetentionPolicy;
27  import java.lang.annotation.Target;
28  import java.lang.reflect.Method;
29  import java.net.SocketAddress;
30  import java.security.AccessController;
31  import java.security.PrivilegedExceptionAction;
32  import java.util.Map;
33  import java.util.WeakHashMap;
34  
35  final class ChannelHandlerMask {
36      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelHandlerMask.class);
37  
38      // Using to mask which methods must be called for a ChannelHandler.
39      static final int MASK_EXCEPTION_CAUGHT = 1;
40      static final int MASK_CHANNEL_REGISTERED = 1 << 1;
41      static final int MASK_CHANNEL_UNREGISTERED = 1 << 2;
42      static final int MASK_CHANNEL_ACTIVE = 1 << 3;
43      static final int MASK_CHANNEL_INACTIVE = 1 << 4;
44      static final int MASK_CHANNEL_READ = 1 << 5;
45      static final int MASK_CHANNEL_READ_COMPLETE = 1 << 6;
46      static final int MASK_USER_EVENT_TRIGGERED = 1 << 7;
47      static final int MASK_CHANNEL_WRITABILITY_CHANGED = 1 << 8;
48      static final int MASK_BIND = 1 << 9;
49      static final int MASK_CONNECT = 1 << 10;
50      static final int MASK_DISCONNECT = 1 << 11;
51      static final int MASK_CLOSE = 1 << 12;
52      static final int MASK_DEREGISTER = 1 << 13;
53      static final int MASK_READ = 1 << 14;
54      static final int MASK_WRITE = 1 << 15;
55      static final int MASK_FLUSH = 1 << 16;
56  
57      static final int MASK_ONLY_INBOUND =  MASK_CHANNEL_REGISTERED |
58              MASK_CHANNEL_UNREGISTERED | MASK_CHANNEL_ACTIVE | MASK_CHANNEL_INACTIVE | MASK_CHANNEL_READ |
59              MASK_CHANNEL_READ_COMPLETE | MASK_USER_EVENT_TRIGGERED | MASK_CHANNEL_WRITABILITY_CHANGED;
60      private static final int MASK_ALL_INBOUND = MASK_EXCEPTION_CAUGHT | MASK_ONLY_INBOUND;
61      static final int MASK_ONLY_OUTBOUND =  MASK_BIND | MASK_CONNECT | MASK_DISCONNECT |
62              MASK_CLOSE | MASK_DEREGISTER | MASK_READ | MASK_WRITE | MASK_FLUSH;
63      private static final int MASK_ALL_OUTBOUND = MASK_EXCEPTION_CAUGHT | MASK_ONLY_OUTBOUND;
64  
65      private static final FastThreadLocal<Map<Class<? extends ChannelHandler>, Integer>> MASKS =
66              new FastThreadLocal<Map<Class<? extends ChannelHandler>, Integer>>() {
67                  @Override
68                  protected Map<Class<? extends ChannelHandler>, Integer> initialValue() {
69                      return new WeakHashMap<Class<? extends ChannelHandler>, Integer>(32);
70                  }
71              };
72  
73      /**
74       * Return the {@code executionMask}.
75       */
76      static int mask(Class<? extends ChannelHandler> clazz) {
77          // Try to obtain the mask from the cache first. If this fails calculate it and put it in the cache for fast
78          // lookup in the future.
79          Map<Class<? extends ChannelHandler>, Integer> cache = MASKS.get();
80          Integer mask = cache.get(clazz);
81          if (mask == null) {
82              mask = mask0(clazz);
83              cache.put(clazz, mask);
84          }
85          return mask;
86      }
87  
88      /**
89       * Calculate the {@code executionMask}.
90       */
91      private static int mask0(Class<? extends ChannelHandler> handlerType) {
92          int mask = MASK_EXCEPTION_CAUGHT;
93          try {
94              if (ChannelInboundHandler.class.isAssignableFrom(handlerType)) {
95                  mask |= MASK_ALL_INBOUND;
96  
97                  if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
98                      mask &= ~MASK_CHANNEL_REGISTERED;
99                  }
100                 if (isSkippable(handlerType, "channelUnregistered", ChannelHandlerContext.class)) {
101                     mask &= ~MASK_CHANNEL_UNREGISTERED;
102                 }
103                 if (isSkippable(handlerType, "channelActive", ChannelHandlerContext.class)) {
104                     mask &= ~MASK_CHANNEL_ACTIVE;
105                 }
106                 if (isSkippable(handlerType, "channelInactive", ChannelHandlerContext.class)) {
107                     mask &= ~MASK_CHANNEL_INACTIVE;
108                 }
109                 if (isSkippable(handlerType, "channelRead", ChannelHandlerContext.class, Object.class)) {
110                     mask &= ~MASK_CHANNEL_READ;
111                 }
112                 if (isSkippable(handlerType, "channelReadComplete", ChannelHandlerContext.class)) {
113                     mask &= ~MASK_CHANNEL_READ_COMPLETE;
114                 }
115                 if (isSkippable(handlerType, "channelWritabilityChanged", ChannelHandlerContext.class)) {
116                     mask &= ~MASK_CHANNEL_WRITABILITY_CHANGED;
117                 }
118                 if (isSkippable(handlerType, "userEventTriggered", ChannelHandlerContext.class, Object.class)) {
119                     mask &= ~MASK_USER_EVENT_TRIGGERED;
120                 }
121             }
122 
123             if (ChannelOutboundHandler.class.isAssignableFrom(handlerType)) {
124                 mask |= MASK_ALL_OUTBOUND;
125 
126                 if (isSkippable(handlerType, "bind", ChannelHandlerContext.class,
127                         SocketAddress.class, ChannelPromise.class)) {
128                     mask &= ~MASK_BIND;
129                 }
130                 if (isSkippable(handlerType, "connect", ChannelHandlerContext.class, SocketAddress.class,
131                         SocketAddress.class, ChannelPromise.class)) {
132                     mask &= ~MASK_CONNECT;
133                 }
134                 if (isSkippable(handlerType, "disconnect", ChannelHandlerContext.class, ChannelPromise.class)) {
135                     mask &= ~MASK_DISCONNECT;
136                 }
137                 if (isSkippable(handlerType, "close", ChannelHandlerContext.class, ChannelPromise.class)) {
138                     mask &= ~MASK_CLOSE;
139                 }
140                 if (isSkippable(handlerType, "deregister", ChannelHandlerContext.class, ChannelPromise.class)) {
141                     mask &= ~MASK_DEREGISTER;
142                 }
143                 if (isSkippable(handlerType, "read", ChannelHandlerContext.class)) {
144                     mask &= ~MASK_READ;
145                 }
146                 if (isSkippable(handlerType, "write", ChannelHandlerContext.class,
147                         Object.class, ChannelPromise.class)) {
148                     mask &= ~MASK_WRITE;
149                 }
150                 if (isSkippable(handlerType, "flush", ChannelHandlerContext.class)) {
151                     mask &= ~MASK_FLUSH;
152                 }
153             }
154 
155             if (isSkippable(handlerType, "exceptionCaught", ChannelHandlerContext.class, Throwable.class)) {
156                 mask &= ~MASK_EXCEPTION_CAUGHT;
157             }
158         } catch (Exception e) {
159             // Should never reach here.
160             PlatformDependent.throwException(e);
161         }
162 
163         return mask;
164     }
165 
166     @SuppressWarnings("rawtypes")
167     private static boolean isSkippable(
168             final Class<?> handlerType, final String methodName, final Class<?>... paramTypes) throws Exception {
169         return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
170             @Override
171             public Boolean run() throws Exception {
172                 Method m;
173                 try {
174                     m = handlerType.getMethod(methodName, paramTypes);
175                 } catch (NoSuchMethodException e) {
176                     if (logger.isDebugEnabled()) {
177                         logger.debug(
178                             "Class {} missing method {}, assume we can not skip execution", handlerType, methodName, e);
179                     }
180                     return false;
181                 }
182                 return m.isAnnotationPresent(Skip.class);
183             }
184         });
185     }
186 
187     private ChannelHandlerMask() { }
188 
189     /**
190      * Indicates that the annotated event handler method in {@link ChannelHandler} will not be invoked by
191      * {@link ChannelPipeline} and so <strong>MUST</strong> only be used when the {@link ChannelHandler}
192      * method does nothing except forward to the next {@link ChannelHandler} in the pipeline.
193      * <p>
194      * Note that this annotation is not {@linkplain Inherited inherited}. If a user overrides a method annotated with
195      * {@link Skip}, it will not be skipped anymore. Similarly, the user can override a method not annotated with
196      * {@link Skip} and simply pass the event through to the next handler, which reverses the behavior of the
197      * supertype.
198      * </p>
199      */
200     @Target(ElementType.METHOD)
201     @Retention(RetentionPolicy.RUNTIME)
202     @interface Skip {
203         // no value
204     }
205 }