1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
75
76 static int mask(Class<? extends ChannelHandler> clazz) {
77
78
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
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
160 PlatformDependent.throwException(e);
161 }
162
163 return mask;
164 }
165
166 private static boolean isSkippable(
167 final Class<?> handlerType, final String methodName, final Class<?>... paramTypes) throws Exception {
168 return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
169 @Override
170 public Boolean run() throws Exception {
171 Method m;
172 try {
173 m = handlerType.getMethod(methodName, paramTypes);
174 } catch (NoSuchMethodException e) {
175 if (logger.isDebugEnabled()) {
176 logger.debug(
177 "Class {} missing method {}, assume we can not skip execution", handlerType, methodName, e);
178 }
179 return false;
180 }
181 return m.isAnnotationPresent(Skip.class);
182 }
183 });
184 }
185
186 private ChannelHandlerMask() { }
187
188
189
190
191
192
193
194
195
196
197
198
199 @Target(ElementType.METHOD)
200 @Retention(RetentionPolicy.RUNTIME)
201 @interface Skip {
202
203 }
204 }