001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.util.collections; 018 019import java.io.Serializable; 020import java.util.AbstractList; 021import java.util.AbstractSet; 022import java.util.Collection; 023import java.util.Iterator; 024import java.util.Map; 025import java.util.NoSuchElementException; 026import java.util.Set; 027 028/** 029 * An implementation of the java.util.Map interface which can only hold a single object. This is 030 * particularly useful to control memory usage in Wicket because many containers hold only a single 031 * component. 032 * 033 * @author Jonathan Locke 034 * @param <K> 035 * Key type 036 * @param <V> 037 * Value type 038 * 039 * @deprecated Please use {@link Map#of(Object, Object)} instead 040 */ 041@Deprecated(forRemoval = true, since = "9.0.0") 042public final class MicroMap<K, V> implements Map<K, V>, Serializable 043{ 044 private static final long serialVersionUID = 1L; 045 046 /** The maximum number of entries this map supports. */ 047 public static final int MAX_ENTRIES = 1; 048 049 /** The one and only key in this tiny map */ 050 private K key; 051 052 /** The value for the only key in this tiny map */ 053 private V value; 054 055 /** 056 * Constructor 057 */ 058 public MicroMap() 059 { 060 } 061 062 /** 063 * Constructs map with a single key and value pair. 064 * 065 * @param key 066 * The key 067 * @param value 068 * The value 069 */ 070 public MicroMap(final K key, final V value) 071 { 072 put(key, value); 073 } 074 075 /** 076 * @return True if this MicroMap is full 077 */ 078 public boolean isFull() 079 { 080 return size() == MAX_ENTRIES; 081 } 082 083 /** 084 * @see java.util.Map#size() 085 */ 086 @Override 087 public int size() 088 { 089 return (key != null) ? 1 : 0; 090 } 091 092 /** 093 * @see java.util.Map#isEmpty() 094 */ 095 @Override 096 public boolean isEmpty() 097 { 098 return size() == 0; 099 } 100 101 /** 102 * @see java.util.Map#containsKey(java.lang.Object) 103 */ 104 @Override 105 public boolean containsKey(final Object key) 106 { 107 return key.equals(this.key); 108 } 109 110 /** 111 * @see java.util.Map#containsValue(java.lang.Object) 112 */ 113 @Override 114 public boolean containsValue(final Object value) 115 { 116 return value.equals(this.value); 117 } 118 119 /** 120 * @see java.util.Map#get(java.lang.Object) 121 */ 122 @Override 123 public V get(final Object key) 124 { 125 if (key.equals(this.key)) 126 { 127 return value; 128 } 129 130 return null; 131 } 132 133 /** 134 * @see java.util.Map#put(java.lang.Object, java.lang.Object) 135 */ 136 @Override 137 public V put(final K key, final V value) 138 { 139 // Replace? 140 if (key.equals(this.key)) 141 { 142 final V oldValue = this.value; 143 144 this.value = value; 145 146 return oldValue; 147 } 148 else 149 { 150 // Is there room for a new entry? 151 if (size() < MAX_ENTRIES) 152 { 153 // Store 154 this.key = key; 155 this.value = value; 156 157 return null; 158 } 159 else 160 { 161 throw new IllegalStateException("Map full"); 162 } 163 } 164 } 165 166 /** 167 * @see java.util.Map#remove(java.lang.Object) 168 */ 169 @Override 170 public V remove(final Object key) 171 { 172 if (key.equals(this.key)) 173 { 174 final V oldValue = value; 175 176 this.key = null; 177 value = null; 178 179 return oldValue; 180 } 181 182 return null; 183 } 184 185 /** 186 * @see java.util.Map#putAll(java.util.Map) 187 */ 188 @Override 189 public void putAll(final Map<? extends K, ? extends V> map) 190 { 191 if (map.size() <= MAX_ENTRIES) 192 { 193 final Entry<? extends K, ? extends V> e = map.entrySet().iterator().next(); 194 195 put(e.getKey(), e.getValue()); 196 } 197 else 198 { 199 throw new IllegalStateException("Map full. Cannot add " + map.size() + " entries"); 200 } 201 } 202 203 /** 204 * @see java.util.Map#clear() 205 */ 206 @Override 207 public void clear() 208 { 209 key = null; 210 value = null; 211 } 212 213 /** 214 * @see java.util.Map#keySet() 215 */ 216 @Override 217 public Set<K> keySet() 218 { 219 return new AbstractSet<K>() 220 { 221 @Override 222 public Iterator<K> iterator() 223 { 224 return new Iterator<K>() 225 { 226 @Override 227 public boolean hasNext() 228 { 229 return index < MicroMap.this.size(); 230 } 231 232 @Override 233 public K next() 234 { 235 if (!hasNext()) 236 { 237 throw new NoSuchElementException(); 238 } 239 index++; 240 241 return key; 242 } 243 244 @Override 245 public void remove() 246 { 247 MicroMap.this.clear(); 248 } 249 250 int index; 251 }; 252 } 253 254 @Override 255 public int size() 256 { 257 return MicroMap.this.size(); 258 } 259 }; 260 } 261 262 /** 263 * @see java.util.Map#values() 264 */ 265 @Override 266 public Collection<V> values() 267 { 268 return new AbstractList<V>() 269 { 270 @Override 271 public V get(final int index) 272 { 273 if (index > size() - 1) 274 { 275 throw new IndexOutOfBoundsException(); 276 } 277 return value; 278 } 279 280 @Override 281 public int size() 282 { 283 return MicroMap.this.size(); 284 } 285 }; 286 } 287 288 /** 289 * @see java.util.Map#entrySet() 290 */ 291 @Override 292 public Set<Entry<K, V>> entrySet() 293 { 294 return new AbstractSet<Entry<K, V>>() 295 { 296 @Override 297 public Iterator<Entry<K, V>> iterator() 298 { 299 return new Iterator<Entry<K, V>>() 300 { 301 @Override 302 public boolean hasNext() 303 { 304 return index < MicroMap.this.size(); 305 } 306 307 @Override 308 public Entry<K, V> next() 309 { 310 if (!hasNext()) 311 { 312 throw new NoSuchElementException(); 313 } 314 index++; 315 316 return new Map.Entry<K, V>() 317 { 318 @Override 319 public K getKey() 320 { 321 return key; 322 } 323 324 @Override 325 public V getValue() 326 { 327 return value; 328 } 329 330 @Override 331 public V setValue(final V value) 332 { 333 final V oldValue = MicroMap.this.value; 334 335 MicroMap.this.value = value; 336 337 return oldValue; 338 } 339 }; 340 } 341 342 @Override 343 public void remove() 344 { 345 clear(); 346 } 347 348 int index = 0; 349 }; 350 } 351 352 @Override 353 public int size() 354 { 355 return MicroMap.this.size(); 356 } 357 }; 358 } 359}