1 /* 2 * Copyright 2009 Red Hat, Inc. 3 * 4 * Red Hat licenses this file to you under the Apache License, version 2.0 5 * (the "License"); you may not use this file except in compliance with the 6 * License. You may obtain a copy of the License at: 7 * 8 * http://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 org.jboss.netty.channel; 17 18 import java.util.concurrent.ConcurrentMap; 19 20 import org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap; 21 22 /** 23 * A global variable that is local to a {@link Channel}. Think of this as a 24 * variation of {@link ThreadLocal} whose key is a {@link Channel} rather than 25 * a {@link Thread#currentThread()}. One difference is that you always have to 26 * specify the {@link Channel} to access the variable. 27 * <p> 28 * Alternatively, you might want to use the 29 * {@link ChannelHandlerContext#setAttachment(Object) ChannelHandlerContext.attachment} 30 * property, which performs better. 31 * 32 * @author <a href="http://www.jboss.org/netty/">The Netty Project</a> 33 * @author <a href="http://gleamynode.net/">Trustin Lee</a> 34 * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $ 35 * 36 * @apiviz.stereotype utility 37 */ 38 public class ChannelLocal<T> { 39 40 private final ConcurrentMap<Channel, T> map = 41 new ConcurrentIdentityWeakKeyHashMap<Channel, T>(); 42 43 /** 44 * Creates a {@link Channel} local variable. 45 */ 46 public ChannelLocal() { 47 super(); 48 } 49 50 /** 51 * Returns the initial value of the variable. By default, it returns 52 * {@code null}. Override it to change the initial value. 53 */ 54 protected T initialValue(@SuppressWarnings("unused") Channel channel) { 55 return null; 56 } 57 58 /** 59 * Returns the value of this variable. 60 */ 61 public T get(Channel channel) { 62 if (channel == null) { 63 throw new NullPointerException("channel"); 64 } 65 66 T value = map.get(channel); 67 if (value == null) { 68 value = initialValue(channel); 69 if (value != null) { 70 T oldValue = setIfAbsent(channel, value); 71 if (oldValue != null) { 72 value = oldValue; 73 } 74 } 75 } 76 return value; 77 } 78 79 /** 80 * Sets the value of this variable. 81 * 82 * @return the old value. {@code null} if there was no old value. 83 */ 84 public T set(Channel channel, T value) { 85 if (value == null) { 86 return remove(channel); 87 } else { 88 if (channel == null) { 89 throw new NullPointerException("channel"); 90 } 91 return map.put(channel, value); 92 } 93 } 94 95 /** 96 * Sets the value of this variable only when no value was set. 97 * 98 * @return {@code null} if the specified value was set. 99 * An existing value if failed to set. 100 */ 101 public T setIfAbsent(Channel channel, T value) { 102 if (value == null) { 103 return get(channel); 104 } else { 105 if (channel == null) { 106 throw new NullPointerException("channel"); 107 } 108 return map.putIfAbsent(channel, value); 109 } 110 } 111 112 /** 113 * Removes the variable. 114 * 115 * @return the removed value. {@code null} if no value was set. 116 */ 117 public T remove(Channel channel) { 118 if (channel == null) { 119 throw new NullPointerException("channel"); 120 } 121 return map.remove(channel); 122 } 123 }