KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > RolapAggregationManager


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/rolap/RolapAggregationManager.java#34 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2001-2002 Kana Software, Inc.
7 // Copyright (C) 2001-2007 Julian Hyde and others
8 // All Rights Reserved.
9 // You must accept the terms of that agreement to use this software.
10 //
11 // jhyde, 30 August, 2001
12 */

13
14 package mondrian.rolap;
15
16 import mondrian.olap.Evaluator;
17 import mondrian.olap.Hierarchy;
18 import mondrian.olap.Level;
19 import mondrian.olap.Member;
20 import mondrian.olap.Util;
21 import mondrian.rolap.agg.*;
22 import mondrian.olap.CacheControl;
23
24 import java.util.*;
25 import java.io.PrintWriter JavaDoc;
26
27 /**
28  * <code>RolapAggregationManager</code> manages all {@link
29  * mondrian.rolap.agg.Aggregation}s in the system. It is a singleton class.
30  *
31  * <p> The bits of the implementation which depend upon dimensional concepts
32  * <code>RolapMember</code>, etc.) live in this class, and the other bits live
33  * in the derived class, {@link mondrian.rolap.agg.AggregationManager}.
34  *
35  * @author jhyde
36  * @since 30 August, 2001
37  * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapAggregationManager.java#34 $
38  */

39 public abstract class RolapAggregationManager implements CellReader {
40
41     /**
42      * Creates a request to evaluate the cell identified by
43      * <code>members</code>. If any of the members is the null member, returns
44      * null, since there is no cell. If the measure is calculated, returns
45      * null.
46      *
47      * @param members Set of members which constrain the cell
48      * @param extendedContext If true, add non-constraining columns to the
49      * query for levels below each current member. This additional context
50      * makes the drill-through queries easier for humans to understand.
51      * @param drillThrough If true, request returns the list of fact table
52      * rows contributing to the cell
53      * @return Cell request, or null if the requst is unsatisfiable
54      */

55     public static CellRequest makeRequest(
56             final Member[] members,
57             final boolean extendedContext,
58             final boolean drillThrough) {
59
60         if (! (members[0] instanceof RolapStoredMeasure)) {
61             return null;
62         }
63
64         final RolapStoredMeasure measure = (RolapStoredMeasure) members[0];
65         final RolapStar.Measure starMeasure =
66                     (RolapStar.Measure) measure.getStarMeasure();
67         assert starMeasure != null;
68         final RolapStar star = starMeasure.getStar();
69         final CellRequest request =
70             new CellRequest(starMeasure, extendedContext, drillThrough);
71         final Map<RolapLevel, RolapStar.Column> levelToColumnMap =
72             star.getLevelToColumnMap(measure.getCube());
73
74         // Since 'request.extendedContext == false' is a well-worn code path,
75
// we have moved the test outside the loop.
76
if (request.extendedContext) {
77             for (int i = 1; i < members.length; i++) {
78                 final RolapMember member = (RolapMember) members[i];
79                 addNonConstrainingColumns(member, levelToColumnMap, request);
80
81                 final RolapLevel level = member.getLevel();
82                 final boolean needToReturnNull =
83                     level.getLevelReader().constrainRequest(
84                         member, levelToColumnMap, request);
85                 if (needToReturnNull) {
86                     return null;
87                 }
88             }
89         } else {
90             for (int i = 1; i < members.length; i++) {
91                 RolapMember member = (RolapMember) members[i];
92                 final RolapLevel level = member.getLevel();
93                 final boolean needToReturnNull =
94                     level.getLevelReader().constrainRequest(
95                         member, levelToColumnMap, request);
96                 if (needToReturnNull) {
97                     return null;
98                 }
99             }
100         }
101         return request;
102     }
103
104     /**
105      * Adds the key columns as non-constraining columns. For
106      * example, if they asked for [Gender].[M], [Store].[USA].[CA]
107      * then the following levels are in play:<ul>
108      * <li>Gender = 'M'
109      * <li>Marital Status not constraining
110      * <li>Nation = 'USA'
111      * <li>State = 'CA'
112      * <li>City not constraining
113      * </ul>
114      *
115      * <p>Note that [Marital Status] column is present by virtue of
116      * the implicit [Marital Status].[All] member. Hence the SQL
117      *
118      * <blockquote><pre>
119      * select [Marital Status], [City]
120      * from [Star]
121      * where [Gender] = 'M'
122      * and [Nation] = 'USA'
123      * and [State] = 'CA'
124      * </pre></blockquote>
125      *
126      * @param member Member to constraint
127      * @param levelToColumnMap Level to star column map
128      * @param request Cell request
129      */

130     private static void addNonConstrainingColumns(
131             final RolapMember member,
132             final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
133             final CellRequest request) {
134
135         final Hierarchy hierarchy = member.getHierarchy();
136         final Level[] levels = hierarchy.getLevels();
137         for (int j = levels.length - 1, depth = member.getLevel().getDepth();
138              j > depth; j--) {
139             final RolapLevel level = (RolapLevel) levels[j];
140             final RolapStar.Column column = levelToColumnMap.get(level);
141
142             if (column != null) {
143                 request.addConstrainedColumn(column, null);
144                 if (request.extendedContext &&
145                         level.getNameExp() != null) {
146                     final RolapStar.Column nameColumn = column.getNameColumn();
147                     Util.assertTrue(nameColumn != null);
148                     request.addConstrainedColumn(nameColumn, null);
149                 }
150             }
151         }
152     }
153
154     protected RolapAggregationManager() {
155     }
156
157     /**
158      * Returns the value of a cell from an existing aggregation.
159      */

160     public Object JavaDoc getCellFromCache(final Member[] members) {
161         final CellRequest request = makeRequest(members, false, false);
162         return (request == null)
163             // request out of bounds
164
? Util.nullValue
165             : getCellFromCache(request);
166     }
167
168     public abstract Object JavaDoc getCellFromCache(CellRequest request);
169
170     public abstract Object JavaDoc getCellFromCache(
171         CellRequest request,
172         PinSet pinSet);
173
174     public Object JavaDoc getCell(final Member[] members) {
175         final CellRequest request = makeRequest(members, false, false);
176         final RolapStoredMeasure measure = (RolapStoredMeasure) members[0];
177         final RolapStar.Measure starMeasure = (RolapStar.Measure)
178                 measure.getStarMeasure();
179
180         assert starMeasure != null;
181
182         final RolapStar star = starMeasure.getStar();
183         return star.getCell(request);
184     }
185
186     // implement CellReader
187
public Object JavaDoc get(final Evaluator evaluator) {
188         final RolapEvaluator rolapEvaluator = (RolapEvaluator) evaluator;
189         return getCell(rolapEvaluator.getMembers());
190     }
191
192     /**
193      * Generates a SQL statement which will return the rows which contribute to
194      * this request.
195      *
196      * @param request Cell request
197      * @param countOnly If true, return a statment which returns only the count
198      * @return SQL statement
199      */

200     public abstract String JavaDoc getDrillThroughSql(
201         CellRequest request,
202         boolean countOnly);
203
204     public int getMissCount() {
205         return 0; // never lies
206
}
207
208     /**
209      * Returns an API with which to explicitly manage the contents of the cache.
210      *
211      * @param pw Print writer, for tracing
212      * @return CacheControl API
213      */

214     public CacheControl getCacheControl(final PrintWriter JavaDoc pw) {
215         return new CacheControlImpl() {
216             protected void flushNonUnion(final CellRegion region) {
217                 final List<RolapStar> starList = getStarList(region);
218
219                 // For each of the candidate stars, scan the list of aggregates.
220
for (RolapStar star : starList) {
221                     star.flush(this, region);
222                 }
223             }
224
225             public void flush(final CellRegion region) {
226                 if (pw != null) {
227                     pw.println("Cache state before flush:");
228                     printCacheState(pw, region);
229                     pw.println();
230                 }
231                 super.flush(region);
232                 if (pw != null) {
233                     pw.println("Cache state after flush:");
234                     printCacheState(pw, region);
235                     pw.println();
236                 }
237             }
238
239             public void trace(final String JavaDoc message) {
240                 if (pw != null) {
241                     pw.println(message);
242                 }
243             }
244         };
245     }
246
247     public static RolapCacheRegion makeCacheRegion(
248         final RolapStar star,
249         final CacheControl.CellRegion region)
250     {
251         final List<Member> measureList = CacheControlImpl.findMeasures(region);
252         final List<RolapStar.Measure> starMeasureList =
253             new ArrayList<RolapStar.Measure>();
254         Map<RolapLevel, RolapStar.Column> levelToColumnMap = null;
255         for (Member measure : measureList) {
256             if (!(measure instanceof RolapStoredMeasure)) {
257                 continue;
258             }
259             final RolapStoredMeasure storedMeasure =
260                 (RolapStoredMeasure) measure;
261             final RolapStar.Measure starMeasure =
262                 (RolapStar.Measure) storedMeasure.getStarMeasure();
263             assert starMeasure != null;
264             if (star != starMeasure.getStar()) {
265                 continue;
266             }
267             // TODO: each time this code executes, levelToColumnMap is set.
268
// Should there be a 'break' here? Are all of the
269
// storedMeasure cubes the same cube? Is the measureList always
270
// non-empty so that levelToColumnMap is always set?
271
levelToColumnMap =
272                 star.getLevelToColumnMap(storedMeasure.getCube());
273             starMeasureList.add(starMeasure);
274         }
275         final RolapCacheRegion cacheRegion =
276             new RolapCacheRegion(star, starMeasureList);
277         if (region instanceof CacheControlImpl.CrossjoinCellRegion) {
278             final CacheControlImpl.CrossjoinCellRegion crossjoin =
279                 (CacheControlImpl.CrossjoinCellRegion) region;
280             for (CacheControl.CellRegion component : crossjoin.getComponents()) {
281                 constrainCacheRegion(cacheRegion, levelToColumnMap, component);
282             }
283         } else {
284             constrainCacheRegion(cacheRegion, levelToColumnMap, region);
285         }
286         return cacheRegion;
287     }
288
289     private static void constrainCacheRegion(
290         final RolapCacheRegion cacheRegion,
291         final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
292         final CacheControl.CellRegion region)
293     {
294         if (region instanceof CacheControlImpl.MemberCellRegion) {
295             final CacheControlImpl.MemberCellRegion memberCellRegion =
296                 (CacheControlImpl.MemberCellRegion) region;
297             final List<Member> memberList = memberCellRegion.getMemberList();
298             for (Member member : memberList) {
299                 final RolapMember rolapMember = (RolapMember) member;
300                 final RolapLevel level = rolapMember.getLevel();
301                 final RolapStar.Column column = levelToColumnMap.get(level);
302                 level.getLevelReader().constrainRegion(
303                     new MemberColumnPredicate(column, rolapMember),
304                     levelToColumnMap, cacheRegion);
305             }
306         } else if (region instanceof CacheControlImpl.MemberRangeCellRegion) {
307             final CacheControlImpl.MemberRangeCellRegion rangeRegion =
308                 (CacheControlImpl.MemberRangeCellRegion) region;
309             final RolapLevel level = rangeRegion.getLevel();
310             final RolapStar.Column column = levelToColumnMap.get(level);
311             level.getLevelReader().constrainRegion(
312                 new RangeColumnPredicate(
313                     column,
314                     rangeRegion.getLowerInclusive(),
315                     (rangeRegion.getLowerBound() == null ?
316                         null :
317                         new MemberColumnPredicate(
318                             column, rangeRegion.getLowerBound())),
319                     rangeRegion.getUpperInclusive(),
320                     (rangeRegion.getUpperBound() == null ?
321                         null :
322                         new MemberColumnPredicate(
323                             column, rangeRegion.getUpperBound()))),
324                 levelToColumnMap, cacheRegion);
325         } else {
326             throw new UnsupportedOperationException JavaDoc();
327         }
328     }
329
330     /**
331      * Creates a {@link PinSet}.
332      *
333      * @return a new PinSet
334      */

335     public abstract PinSet createPinSet();
336
337     /**
338      * A set of segments which are pinned for a short duration as a result of a
339      * cache inquiry.
340      */

341     public interface PinSet {}
342 }
343
344 // End RolapAggregationManager.java
345
Popular Tags