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 }