1 22 package org.jboss.util; 23 24 import java.util.HashMap ; 25 26 32 public class LRUCachePolicy 33 implements CachePolicy 34 { 35 37 41 protected HashMap m_map; 42 45 protected LRUList m_list; 46 49 protected int m_maxCapacity; 50 53 protected int m_minCapacity; 54 55 57 63 public LRUCachePolicy() 64 { 65 } 66 72 public LRUCachePolicy(int min, int max) 73 { 74 if (min < 2 || min > max) {throw new IllegalArgumentException ("Illegal cache capacities");} 75 m_minCapacity = min; 76 m_maxCapacity = max; 77 } 78 79 81 88 public void create() 89 { 90 m_map = new HashMap (); 91 m_list = createList(); 92 m_list.m_maxCapacity = m_maxCapacity; 93 m_list.m_minCapacity = m_minCapacity; 94 m_list.m_capacity = m_maxCapacity; 95 } 96 101 public void start() 102 { 103 } 104 110 public void stop() 111 { 112 if (m_list != null) 113 { 114 flush(); 115 } 116 } 117 124 public void destroy() 125 { 126 if( m_map != null ) 127 m_map.clear(); 128 if( m_list != null ) 129 m_list.clear(); 130 } 131 132 public Object get(Object key) 133 { 134 if (key == null) 135 { 136 throw new IllegalArgumentException ("Requesting an object using a null key"); 137 } 138 139 LRUCacheEntry value = (LRUCacheEntry)m_map.get(key); 140 if (value != null) 141 { 142 m_list.promote(value); 143 return value.m_object; 144 } 145 else 146 { 147 cacheMiss(); 148 return null; 149 } 150 } 151 public Object peek(Object key) 152 { 153 if (key == null) 154 { 155 throw new IllegalArgumentException ("Requesting an object using a null key"); 156 } 157 158 LRUCacheEntry value = (LRUCacheEntry)m_map.get(key); 159 if (value == null) 160 { 161 return null; 162 } 163 else 164 { 165 return value.m_object; 166 } 167 } 168 public void insert(Object key, Object o) 169 { 170 if (o == null) {throw new IllegalArgumentException ("Cannot insert a null object in the cache");} 171 if (key == null) {throw new IllegalArgumentException ("Cannot insert an object in the cache with null key");} 172 if (m_map.containsKey(key)) 173 { 174 throw new IllegalStateException ("Attempt to put in the cache an object that is already there"); 175 } 176 m_list.demote(); 177 LRUCacheEntry entry = createCacheEntry(key, o); 178 m_map.put(key, entry); 179 m_list.promote(entry); 180 } 181 public void remove(Object key) 182 { 183 if (key == null) {throw new IllegalArgumentException ("Removing an object using a null key");} 184 185 Object value = m_map.remove(key); 186 if (value != null) 187 { 188 m_list.remove((LRUCacheEntry)value); 189 } 190 } 192 public void flush() 193 { 194 LRUCacheEntry entry = null; 195 while ((entry = m_list.m_tail) != null) 196 { 197 ageOut(entry); 198 } 199 } 200 201 public int size() { 202 return m_list.m_count; 203 } 204 205 207 209 213 protected LRUList createList() {return new LRUList();} 214 219 protected void ageOut(LRUCacheEntry entry) 220 { 221 remove(entry.m_key); 222 } 223 226 protected void cacheMiss() 227 { 228 } 229 232 protected LRUCacheEntry createCacheEntry(Object key, Object value) 233 { 234 return new LRUCacheEntry(key, value); 235 } 236 237 239 243 public class LRUList 244 { 245 246 public int m_maxCapacity; 247 248 public int m_minCapacity; 249 250 public int m_capacity; 251 252 public int m_count; 253 254 public LRUCacheEntry m_head; 255 256 public LRUCacheEntry m_tail; 257 258 public int m_cacheMiss; 259 262 protected LRUList() 263 { 264 m_head = null; 265 m_tail = null; 266 m_count = 0; 267 } 268 276 protected void promote(LRUCacheEntry entry) 277 { 278 if (entry == null) {throw new IllegalArgumentException ("Trying to promote a null object");} 279 if (m_capacity < 1) {throw new IllegalStateException ("Can't work with capacity < 1");} 280 281 entryPromotion(entry); 282 283 entry.m_time = System.currentTimeMillis(); 284 if (entry.m_prev == null) 285 { 286 if (entry.m_next == null) 287 { 288 if (m_count == 0) { 291 m_head = entry; 292 m_tail = entry; 293 ++m_count; 294 entryAdded(entry); 295 } 296 else if (m_count == 1 && m_head == entry) {} else if (m_count < m_capacity) 298 { 299 entry.m_prev = null; 300 entry.m_next = m_head; 301 m_head.m_prev = entry; 302 m_head = entry; 303 ++m_count; 304 entryAdded(entry); 305 } 306 else if (m_count < m_maxCapacity) 307 { 308 entry.m_prev = null; 309 entry.m_next = m_head; 310 m_head.m_prev = entry; 311 m_head = entry; 312 ++m_count; 313 int oldCapacity = m_capacity; 314 ++m_capacity; 315 entryAdded(entry); 316 capacityChanged(oldCapacity); 317 } 318 else {throw new IllegalStateException ("Attempt to put a new cache entry on a full cache");} 319 } 320 else {} } 322 else 323 { 324 if (entry.m_next == null) { 326 LRUCacheEntry beforeLast = entry.m_prev; 327 beforeLast.m_next = null; 328 entry.m_prev = null; 329 entry.m_next = m_head; 330 m_head.m_prev = entry; 331 m_head = entry; 332 m_tail = beforeLast; 333 } 334 else { 336 LRUCacheEntry previous = entry.m_prev; 337 previous.m_next = entry.m_next; 338 entry.m_next.m_prev = previous; 339 entry.m_prev = null; 340 entry.m_next = m_head; 341 m_head.m_prev = entry; 342 m_head = entry; 343 } 344 } 345 } 346 351 protected void demote() 352 { 353 if (m_capacity < 1) {throw new IllegalStateException ("Can't work with capacity < 1");} 354 if (m_count > m_maxCapacity) {throw new IllegalStateException ("Cache list entries number (" + m_count + ") > than the maximum allowed (" + m_maxCapacity + ")");} 355 if (m_count == m_maxCapacity) 356 { 357 LRUCacheEntry entry = m_tail; 358 359 ageOut(entry); 361 } 362 else {} } 364 367 protected void remove(LRUCacheEntry entry) 368 { 369 if (entry == null) {throw new IllegalArgumentException ("Cannot remove a null entry from the cache");} 370 if (m_count < 1) {throw new IllegalStateException ("Trying to remove an entry from an empty cache");} 371 372 entry.m_key = entry.m_object = null; 373 if (m_count == 1) 374 { 375 m_head = m_tail = null; 376 } 377 else 378 { 379 if (entry.m_prev == null) { 381 m_head = entry.m_next; 382 m_head.m_prev = null; 383 entry.m_next = null; 384 } 385 else if (entry.m_next == null) { 387 m_tail = entry.m_prev; 388 m_tail.m_next = null; 389 entry.m_prev = null; 390 } 391 else { 393 entry.m_next.m_prev = entry.m_prev; 394 entry.m_prev.m_next = entry.m_next; 395 entry.m_prev = null; 396 entry.m_next = null; 397 } 398 } 399 --m_count; 400 entryRemoved(entry); 401 } 402 405 protected void entryPromotion(LRUCacheEntry entry) {} 406 409 protected void entryAdded(LRUCacheEntry entry) {} 410 413 protected void entryRemoved(LRUCacheEntry entry) {} 414 418 protected void capacityChanged(int oldCapacity) {} 419 420 protected void clear() 421 { 422 LRUCacheEntry entry = m_head; 423 m_head = null; 424 m_tail = null; 425 m_count = 0; 426 for (; entry != null; entry = entry.m_next) 427 entryRemoved(entry); 428 } 429 430 public String toString() 431 { 432 String s = Integer.toHexString(super.hashCode()); 433 s += " size: " + m_count; 434 for (LRUCacheEntry entry = m_head; entry != null; entry = entry.m_next) 435 { 436 s += "\n" + entry; 437 } 438 return s; 439 } 440 } 441 442 445 public class LRUCacheEntry 446 { 447 448 public LRUCacheEntry m_next; 449 450 public LRUCacheEntry m_prev; 451 452 public Object m_key; 453 454 public Object m_object; 455 456 public long m_time; 457 461 protected LRUCacheEntry(Object key, Object object) 462 { 463 m_key = key; 464 m_object = object; 465 m_next = null; 466 m_prev = null; 467 m_time = 0; } 469 public String toString() 470 { 471 return "key: " + m_key + ", object: " + ( m_object==null ? "null" : Integer.toHexString(m_object.hashCode())) + ", entry: " + Integer.toHexString(super.hashCode()); 472 } 473 } 474 } 475 | Popular Tags |