001    /*
002    // $Id: //open/mondrian-release/3.1/src/main/mondrian/rolap/SmartMemberListCache.java#2 $
003    // This software is subject to the terms of the Eclipse Public License v1.0
004    // Agreement, available at the following URL:
005    // http://www.eclipse.org/legal/epl-v10.html.
006    // Copyright (C) 2004-2005 TONBELLER AG
007    // Copyright (C) 2006-2009 Julian Hyde
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    */
011    package mondrian.rolap;
012    
013    import mondrian.rolap.cache.SmartCache;
014    import mondrian.rolap.cache.SoftSmartCache;
015    import mondrian.rolap.sql.SqlConstraint;
016    
017    /**
018     * Uses a {@link mondrian.rolap.cache.SmartCache} to store lists of members,
019     * where the key depends on a {@link mondrian.rolap.sql.SqlConstraint}.
020     *
021     * <p>Example 1:
022     *
023     * <pre>
024     *   select ...
025     *   [Customer].[Name].members on rows
026     *   ...
027     * </pre>
028     *
029     * <p>Example 2:
030     * <pre>
031     *   select ...
032     *   NON EMPTY [Customer].[Name].members on rows
033     *   ...
034     *   WHERE ([Store#14], [Product].[Product#1])
035     * </pre>
036     *
037     * <p>The first set, <em>all</em> customers are computed, in the second only
038     * those, who have bought Product#1 in Store#14. We want to put both results
039     * into the cache. Then the key for the cache entry is the Level that the
040     * members belong to <em>plus</em> the costraint that restricted the amount of
041     * members fetched. For Level.Members the key consists of the Level and the
042     * cacheKey of the {@link mondrian.rolap.sql.SqlConstraint}.
043     *
044     * @see mondrian.rolap.sql.SqlConstraint#getCacheKey
045     *
046     * @author av
047     * @since Nov 21, 2005
048     * @version $Id: //open/mondrian-release/3.1/src/main/mondrian/rolap/SmartMemberListCache.java#2 $
049     */
050    public class SmartMemberListCache <K, V> {
051        SmartCache<Key2<K, Object>, V> cache;
052    
053        /**
054         * a HashMap key that consists of two components.
055         */
056        static class Key2 <T1, T2> {
057            T1 o1;
058            T2 o2;
059    
060            public Key2(T1 o1, T2 o2) {
061                this.o1 = o1;
062                this.o2 = o2;
063            }
064    
065            public boolean equals(Object obj) {
066                if (!(obj instanceof Key2)) {
067                    return false;
068                }
069                Key2 that = (Key2) obj;
070                return equals(this.o1, that.o1) && equals(this.o2, that.o2);
071            }
072    
073            private boolean equals(Object o1, Object o2) {
074                return o1 == null ? o2 == null : o1.equals(o2);
075            }
076    
077            public int hashCode() {
078                int c = 1;
079                if (o1 != null) {
080                    c = o1.hashCode();
081                }
082                if (o2 != null) {
083                    c = 31 * c + o2.hashCode();
084                }
085                return c;
086            }
087    
088            public String toString() {
089                return "key(" + o1 + "," + o2 + ")";
090            }
091        }
092    
093        public SmartMemberListCache() {
094            cache = new SoftSmartCache<Key2<K, Object>, V>();
095        }
096    
097        public Object put(K key, SqlConstraint constraint, V value) {
098            Object cacheKey = constraint.getCacheKey();
099            if (cacheKey == null) {
100                return null;
101            }
102            Key2<K, Object> key2 = new Key2<K, Object>(key, cacheKey);
103            return cache.put(key2, value);
104        }
105    
106        public V get(K key, SqlConstraint constraint) {
107            Key2<K, Object> key2 =
108                new Key2<K, Object>(key, constraint.getCacheKey());
109            return cache.get(key2);
110        }
111    
112        public void clear() {
113            cache.clear();
114        }
115    
116        SmartCache<Key2<K, Object>, V> getCache() {
117            return cache;
118        }
119    
120        void setCache(SmartCache<Key2<K, Object>, V> cache) {
121            this.cache = cache;
122        }
123    }
124    
125    // End SmartMemberListCache.java