/* */ package org.jboss.ejb.plugins.cmp.jdbc;
/* */
/* */ import java.lang.ref.SoftReference;
/* */ import java.util.Collection;
/* */ import java.util.Collections;
/* */ import java.util.HashMap;
/* */ import java.util.HashSet;
/* */ import java.util.Iterator;
/* */ import java.util.LinkedList;
/* */ import java.util.List;
/* */ import java.util.Map;
/* */ import java.util.Map.Entry;
/* */ import java.util.Set;
/* */ import javax.transaction.SystemException;
/* */ import javax.transaction.Transaction;
/* */ import javax.transaction.TransactionManager;
/* */ import org.jboss.ejb.EntityEnterpriseContext;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractCMRFieldBridge;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMPFieldBridge;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
/* */ import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData;
/* */ import org.jboss.logging.Logger;
/* */ import org.jboss.tm.TransactionLocal;
/* */
/* */ public final class ReadAheadCache
/* */ {
/* 60 */ private static final Object NULL_VALUE = new Object();
/* */ private final JDBCStoreManager manager;
/* */ private final Logger log;
/* 65 */ private final TransactionLocal listMapTxLocal = new TransactionLocal()
/* */ {
/* */ protected Object initialValue()
/* */ {
/* 69 */ return new HashMap();
/* */ }
/* */
/* */ public Transaction getTransaction()
/* */ {
/* */ try
/* */ {
/* 76 */ return this.transactionManager.getTransaction();
/* */ }
/* */ catch (SystemException e) {
/* */ }
/* 80 */ throw new IllegalStateException("An error occured while getting the transaction associated with the current thread: " + e);
/* */ }
/* 65 */ };
/* */ private ListCache listCache;
/* */ private int listCacheMax;
/* */
/* */ public ReadAheadCache(JDBCStoreManager manager)
/* */ {
/* 91 */ this.manager = manager;
/* */
/* 94 */ this.log = Logger.getLogger(getClass().getName() + "." + manager.getMetaData().getName());
/* */ }
/* */
/* */ public void create()
/* */ {
/* 103 */ this.listCacheMax = ((JDBCEntityBridge)this.manager.getEntityBridge()).getListCacheMax();
/* 104 */ this.listCache = new ListCache(this.listCacheMax);
/* */ }
/* */
/* */ public void start()
/* */ {
/* */ }
/* */
/* */ public void stop()
/* */ {
/* 113 */ this.listCache.clear();
/* */ }
/* */
/* */ public void destroy()
/* */ {
/* 118 */ this.listCache = null;
/* */ }
/* */
/* */ public void addFinderResults(List results, JDBCReadAheadMetaData readahead)
/* */ {
/* 123 */ if ((this.listCacheMax == 0) || (results.size() < 2))
/* */ {
/* 126 */ return;
/* */ }
/* */
/* 129 */ Map listMap = getListMap();
/* 130 */ if (listMap == null)
/* */ {
/* 133 */ return;
/* */ }
/* */
/* 136 */ if (this.log.isTraceEnabled())
/* */ {
/* 138 */ this.log.trace("Add finder results: entity=" + this.manager.getEntityBridge().getEntityName() + " results=" + results + " readahead=" + readahead);
/* */ }
/* */
/* 145 */ if (!readahead.isNone())
/* */ {
/* 147 */ this.listCache.add(results);
/* */ }
/* */
/* 155 */ HashSet dereferencedResults = new HashSet();
/* 156 */ Iterator iter = results.iterator();
/* 157 */ for (int i = 0; iter.hasNext(); i++)
/* */ {
/* 159 */ Object pk = iter.next();
/* */ EntityMapEntry entry;
/* */ EntityMapEntry entry;
/* 163 */ if (readahead.isNone())
/* */ {
/* 165 */ entry = new EntityMapEntry(0, Collections.singletonList(pk), readahead, null);
/* */ }
/* */ else
/* */ {
/* 169 */ entry = new EntityMapEntry(i, results, readahead, null);
/* */ }
/* */
/* 174 */ EntityMapEntry oldInfo = (EntityMapEntry)listMap.put(pk, entry);
/* 175 */ if (oldInfo == null)
/* */ continue;
/* 177 */ dereferencedResults.add(oldInfo.results);
/* */ }
/* */
/* 187 */ if (dereferencedResults.isEmpty())
/* */ {
/* 189 */ return;
/* */ }
/* */
/* 198 */ iter = dereferencedResults.iterator();
/* 199 */ while (iter.hasNext())
/* */ {
/* 201 */ List dereferencedList = (List)iter.next();
/* */
/* 203 */ boolean listHasReference = false;
/* 204 */ Iterator iter2 = dereferencedList.iterator();
/* 205 */ while ((!listHasReference) && (iter2.hasNext()))
/* */ {
/* 208 */ EntityMapEntry entry = (EntityMapEntry)listMap.get(iter2.next());
/* 209 */ if ((entry != null) && (entry.results == dereferencedList))
/* */ {
/* 211 */ listHasReference = true;
/* */ }
/* */ }
/* */
/* 215 */ if (listHasReference)
/* */ {
/* 218 */ iter.remove();
/* */ }
/* */
/* */ }
/* */
/* 223 */ if (dereferencedResults.isEmpty())
/* */ {
/* 225 */ return;
/* */ }
/* */
/* 229 */ iter = dereferencedResults.iterator();
/* 230 */ while (iter.hasNext())
/* */ {
/* 232 */ List list = (List)iter.next();
/* 233 */ if (this.log.isTraceEnabled())
/* */ {
/* 235 */ this.log.trace("Removing dereferenced results: " + list);
/* */ }
/* 237 */ this.listCache.remove(list);
/* */ }
/* */ }
/* */
/* */ private void removeFinderResult(List results)
/* */ {
/* 243 */ Map listMap = getListMap();
/* 244 */ if (listMap == null)
/* */ {
/* 247 */ return;
/* */ }
/* */
/* 251 */ this.listCache.remove(results);
/* */
/* 254 */ if (!listMap.isEmpty())
/* */ {
/* 256 */ Iterator iter = listMap.values().iterator();
/* 257 */ while (iter.hasNext())
/* */ {
/* 259 */ EntityMapEntry entry = (EntityMapEntry)iter.next();
/* */
/* 262 */ if (entry.results == results)
/* */ {
/* 264 */ iter.remove();
/* */ }
/* */ }
/* */ }
/* */ }
/* */
/* */ public EntityReadAheadInfo getEntityReadAheadInfo(Object pk)
/* */ {
/* 272 */ Map listMap = getListMap();
/* 273 */ if (listMap == null)
/* */ {
/* 276 */ return new EntityReadAheadInfo(Collections.singletonList(pk), null);
/* */ }
/* */
/* 279 */ EntityMapEntry entry = (EntityMapEntry)getListMap().get(pk);
/* 280 */ if (entry != null)
/* */ {
/* 284 */ if (!entry.readahead.isNone())
/* */ {
/* 286 */ this.listCache.promote(entry.results);
/* */ }
/* */
/* 290 */ JDBCReadAheadMetaData readahead = entry.readahead;
/* 291 */ if (readahead == null)
/* */ {
/* 293 */ readahead = this.manager.getMetaData().getReadAhead();
/* */ }
/* */
/* 296 */ int from = entry.index;
/* 297 */ int to = Math.min(entry.results.size(), entry.index + readahead.getPageSize());
/* 298 */ List loadKeys = entry.results.subList(from, to);
/* */
/* 300 */ return new EntityReadAheadInfo(loadKeys, readahead, null);
/* */ }
/* */
/* 304 */ return new EntityReadAheadInfo(Collections.singletonList(pk), null);
/* */ }
/* */
/* */ public boolean load(EntityEnterpriseContext ctx)
/* */ {
/* 315 */ if (this.log.isTraceEnabled())
/* */ {
/* 317 */ this.log.trace("load data: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + ctx.getId());
/* */ }
/* */
/* 323 */ Map preloadDataMap = getPreloadDataMap(ctx.getId(), false);
/* 324 */ if ((preloadDataMap == null) || (preloadDataMap.isEmpty()))
/* */ {
/* 327 */ if (this.log.isTraceEnabled())
/* */ {
/* 329 */ this.log.trace("No preload data found: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + ctx.getId());
/* */ }
/* */
/* 333 */ return false;
/* */ }
/* */
/* 336 */ boolean cleanReadAhead = this.manager.getMetaData().isCleanReadAheadOnLoad();
/* */
/* 338 */ boolean loaded = false;
/* 339 */ JDBCCMRFieldBridge onlyOneSingleValuedCMR = null;
/* */
/* 342 */ Iterator iter = preloadDataMap.entrySet().iterator();
/* 343 */ while (iter.hasNext())
/* */ {
/* 345 */ Map.Entry entry = (Map.Entry)iter.next();
/* 346 */ Object field = entry.getKey();
/* */
/* 349 */ Object value = entry.getValue();
/* */
/* 352 */ if (value == null)
/* */ {
/* 354 */ throw new IllegalStateException("Preloaded value not found");
/* */ }
/* */
/* 357 */ if (cleanReadAhead)
/* */ {
/* 360 */ iter.remove();
/* */ }
/* */
/* 364 */ if (value == NULL_VALUE)
/* */ {
/* 366 */ value = null;
/* */ }
/* */
/* 369 */ if ((field instanceof JDBCCMPFieldBridge))
/* */ {
/* 371 */ JDBCCMPFieldBridge cmpField = (JDBCCMPFieldBridge)field;
/* */
/* 373 */ if (!cmpField.isLoaded(ctx))
/* */ {
/* 375 */ if (this.log.isTraceEnabled())
/* */ {
/* 377 */ this.log.trace("Preloading data: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + ctx.getId() + " cmpField=" + cmpField.getFieldName());
/* */ }
/* */
/* 384 */ cmpField.setInstanceValue(ctx, value);
/* */
/* 387 */ cmpField.setClean(ctx);
/* */
/* 389 */ loaded = true;
/* */ }
/* 393 */ else if (this.log.isTraceEnabled())
/* */ {
/* 395 */ this.log.trace("CMPField already loaded: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + ctx.getId() + " cmpField=" + cmpField.getFieldName());
/* */ }
/* */
/* */ }
/* 402 */ else if ((field instanceof JDBCCMRFieldBridge))
/* */ {
/* 404 */ JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)field;
/* */
/* 406 */ if (!cmrField.isLoaded(ctx))
/* */ {
/* 408 */ if (this.log.isTraceEnabled())
/* */ {
/* 410 */ this.log.trace("Preloading data: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + ctx.getId() + " cmrField=" + cmrField.getFieldName());
/* */ }
/* */
/* 417 */ cmrField.load(ctx, (List)value);
/* */
/* 420 */ JDBCStoreManager relatedManager = (JDBCStoreManager)cmrField.getRelatedCMRField().getManager();
/* 421 */ ReadAheadCache relatedReadAheadCache = relatedManager.getReadAheadCache();
/* */
/* 423 */ relatedReadAheadCache.addFinderResults((List)value, cmrField.getReadAhead());
/* */
/* 426 */ if (!loaded)
/* */ {
/* 429 */ if ((cmrField.isSingleValued()) && (onlyOneSingleValuedCMR == null))
/* */ {
/* 431 */ onlyOneSingleValuedCMR = cmrField;
/* */ }
/* */ else
/* */ {
/* 435 */ loaded = true;
/* */ }
/* */
/* */ }
/* */
/* */ }
/* 441 */ else if (this.log.isTraceEnabled())
/* */ {
/* 443 */ this.log.trace("CMRField already loaded: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + ctx.getId() + " cmrField=" + cmrField.getFieldName());
/* */ }
/* */
/* */ }
/* */
/* */ }
/* */
/* 452 */ if (cleanReadAhead)
/* */ {
/* 455 */ this.manager.removeEntityTxData(new PreloadKey(ctx.getId()));
/* */ }
/* */
/* 458 */ return loaded;
/* */ }
/* */
/* */ public Collection getCachedCMRValue(Object pk, JDBCCMRFieldBridge cmrField)
/* */ {
/* 469 */ Map preloadDataMap = getPreloadDataMap(pk, true);
/* 470 */ return (Collection)preloadDataMap.get(cmrField);
/* */ }
/* */
/* */ public void addPreloadData(Object pk, JDBCFieldBridge field, Object fieldValue)
/* */ {
/* 480 */ if ((field instanceof JDBCCMRFieldBridge))
/* */ {
/* 482 */ if (fieldValue == null)
/* */ {
/* 484 */ fieldValue = Collections.EMPTY_LIST;
/* */ }
/* 486 */ else if (!(fieldValue instanceof Collection))
/* */ {
/* 488 */ fieldValue = Collections.singletonList(fieldValue);
/* */ }
/* */ }
/* */
/* 492 */ if (this.log.isTraceEnabled())
/* */ {
/* 494 */ this.log.trace("Add preload data: entity=" + this.manager.getEntityBridge().getEntityName() + " pk=" + pk + " field=" + field.getFieldName());
/* */ }
/* */
/* 501 */ if (fieldValue == null)
/* */ {
/* 503 */ fieldValue = NULL_VALUE;
/* */ }
/* */
/* 507 */ Map preloadDataMap = getPreloadDataMap(pk, true);
/* 508 */ Object overriden = preloadDataMap.put(field, fieldValue);
/* */
/* 510 */ if ((this.log.isTraceEnabled()) && (overriden != null))
/* */ {
/* 512 */ this.log.trace("Overriding cached value " + overriden + " with " + (fieldValue == NULL_VALUE ? null : fieldValue) + ". pk=" + pk + ", field=" + field.getFieldName());
/* */ }
/* */ }
/* */
/* */ public void removeCachedData(Object primaryKey)
/* */ {
/* 523 */ if (this.log.isTraceEnabled())
/* */ {
/* 525 */ this.log.trace("Removing cached data for " + primaryKey);
/* */ }
/* */
/* 528 */ Map listMap = getListMap();
/* 529 */ if (listMap == null)
/* */ {
/* 532 */ return;
/* */ }
/* */
/* 536 */ this.manager.removeEntityTxData(new PreloadKey(primaryKey));
/* */
/* 540 */ EntityMapEntry oldInfo = (EntityMapEntry)listMap.remove(primaryKey);
/* 541 */ if ((oldInfo == null) || (oldInfo.readahead.isNone()))
/* */ {
/* 543 */ return;
/* */ }
/* */
/* 547 */ Iterator iter = listMap.values().iterator();
/* 548 */ while (iter.hasNext())
/* */ {
/* 550 */ EntityMapEntry entry = (EntityMapEntry)iter.next();
/* */
/* 553 */ if (entry.results == oldInfo.results)
/* */ {
/* 556 */ return;
/* */ }
/* */
/* */ }
/* */
/* 561 */ if (this.log.isTraceEnabled())
/* */ {
/* 563 */ this.log.trace("Removing dereferenced finder results: " + oldInfo.results);
/* */ }
/* */
/* 566 */ this.listCache.remove(oldInfo.results);
/* */ }
/* */
/* */ public Map getPreloadDataMap(Object entityPrimaryKey, boolean create)
/* */ {
/* 584 */ PreloadKey preloadKey = new PreloadKey(entityPrimaryKey);
/* */
/* 587 */ SoftReference ref = (SoftReference)this.manager.getEntityTxData(preloadKey);
/* */
/* 590 */ if (ref != null)
/* */ {
/* 593 */ Map preloadDataMap = (Map)ref.get();
/* */
/* 596 */ if (preloadDataMap != null)
/* */ {
/* 598 */ return preloadDataMap;
/* */ }
/* */
/* */ }
/* */
/* 606 */ if (ref != null)
/* */ {
/* 609 */ this.manager.removeEntityTxData(preloadKey);
/* */ }
/* */
/* 613 */ if (!create)
/* */ {
/* 615 */ return null;
/* */ }
/* */
/* 619 */ Map preloadDataMap = new HashMap();
/* */
/* 622 */ ref = new SoftReference(preloadDataMap);
/* */
/* 625 */ this.manager.putEntityTxData(preloadKey, ref);
/* */
/* 628 */ return preloadDataMap;
/* */ }
/* */
/* */ private Map getListMap()
/* */ {
/* 633 */ return (Map)this.listMapTxLocal.get();
/* */ }
/* */
/* */ private static final class IdentityObject
/* */ {
/* */ private final Object object;
/* */
/* */ public IdentityObject(Object object)
/* */ {
/* 832 */ if (object == null)
/* */ {
/* 834 */ throw new IllegalArgumentException("Object is null");
/* */ }
/* 836 */ this.object = object;
/* */ }
/* */
/* */ public Object getObject()
/* */ {
/* 841 */ return this.object;
/* */ }
/* */
/* */ public boolean equals(Object object)
/* */ {
/* 846 */ return this.object == object;
/* */ }
/* */
/* */ public int hashCode()
/* */ {
/* 851 */ return this.object.hashCode();
/* */ }
/* */
/* */ public String toString()
/* */ {
/* 856 */ return this.object.toString();
/* */ }
/* */ }
/* */
/* */ public static final class EntityReadAheadInfo
/* */ {
/* */ private final List loadKeys;
/* */ private final JDBCReadAheadMetaData readahead;
/* */
/* */ private EntityReadAheadInfo(List loadKeys)
/* */ {
/* 803 */ this(loadKeys, null);
/* */ }
/* */
/* */ private EntityReadAheadInfo(List loadKeys, JDBCReadAheadMetaData r)
/* */ {
/* 808 */ this.loadKeys = loadKeys;
/* 809 */ this.readahead = r;
/* */ }
/* */
/* */ public List getLoadKeys()
/* */ {
/* 814 */ return this.loadKeys;
/* */ }
/* */
/* */ public JDBCReadAheadMetaData getReadAhead()
/* */ {
/* 819 */ return this.readahead;
/* */ }
/* */ }
/* */
/* */ private static final class EntityMapEntry
/* */ {
/* */ public final int index;
/* */ public final List results;
/* */ public final JDBCReadAheadMetaData readahead;
/* */
/* */ private EntityMapEntry(int index, List results, JDBCReadAheadMetaData readahead)
/* */ {
/* 790 */ this.index = index;
/* 791 */ this.results = results;
/* 792 */ this.readahead = readahead;
/* */ }
/* */ }
/* */
/* */ private static final class PreloadKey
/* */ {
/* */ private final Object entityPrimaryKey;
/* */
/* */ public PreloadKey(Object entityPrimaryKey)
/* */ {
/* 750 */ if (entityPrimaryKey == null)
/* */ {
/* 752 */ throw new IllegalArgumentException("Entity primary key is null");
/* */ }
/* 754 */ this.entityPrimaryKey = entityPrimaryKey;
/* */ }
/* */
/* */ public boolean equals(Object object)
/* */ {
/* 759 */ if ((object instanceof PreloadKey))
/* */ {
/* 761 */ PreloadKey preloadKey = (PreloadKey)object;
/* 762 */ return preloadKey.entityPrimaryKey.equals(this.entityPrimaryKey);
/* */ }
/* 764 */ return false;
/* */ }
/* */
/* */ public int hashCode()
/* */ {
/* 769 */ return this.entityPrimaryKey.hashCode();
/* */ }
/* */
/* */ public String toString()
/* */ {
/* 774 */ return "PreloadKey: entityId=" + this.entityPrimaryKey;
/* */ }
/* */ }
/* */
/* */ private final class ListCache
/* */ {
/* 638 */ private final TransactionLocal cacheTxLocal = new TransactionLocal()
/* */ {
/* */ protected Object initialValue()
/* */ {
/* 642 */ return new LinkedList();
/* */ }
/* */
/* */ public Transaction getTransaction()
/* */ {
/* */ try
/* */ {
/* 649 */ return this.transactionManager.getTransaction();
/* */ }
/* */ catch (SystemException e) {
/* */ }
/* 653 */ throw new IllegalStateException("An error occured while getting the transaction associated with the current thread: " + e);
/* */ }
/* 638 */ };
/* */ private int max;
/* */
/* */ public ListCache(int max)
/* */ {
/* 662 */ if (max < 0)
/* 663 */ throw new IllegalArgumentException("list-cache-max is negative: " + max);
/* 664 */ this.max = max;
/* */ }
/* */
/* */ public void add(List list)
/* */ {
/* 669 */ if (this.max == 0)
/* */ {
/* 672 */ return;
/* */ }
/* */
/* 675 */ LinkedList cache = getCache();
/* 676 */ if (cache == null)
/* 677 */ return;
/* 678 */ cache.addFirst(new ReadAheadCache.IdentityObject(list));
/* */
/* 681 */ while (cache.size() > this.max)
/* */ {
/* 683 */ ReadAheadCache.IdentityObject object = (ReadAheadCache.IdentityObject)cache.removeLast();
/* 684 */ ageOut((List)object.getObject());
/* */ }
/* */ }
/* */
/* */ public void promote(List list)
/* */ {
/* 690 */ if (this.max == 0)
/* */ {
/* 693 */ return;
/* */ }
/* */
/* 696 */ LinkedList cache = getCache();
/* 697 */ if (cache == null) {
/* 698 */ return;
/* */ }
/* 700 */ ReadAheadCache.IdentityObject object = new ReadAheadCache.IdentityObject(list);
/* 701 */ if (cache.remove(object))
/* */ {
/* 704 */ cache.addFirst(object);
/* */ }
/* */ }
/* */
/* */ public void remove(List list)
/* */ {
/* 710 */ if (this.max == 0)
/* */ {
/* 713 */ return;
/* */ }
/* 715 */ LinkedList cache = getCache();
/* 716 */ if (cache != null)
/* 717 */ cache.remove(new ReadAheadCache.IdentityObject(list));
/* */ }
/* */
/* */ public void clear()
/* */ {
/* 722 */ if (this.max == 0)
/* */ {
/* 725 */ return;
/* */ }
/* */ }
/* */
/* */ private void ageOut(List list)
/* */ {
/* 731 */ ReadAheadCache.this.removeFinderResult(list);
/* */ }
/* */
/* */ private LinkedList getCache()
/* */ {
/* 736 */ return (LinkedList)this.cacheTxLocal.get();
/* */ }
/* */ }
/* */ }
/* Location: /home/mnovotny/projects/EMBEDDED_JBOSS_BETA3_COMMUNITY/embedded/output/lib/embedded-jboss/lib/jboss-embedded-all.jar
* Qualified Name: org.jboss.ejb.plugins.cmp.jdbc.ReadAheadCache
* JD-Core Version: 0.6.0
*/