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 }