View Javadoc

    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 }