1 38 39 40 package org.jahia.services.cache.simplecache; 41 42 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 43 import java.util.*; 44 45 import org.jahia.services.cache.Cache; 46 import org.jahia.services.cache.CacheEntry; 47 import org.jahia.services.cache.CacheFactory; 48 import org.jahia.services.cache.CacheListener; 49 import org.jahia.services.cache.JMSHub; 50 51 52 86 public class SimpleCache implements Cache { 87 88 89 final private static org.apache.log4j.Logger logger = 90 org.apache.log4j.Logger.getLogger (SimpleCache.class); 91 92 93 private Map cache; 94 95 96 private String name; 97 98 99 private long successHitCount = 0; 100 101 102 private long totalHitCount = 0; 103 104 105 private int cacheLimit = -1; 106 107 108 109 private JMSHub jmsHub = null; 110 111 private ArrayList listeners = null; 112 113 114 120 public SimpleCache (final String aName, final JMSHub hub) { 121 init (aName, hub); 122 } 123 124 125 139 public CacheEntry getCacheEntry (Object entryKey) { 140 141 if (entryKey == null) 143 return null; 144 145 if (cache == null) { 147 cache = new ConcurrentReaderHashMap (2003); 149 } 150 151 totalHitCount++; 153 154 CacheEntry entry = (CacheEntry)cache.get (entryKey); 156 if (entry == null) { 157 if (logger.isDebugEnabled()) { 158 StringBuffer buffer = new StringBuffer ("Entry ["); 160 buffer.append(entryKey.toString()); 161 buffer.append("] could not be found in cache ["); 162 buffer.append(name); 163 buffer.append("]!"); 164 logger.debug(buffer.toString()); 165 } 166 return null; 167 } 168 169 Date date = entry.getExpirationDate (); 171 172 if (date != null) { 174 if (date.getTime() <= System.currentTimeMillis() ) { 175 logger.debug ("Cache entry has expired, ignoring entry and removing..."); 177 remove (entryKey); 178 return null; 179 180 } else { 181 logger.debug ("Cache entry has not expired, continuing..."); 182 } 183 } 184 185 successHitCount++; 187 188 entry.incrementHits (); 190 191 entry.setLastAccessedTimeNow (); 193 194 return entry; 195 } 196 197 207 public Object get (Object entryKey) { 208 if (entryKey == null) { 209 logger.debug ("Cannot fetch with an null entry key!!!"); 210 return null; 211 } 212 213 CacheEntry entry = getCacheEntry (entryKey); 214 if (entry != null) { 215 return entry.getObject (); 216 } 217 return null; 218 } 219 220 221 231 public void put (Object entryKey, Object entryObj) { 232 put(entryKey, entryObj, true); 233 } 234 235 249 public void put (Object entryKey, Object entryObj, boolean propagate) { 250 if (entryKey == null) { 251 logger.debug ("Cannot add an object with an empty key!!"); 252 return; 253 } 254 255 CacheEntry entry = new CacheEntry (entryObj); 256 putCacheEntry (entryKey, entry, propagate); 257 } 258 259 260 275 public synchronized void putCacheEntry (Object entryKey, CacheEntry entry, boolean propagate) { 276 277 internalPut(entryKey, entry); 278 279 if ((listeners != null) && (listeners.size() > 0)) { 280 for (int i = 0; i < listeners.size(); i++) { 281 CacheListener listener = (CacheListener) listeners.get(i); 282 if (listener != null) 283 listener.onCachePut(name, entryKey); 284 } 285 } 286 if ((jmsHub != null) && (propagate) ) { 288 if (!jmsHub.sendPutMessage (this, entryKey, entry)) 289 logger.debug ("Could not send the update message!"); 290 } 291 } 292 293 private boolean internalPut (Object entryKey, CacheEntry entry) { 294 if ((entryKey == null) || (entry == null)) { 295 logger.debug ("null cache entry key or entry object, cannot cache such an object!"); 296 return false; 297 } 298 299 if (cache == null) { 301 cache = new ConcurrentReaderHashMap(2003); 302 } 303 304 if (getCacheLimit () == 0) { 305 logger.debug ("cache is deactivated. Aborting store."); 306 return false; 307 } 308 309 310 if (cache.containsKey (entryKey)) { 312 if (logger.isDebugEnabled()) { 313 StringBuffer buffer = new StringBuffer ("Updating key ["); 314 buffer.append(entryKey.toString()); 315 buffer.append("] into cache ["); 316 buffer.append(name); 317 buffer.append(", cache size before set="); 318 buffer.append(size()); 319 logger.debug(buffer.toString()); 320 } 321 } else { 322 checkCacheSize (); 324 325 if (logger.isDebugEnabled()) { 326 StringBuffer buffer = new StringBuffer ("Adding key ["); 327 buffer.append(entryKey.toString()); 328 buffer.append("] into cache ["); 329 buffer.append(name); 330 buffer.append(", cache size before set="); 331 buffer.append(size()); 332 logger.debug(buffer.toString()); 333 } 334 } 335 cache.put (entryKey, entry); 336 return true; 337 } 338 339 340 346 private void init (final String aName, JMSHub hub) { 347 this.name = aName; 349 350 jmsHub = hub; 352 353 cache = new ConcurrentReaderHashMap(2003); 355 } 356 357 358 364 public synchronized void remove (Object entryKey) { 365 internalRemove (entryKey); 366 367 if (jmsHub != null) { 369 jmsHub.sendRemoveMessage (this, entryKey); 370 } 371 } 372 373 380 final public boolean isEmpty() { 381 return cache.isEmpty(); 382 } 383 384 388 final public int size () { 389 return cache.size (); 390 } 391 392 393 398 final public int getCacheLimit () { 399 return cacheLimit; 400 } 401 402 403 407 final public void setCacheLimit (int limit) { 408 cacheLimit = limit; 409 } 410 411 412 416 final public String getName () { 417 return name; 418 } 419 420 421 424 public final void flush () { 425 flush (true); 426 } 427 428 431 public void flush(boolean propagate) { 432 433 synchronized (this) { 434 cache.clear(); 436 437 successHitCount = 0; 439 totalHitCount = 0; 440 } 441 442 logger.debug("Flushed all entries from cache [" + name + "]"); 443 444 if (propagate) { 446 if (jmsHub != null) { 448 if (!jmsHub.sendFlushMessage(this)) 449 logger.debug("Could not send the flush message!"); 450 } 451 452 if ((listeners != null) && (listeners.size() > 0)) { 454 for (int i = 0; i < listeners.size(); i++) { 455 CacheListener listener = (CacheListener) listeners.get(i); 456 if (listener != null) 457 listener.onCacheFlush(name); 458 } 459 } 460 461 } else { 462 logger.debug("Got cache flush request without event propagation"); 463 } 464 465 466 } 467 468 477 public synchronized Object [] keys () { 478 if (cache != null) { 479 Set keys = cache.keySet (); 480 return (Object [])(keys.toArray (new Object [0])).clone(); 481 } 482 return new Object [0]; 483 } 484 485 486 490 final public long getSuccessHits () { 491 return successHitCount; 492 } 493 494 495 499 final public long getTotalHits () { 500 return totalHitCount; 501 } 502 503 504 510 public double getCacheEfficiency () { 511 return (successHitCount * 100.0) / totalHitCount; 512 } 513 514 515 525 public void onRemove (Object entryKey) { 526 internalRemove (entryKey); 527 } 528 529 530 546 public void onPut (Object entryKey, Object entryValue) { 547 internalPut(entryKey, (CacheEntry) entryValue); 549 if ((listeners != null) && (listeners.size() > 0)) { 551 for (int i = 0; i < listeners.size(); i++) { 552 CacheListener listener = (CacheListener) listeners.get(i); 553 if (listener != null) 554 listener.onCachePut(name, entryKey); 555 } 556 } 557 } 558 559 560 567 public void onFlush () { 568 flush (false); 569 } 570 571 572 579 final public boolean containsKey (final Object entryKey) { 580 return cache.containsKey (entryKey); 581 } 582 583 584 587 private void checkCacheSize () { 588 if (getCacheLimit () <= 0) { 589 return; 590 } 591 592 while (cache.size () >= getCacheLimit ()) { 593 logger.debug ("Cache is at limit(" + getCacheLimit () + "), removing least used entry."); 594 595 Iterator entryIter = cache.entrySet().iterator(); 598 long minTime = Long.MAX_VALUE; 599 Object minEntryKey = null; 600 while (entryIter.hasNext()) { 601 Map.Entry curEntry = (Map.Entry) entryIter.next(); 602 CacheEntry curCacheEntry = (CacheEntry) curEntry.getValue(); 603 if (curCacheEntry.getLastAccessedTimeMillis() < minTime) { 604 minTime = curCacheEntry.getLastAccessedTimeMillis(); 605 minEntryKey = curEntry.getKey(); 606 } 607 } 608 remove(minEntryKey); 609 } 610 } 611 612 613 618 private synchronized void internalRemove (Object entryKey) { 619 if (entryKey == null) 620 return; 621 622 cache.remove (entryKey); 624 logger.debug ("Removed the entry [" + entryKey.toString () + 625 "] from cache [" + name + "]!"); 626 } 627 628 636 public synchronized void registerListener (CacheListener listener) { 637 if (listener == null) 638 return; 639 640 if (listeners == null) { 641 listeners = new ArrayList(); 642 643 } else if (listeners.contains (listener)) { 644 return; 645 } 646 647 listeners.add (listener); 648 } 649 650 658 public synchronized void unregisterListener (CacheListener listener) { 659 if ((listeners == null) || (listener == null)) 660 return; 661 662 listeners.remove (listener); 663 } 664 } 665 | Popular Tags |