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