001package gu.sql2java; 002 003import static com.google.common.base.Preconditions.*; 004import static gu.sql2java.SimpleLog.*; 005 006import java.util.Map; 007import java.util.concurrent.TimeUnit; 008 009import com.google.common.cache.CacheBuilder; 010import com.google.common.collect.ImmutableMap; 011 012import gu.sql2java.TableManager.Action; 013import gu.sql2java.exception.ObjectRetrievalException; 014import gu.sql2java.exception.RuntimeDaoException; 015 016public class TableCache<B extends BaseBean> extends ColumnCache<B> 017 implements TableListener<B>{ 018 private final Map<String, IKeyCache<B>> indexCachers; 019 /** 020 * constructor<br> 021 * @param metaData meta data for table 022 * @param updateStrategy cache update strategy,{@link Constant#DEFAULT_STRATEGY} be used if {@code null} 023 * @param maximumSize maximum capacity of cache ,{@link Constant#DEFAULT_CACHE_MAXIMUMSIZE } be used if {@code null} or <=0,see also {@link CacheBuilder#maximumSize(long)} 024 * @param duration cache data expired time,{@link Constant#DEFAULT_DURATION} be used if {@code null} or <=0,see also {@link CacheBuilder#expireAfterWrite(long, TimeUnit)} 025 * @param unit time unit for {@code duration},{@link Constant#DEFAULT_TIME_UNIT} be used if {@code null} ,see also {@link CacheBuilder#expireAfterWrite(long, TimeUnit)} 026 */ 027 public TableCache(RowMetaData metaData,UpdateStrategy updateStrategy,Long maximumSize, Long duration, TimeUnit unit) { 028 super(metaData,null,updateStrategy,maximumSize, duration, unit); 029 ImmutableMap.Builder<String, IKeyCache<B>> builder = ImmutableMap.builder(); 030 for(IndexMetaData index : metaData.getUniqueIndices().values()){ 031 builder.put( 032 index.name, 033 new ColumnCache<B>( 034 this.metaData, 035 index.name, 036 this.updateStrategy, 037 this.maximumSize, 038 this.duration, 039 this.unit)); 040 } 041 indexCachers = builder.build(); 042 manager.bindForeignKeyListenerForDeleteRule(); 043 } 044 /** ×¢²áÕìÌýÆ÷ */ 045 public void registerListener() { 046 manager.registerListener(this); 047 if(debug){ 048 log("REGISTER LISTENER FOR INDEX AND PRIMARY KEY of " + metaData.tablename); 049 } 050 } 051 /** ×¢ÏúÕìÌýÆ÷ */ 052 public void unregisterListener() { 053 manager.unregisterListener(this); 054 } 055 056 /** 057 * force update bean to all caches that excluding specified by {@link #recursive} 058 * @param bean 059 */ 060 private void updateAll(B bean){ 061 update(bean, UpdateStrategy.always); 062 for(IKeyCache<B> cache : indexCachers.values()){ 063 cache.update(bean, UpdateStrategy.always); 064 } 065 } 066 /** 067 * return record (B) that unique indexed by 'keys' 068 * @param indexName index name 069 * @param keys values for index key 070 * @return B instance if found 071 * @throws ObjectRetrievalException not found record 072 */ 073 public B getBeanByIndex(String indexName,Object... keys)throws ObjectRetrievalException{ 074 return checkNotNull(indexCachers.get(indexName),"INVALID indexName %s",indexName).getBean(keys); 075 } 076 /** 077 * return record (B) that unique indexed by 'keys' 078 * @param indexName index name 079 * @param keys values for index key 080 * @return B instance if found,or null 081 */ 082 public B getBeanByIndexUnchecked(String indexName,Object... keys){ 083 return checkNotNull(indexCachers.get(indexName),"INVALID indexName %s",indexName).getBeanUnchecked(keys); 084 } 085 086 /** 087 * wrap the 'action' for updating cache while retrieve data from database 088 * @param action 089 * @return Action 090 */ 091 public Action<B> wrap(Action<B> action){ 092 if(action != null){ 093 if(!(action instanceof TableCache.CacheWrapper)){ 094 action = new CacheWrapper(action); 095 } 096 } 097 return action; 098 } 099 100 ////////////////////////////////////////////// 101 // TableListener IMPLEMENTATION 102 ////////////////////////////////////////////// 103 104 @Override 105 public void afterUpdate(B bean) { 106 update(bean); 107 for(IKeyCache<B> cache : indexCachers.values()){ 108 cache.update(bean); 109 } 110 } 111 112 @Override 113 public void afterInsert(B bean) { 114 update(bean); 115 for(IKeyCache<B> cache : indexCachers.values()){ 116 cache.update(bean); 117 } 118 } 119 120 @Override 121 public void afterDelete(B bean) { 122 remove(bean); 123 for(IKeyCache<B> cache : indexCachers.values()){ 124 cache.remove(bean); 125 } 126 } 127 128 @Override 129 public void beforeInsert(B bean) throws RuntimeDaoException {} 130 @Override 131 public void beforeUpdate(B bean) throws RuntimeDaoException {} 132 @Override 133 public void beforeDelete(B bean) throws RuntimeDaoException {} 134 @Override 135 public void done() throws RuntimeDaoException {} 136 137 @Override 138 public int hashCode() { 139 final int prime = 31; 140 int result = super.hashCode(); 141 result = prime * result + ((indexCachers == null) ? 0 : indexCachers.hashCode()); 142 return result; 143 } 144 @Override 145 public boolean equals(Object obj) { 146 if (this == obj) { 147 return true; 148 } 149 if (!super.equals(obj)) { 150 return false; 151 } 152 if (!(obj instanceof TableCache)) { 153 return false; 154 } 155 TableCache<?> other = (TableCache<?>) obj; 156 if (indexCachers == null) { 157 if (other.indexCachers != null) { 158 return false; 159 } 160 } else if (!indexCachers.equals(other.indexCachers)) { 161 return false; 162 } 163 return true; 164 } 165 @Override 166 public String toString() { 167 StringBuilder builder = new StringBuilder(); 168 builder.append("TableCache [super="); 169 builder.append(super.toString()); 170 builder.append(",indexCachers="); 171 builder.append(indexCachers); 172 builder.append("]"); 173 return builder.toString(); 174 } 175 private class CacheWrapper implements Action<B>{ 176 private final Action<B> action; 177 public CacheWrapper(Action<B>action){ 178 this.action = checkNotNull(action,"action is null"); 179 } 180 @Override 181 public void call(B bean) { 182 action.call(bean); 183 updateAll(bean); 184 } 185 } 186}