KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > olap > fun > TopBottomPercentSumFunDef


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/olap/fun/TopBottomPercentSumFunDef.java#5 $
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) 2002-2002 Kana Software, Inc.
7 // Copyright (C) 2002-2007 Julian Hyde and others
8 // All Rights Reserved.
9 // You must accept the terms of that agreement to use this software.
10 */

11 package mondrian.olap.fun;
12
13 import mondrian.calc.*;
14 import mondrian.calc.impl.AbstractListCalc;
15 import mondrian.mdx.ResolvedFunCall;
16 import mondrian.olap.*;
17
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20
21 /**
22  * Definition of the <code>TopPercent</code>, <code>BottomPercent</code>,
23  * <code>TopSum</code> and <code>BottomSum</code> MDX builtin functions.
24  *
25  * @author jhyde
26  * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/TopBottomPercentSumFunDef.java#5 $
27  * @since Mar 23, 2006
28  */

29 class TopBottomPercentSumFunDef extends FunDefBase {
30     /**
31      * Whether to calculate top (as opposed to bottom).
32      */

33     final boolean top;
34     /**
35      * Whether to calculate percent (as opposed to sum).
36      */

37     final boolean percent;
38
39     static final ResolverImpl TopPercentResolver = new ResolverImpl(
40             "TopPercent",
41             "TopPercent(<Set>, <Percentage>, <Numeric Expression>)",
42             "Sorts a set and returns the top N elements whose cumulative total is at least a specified percentage.",
43             new String JavaDoc[]{"fxxnn"}, true, true);
44
45     static final ResolverImpl BottomPercentResolver = new ResolverImpl(
46             "BottomPercent",
47             "BottomPercent(<Set>, <Percentage>, <Numeric Expression>)",
48             "Sorts a set and returns the bottom N elements whose cumulative total is at least a specified percentage.",
49             new String JavaDoc[]{"fxxnn"}, false, true);
50
51     static final ResolverImpl TopSumResolver = new ResolverImpl(
52             "TopSum",
53             "TopSum(<Set>, <Value>, <Numeric Expression>)",
54             "Sorts a set and returns the top N elements whose cumulative total is at least a specified value.",
55             new String JavaDoc[]{"fxxnn"}, true, false);
56
57     static final ResolverImpl BottomSumResolver = new ResolverImpl(
58             "BottomSum",
59             "BottomSum(<Set>, <Value>, <Numeric Expression>)",
60             "Sorts a set and returns the bottom N elements whose cumulative total is at least a specified value.",
61             new String JavaDoc[]{"fxxnn"}, false, false);
62
63     public TopBottomPercentSumFunDef(
64             FunDef dummyFunDef, boolean top, boolean percent) {
65         super(dummyFunDef);
66         this.top = top;
67         this.percent = percent;
68     }
69
70     public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
71         final ListCalc listCalc = (ListCalc) compiler.compile(call.getArg(0),
72                     ExpCompiler.MUTABLE_LIST_RESULT_STYLE_ARRAY);
73         final DoubleCalc doubleCalc = compiler.compileDouble(call.getArg(1));
74         final Calc calc = compiler.compileScalar(call.getArg(2), true);
75         return new CalcImpl(call, listCalc, doubleCalc, calc);
76     }
77
78     private static class ResolverImpl extends MultiResolver {
79         private final boolean top;
80         private final boolean percent;
81
82         public ResolverImpl(
83                 final String JavaDoc name, final String JavaDoc signature,
84                 final String JavaDoc description, final String JavaDoc[] signatures,
85                 boolean top, boolean percent) {
86             super(name, signature, description, signatures);
87             this.top = top;
88             this.percent = percent;
89         }
90
91         protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) {
92             return new TopBottomPercentSumFunDef(dummyFunDef, top, percent);
93         }
94     }
95
96     private class CalcImpl extends AbstractListCalc {
97         private final ListCalc listCalc;
98         private final DoubleCalc doubleCalc;
99         private final Calc calc;
100
101         public CalcImpl(ResolvedFunCall call, ListCalc listCalc, DoubleCalc doubleCalc, Calc calc) {
102             super(call, new Calc[]{listCalc, doubleCalc, calc});
103             this.listCalc = listCalc;
104             this.doubleCalc = doubleCalc;
105             this.calc = calc;
106         }
107
108         public List JavaDoc evaluateList(Evaluator evaluator) {
109             List JavaDoc list = listCalc.evaluateList(evaluator);
110             double target = doubleCalc.evaluateDouble(evaluator);
111             if (list.isEmpty()) {
112                 return list;
113             }
114             Map JavaDoc mapMemberToValue;
115             Object JavaDoc first = list.get(0);
116             boolean isMember = true;
117             if (first instanceof Member) {
118                 List JavaDoc<Member> memberList = (List JavaDoc<Member>) list;
119                 mapMemberToValue =
120                     evaluateMembers(evaluator, calc, memberList, false);
121                 sortMembers(evaluator, memberList, calc, top, true);
122             } else {
123                 isMember = false;
124                 List JavaDoc<Member[]> tupleList = (List JavaDoc<Member[]>) list;
125                 mapMemberToValue =
126                     evaluateTuples(evaluator, calc, tupleList);
127                 int arity = ((Member[]) first).length;
128                 sortTuples(evaluator, tupleList, calc, top, true, arity);
129             }
130             if (percent) {
131                 toPercent(list, mapMemberToValue, isMember);
132             }
133             double runningTotal = 0;
134             int memberCount = list.size();
135             int nullCount = 0;
136             for (int i = 0; i < memberCount; i++) {
137                 if (runningTotal >= target) {
138                     list = list.subList(0, i);
139                     break;
140                 }
141                 Object JavaDoc o = (isMember)
142                     ? mapMemberToValue.get(list.get(i))
143                     : mapMemberToValue.get(
144                         new ArrayHolder<Member>((Member []) list.get(i)));
145                 if (o == Util.nullValue) {
146                     nullCount++;
147                 } else if (o instanceof Number JavaDoc) {
148                     runningTotal += ((Number JavaDoc) o).doubleValue();
149                 } else if (o instanceof Exception JavaDoc) {
150                     // ignore the error
151
} else {
152                     throw Util.newInternal("got " + o + " when expecting Number");
153                 }
154             }
155
156             // MSAS exhibits the following behavior. If the value of all members is
157
// null, then the first (or last) member of the set is returned for percent
158
// operations.
159
if (memberCount > 0 && percent && nullCount == memberCount) {
160                 return top ?
161                         list.subList(0, 1) :
162                         list.subList(memberCount - 1, memberCount);
163             }
164             return list;
165         }
166
167         public boolean dependsOn(Dimension dimension) {
168             return anyDependsButFirst(getCalcs(), dimension);
169         }
170     }
171 }
172
173 // End TopBottomPercentSumFunDef.java
174
Popular Tags