1 /* 2 * Copyright 2013 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 17 package io.netty.channel; 18 19 import io.netty.channel.ChannelHandlerMask.Skip; 20 import io.netty.util.internal.InternalThreadLocalMap; 21 22 import java.util.Map; 23 24 /** 25 * Skeleton implementation of a {@link ChannelHandler}. 26 */ 27 public abstract class ChannelHandlerAdapter implements ChannelHandler { 28 29 // Not using volatile because it's used only for a sanity check. 30 boolean added; 31 32 /** 33 * Throws {@link IllegalStateException} if {@link ChannelHandlerAdapter#isSharable()} returns {@code true} 34 */ 35 protected void ensureNotSharable() { 36 if (isSharable()) { 37 throw new IllegalStateException("ChannelHandler " + getClass().getName() + " is not allowed to be shared"); 38 } 39 } 40 41 /** 42 * Return {@code true} if the implementation is {@link Sharable} and so can be added 43 * to different {@link ChannelPipeline}s. 44 */ 45 public boolean isSharable() { 46 /** 47 * Cache the result of {@link Sharable} annotation detection to workaround a condition. We use a 48 * {@link ThreadLocal} and {@link WeakHashMap} to eliminate the volatile write/reads. Using different 49 * {@link WeakHashMap} instances per {@link Thread} is good enough for us and the number of 50 * {@link Thread}s are quite limited anyway. 51 * 52 * See <a href="https://github.com/netty/netty/issues/2289">#2289</a>. 53 */ 54 Class<?> clazz = getClass(); 55 Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache(); 56 Boolean sharable = cache.get(clazz); 57 if (sharable == null) { 58 sharable = clazz.isAnnotationPresent(Sharable.class); 59 cache.put(clazz, sharable); 60 } 61 return sharable; 62 } 63 64 /** 65 * Do nothing by default, sub-classes may override this method. 66 */ 67 @Override 68 public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 69 // NOOP 70 } 71 72 /** 73 * Do nothing by default, sub-classes may override this method. 74 */ 75 @Override 76 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 77 // NOOP 78 } 79 80 /** 81 * Calls {@link ChannelHandlerContext#fireExceptionCaught(Throwable)} to forward 82 * to the next {@link ChannelHandler} in the {@link ChannelPipeline}. 83 * 84 * Sub-classes may override this method to change behavior. 85 * 86 * @deprecated is part of {@link ChannelInboundHandler} 87 */ 88 @Skip 89 @Override 90 @Deprecated 91 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 92 ctx.fireExceptionCaught(cause); 93 } 94 }