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