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}