View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.session;
    21
    22  import static java.util.Collections.unmodifiableSet;
    23  import static org.apache.mina.util.Assert.assertNotNull;
    24
    25  import java.util.Collections;
    26  import java.util.Map;
    27  import java.util.Set;
    28  import java.util.concurrent.ConcurrentHashMap;
    29
    30  /**
    31   * An {@link AttributeContainer} provides type-safe access to attribute values, using {@link AttributeKey}' s which as
    32   * reference-key to an attribute value. <br>
    33   * <br>
    34   * This class is Thread-Safe !
    35   *
    36   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    37   */
    38  final class DefaultAttributeContainer implements AttributeContainer {
    39      /**
    40       * Contains all attributes
    41       * <ul>
    42       * <li>Key: the typesafe attribute key
    43       * <li>Value: the attribute value
    44       * </ul>
    45       */
    46      private final Map<AttributeKey<?>, Object> attributes = new ConcurrentHashMap<AttributeKey<?>, Object>();
    47
    48      /**
    49       * Returns the value of the user-defined attribute for the given <code>key</code>.
    50       *
    51       * @param key the attribute's key, must not be <code>null</code>
    52       * @return <tt>null</tt> if there is no attribute with the specified key
    53       * @exception IllegalArgumentException if <code>key==null</code>
    54       * @see #setAttribute(AttributeKey, Object)
    55       */
    56      @Override
    57      @SuppressWarnings("unchecked")
    58      public <T> T getAttribute(AttributeKey<T> key) {
    59          assertNotNull(key, "key");
    60
    61          T value = (T) attributes.get(key);
    62
    63          return value;
    64      }
    65
    66      /**
    67       * Returns the value of the user-defined attribute for the given <code>key</code>.
    68       *
    69       * @param key the attribute's key, must not be <code>null</code>
    70       * @return <tt>null</tt> if there is no attribute with the specified key
    71       * @exception IllegalArgumentException if <code>key==null</code>
    72       * @see #setAttribute(AttributeKey, Object)
    73       */
    74      @Override
    75      @SuppressWarnings("unchecked")
    76      public <T> T getAttribute(AttributeKey<T> key, T defaultValue) {
    77          assertNotNull(key, "key");
    78
    79          T value = (T) attributes.get(key);
    80
    81          if (value != null) {
    82              return value;
    83          }
    84
    85          return defaultValue;
    86      }
    87
    88      /**
    89       * Sets a user-defined attribute. If the <code>value</code> is <code>null</code> the attribute will be removed from
    90       * this container.
    91       *
    92       * @param key the attribute's key, must not be <code>null</code>
    93       * @param value the attribute's value, <code>null</code> to remove the attribute
    94       * @return The old attribute's value, <code>null</code> if there is no previous value
    95       * @exception IllegalArgumentException <ul>
    96       *            <li>if <code>key==null</code>
    97       *            <li>if <code>value</code> is not <code>null</code> and not an instance of type that is specified in by
    98       *            the given <code>key</code> (see {@link AttributeKey#getType()})
    99       *
    100      *            </ul>
    101      *
    102      * @see #getAttribute(AttributeKey)
    103      */
    104     @Override
    105     @SuppressWarnings("unchecked")
    106     public <T> T setAttribute(AttributeKey<? extends T> key, T value) {
    107         assertNotNull(key, "key");
    108         assertValueIsOfExpectedType(key, value);
    109         if (value == null) {
    110             return removeAttribute(key);
    111         }
    112
    113         return (T) attributes.put(key, value);
    114     }
    115
    116     /**
    117      * Throws an {@link IllegalArgumentException} if the given <code>value</code> is not of the expected type and not
    118      * <code>null</code>.
    119      *
    120      * @param <T>
    121      * @param key
    122      * @param value
    123      * @exception IllegalArgumentException if <code>value</code> is not an instance of {@link AttributeKey#getType()}
    124      */
    125     private static <T> void assertValueIsOfExpectedType(AttributeKey<? extends T> key, T value) {
    126         if (value == null) {
    127             return;
    128         }
    129
    130         Class<? extends T> expectedValueType = key.getType();
    131
    132         if (!expectedValueType.isInstance(value)) {
    133             throw new IllegalArgumentException("Invalid attribute value" + "\r\n  expected type: "
    134                     + expectedValueType.getName() + "\r\n  actual type  : " + value.getClass().getName()
    135                     + "\r\n  actual value : " + value);
    136         }
    137     }
    138
    139     /**
    140      * Returns an unmodifiable {@link Set} of all Keys of this container. If this container contains no key's an empty
    141      * {@link Set} will be returned.
    142      *
    143      * @return all Keys, never <code>null</code>
    144      * @see Collections#unmodifiableSet(Set)
    145      */
    146     @Override
    147     public Set<AttributeKey<?>> getAttributeKeys() {
    148         return unmodifiableSet(attributes.keySet());
    149     }
    150
    151     /**
    152      * Removes the specified Attribute from this container. The old value will be returned, <code>null</code> will be
    153      * returned if there is no such attribute in this container.<br>
    154      * <br>
    155      * This method is equivalent to <code>setAttribute(key,null)</code>.
    156      *
    157      * @param key of the attribute to be removed,must not be <code>null</code>
    158      * @return the removed value, <code>null</code> if this container doesn't contain the specified attribute
    159      * @exception IllegalArgumentException if <code>key==null</code>
    160      */
    161     @Override
    162     @SuppressWarnings("unchecked")
    163     public <T> T removeAttribute(AttributeKey<T> key) {
    164         assertNotNull(key, "key");
    165         return (T) attributes.remove(key);
    166     }
    167 }