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.util; 21 22 import java.util.Collection; 23 import java.util.Map; 24 import java.util.Set; 25 import java.util.concurrent.ConcurrentHashMap; 26 import java.util.concurrent.ConcurrentMap; 27 28 import org.apache.mina.core.buffer.IoBuffer; 29 30 /** 31 * This map is specially useful when reads are much more frequent than writes and 32 * if the cost of instantiating the values is high like allocating an 33 * {@link IoBuffer} for example. 34 * 35 * Based on the final implementation of Memoizer written by Brian Goetz and Tim 36 * Peierls. This implementation will return an 37 * {@link UnsupportedOperationException} on each method that is not intended to 38 * be called by user code for performance reasons. 39 * 40 * @author The Apache MINA Project (dev@mina.apache.org) 41 * @version $Rev: 685705 $, $Date: 2008-08-14 00:16:46 +0200 (Thu, 14 Aug 2008) $ 42 * @since MINA 2.0.0-M2 43 */ 44 public class LazyInitializedCacheMap<K, V> implements Map<K, V> { 45 private ConcurrentMap<K, LazyInitializer<V>> cache; 46 47 /** 48 * This class provides a noop {@link LazyInitializer} meaning it 49 * will return the same object it received when instantiated. 50 */ 51 public class NoopInitializer extends LazyInitializer<V> { 52 private V value; 53 54 public NoopInitializer(V value) { 55 this.value = value; 56 } 57 58 public V init() { 59 return value; 60 } 61 } 62 63 /** 64 * Default constructor. Uses the default parameters to initialize its internal 65 * {@link ConcurrentHashMap}. 66 */ 67 public LazyInitializedCacheMap() { 68 this.cache = new ConcurrentHashMap<K, LazyInitializer<V>>(); 69 } 70 71 /** 72 * This constructor allows to provide a fine tuned {@link ConcurrentHashMap} 73 * to stick with each special case the user needs. 74 */ 75 public LazyInitializedCacheMap(final ConcurrentHashMap<K, LazyInitializer<V>> map) { 76 this.cache = map; 77 } 78 79 /** 80 * {@inheritDoc} 81 */ 82 public V get(Object key) { 83 LazyInitializer<V> c = cache.get(key); 84 if (c != null) { 85 return c.get(); 86 } 87 88 return null; 89 } 90 91 /** 92 * {@inheritDoc} 93 */ 94 public V remove(Object key) { 95 LazyInitializer<V> c = cache.remove(key); 96 if (c != null) { 97 return c.get(); 98 } 99 100 return null; 101 } 102 103 /** 104 * If the specified key is not already associated 105 * with a value, associate it with the given value. 106 * This is equivalent to 107 * <pre> 108 * if (!map.containsKey(key)) 109 * return map.put(key, value); 110 * else 111 * return map.get(key);</pre> 112 * except that the action is performed atomically. 113 * 114 * @param key key with which the specified value is to be associated 115 * @param value a lazy initialized value object. 116 * 117 * @return the previous value associated with the specified key, 118 * or <tt>null</tt> if there was no mapping for the key 119 * @throws NullPointerException if the specified key or value is null 120 */ 121 public V putIfAbsent(K key, LazyInitializer<V> value) { 122 LazyInitializer<V> v = cache.get(key); 123 if (v == null) { 124 v = cache.putIfAbsent(key, value); 125 if (v == null) { 126 return value.get(); 127 } 128 } 129 130 return v.get(); 131 } 132 133 /** 134 * {@inheritDoc} 135 */ 136 public V put(K key, V value) { 137 LazyInitializer<V> c = cache.put(key, new NoopInitializer(value)); 138 if (c != null) { 139 return c.get(); 140 } 141 142 return null; 143 } 144 145 /** 146 * @throws {@link UnsupportedOperationException} as this method would imply 147 * performance drops. 148 */ 149 public boolean containsValue(Object value) { 150 throw new UnsupportedOperationException(); 151 } 152 153 /** 154 * @throws {@link UnsupportedOperationException} as this method would imply 155 * performance drops. 156 */ 157 public Collection<V> values() { 158 throw new UnsupportedOperationException(); 159 } 160 161 /** 162 * @throws {@link UnsupportedOperationException} as this method would imply 163 * performance drops. 164 */ 165 public Set<java.util.Map.Entry<K, V>> entrySet() { 166 throw new UnsupportedOperationException(); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 public void putAll(Map<? extends K, ? extends V> m) { 173 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { 174 cache.put(e.getKey(), new NoopInitializer(e.getValue())); 175 } 176 } 177 178 /** 179 * {@inheritDoc} 180 */ 181 public Collection<LazyInitializer<V>> getValues() { 182 return cache.values(); 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 public void clear() { 189 cache.clear(); 190 } 191 192 /** 193 * {@inheritDoc} 194 */ 195 public boolean containsKey(Object key) { 196 return cache.containsKey(key); 197 } 198 199 /** 200 * {@inheritDoc} 201 */ 202 public boolean isEmpty() { 203 return cache.isEmpty(); 204 } 205 206 /** 207 * {@inheritDoc} 208 */ 209 public Set<K> keySet() { 210 return cache.keySet(); 211 } 212 213 /** 214 * {@inheritDoc} 215 */ 216 public int size() { 217 return cache.size(); 218 } 219 }