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 }