KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/olap/fun/VisualTotalsFunDef.java#8 $
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) 2006-2006 Julian Hyde
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 */

10 package mondrian.olap.fun;
11
12 import mondrian.calc.*;
13 import mondrian.calc.impl.AbstractListCalc;
14 import mondrian.mdx.*;
15 import mondrian.olap.*;
16 import mondrian.olap.type.*;
17 import mondrian.rolap.RolapLevel;
18 import mondrian.rolap.RolapMember;
19 import mondrian.resource.MondrianResource;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.List JavaDoc;
23
24 /**
25  * Definition of the <code>VisualTotals</code> MDX function.
26  *
27  * @author jhyde
28  * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/VisualTotalsFunDef.java#8 $
29  * @since Jan 16, 2006
30  */

31 public class VisualTotalsFunDef extends FunDefBase {
32     static final Resolver Resolver = new ReflectiveMultiResolver(
33             "VisualTotals",
34             "VisualTotals(<Set>[, <Pattern>])",
35             "Dynamically totals child members specified in a set using a pattern for the total label in the result set.",
36             new String JavaDoc[] {"fxx", "fxxS"},
37             VisualTotalsFunDef.class);
38
39     public VisualTotalsFunDef(FunDef dummyFunDef) {
40         super(dummyFunDef);
41     }
42
43     protected Exp validateArg(
44             Validator validator, Exp[] args, int i, int category) {
45         final Exp validatedArg = super.validateArg(validator, args, i, category);
46         if (i == 0) {
47             // The function signature guarantees that we have a set of members
48
// or a set of tuples.
49
final SetType setType = (SetType) validatedArg.getType();
50             final Type elementType = setType.getElementType();
51             if (!(elementType instanceof MemberType)) {
52                 throw MondrianResource.instance().
53                         VisualTotalsAppliedToTuples.ex();
54             }
55         }
56         return validatedArg;
57     }
58
59     public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
60         final ListCalc listCalc = compiler.compileList(call.getArg(0));
61         final StringCalc stringCalc = call.getArgCount() > 1 ?
62                 compiler.compileString(call.getArg(1)) :
63                 null;
64         return new CalcImpl(call, listCalc, stringCalc);
65     }
66
67     /**
68      * Calc implementation of the <code>VisualTotals</code> function.
69      */

70     private static class CalcImpl extends AbstractListCalc {
71         private final ListCalc listCalc;
72         private final StringCalc stringCalc;
73
74         public CalcImpl(
75                 ResolvedFunCall call, ListCalc listCalc, StringCalc stringCalc) {
76             super(call, new Calc[] {listCalc, stringCalc});
77             this.listCalc = listCalc;
78             this.stringCalc = stringCalc;
79         }
80
81         public List JavaDoc evaluateList(Evaluator evaluator) {
82             final List JavaDoc<Member> list = listCalc.evaluateList(evaluator);
83             final List JavaDoc<Member> resultList = new ArrayList JavaDoc<Member>(list);
84             final int memberCount = list.size();
85             for (int i = memberCount - 1; i >= 0; --i) {
86                 Member member = list.get(i);
87                 if (i + 1 < memberCount) {
88                     Member nextMember = resultList.get(i + 1);
89                     if (nextMember != member &&
90                             nextMember.isChildOrEqualTo(member)) {
91                         resultList.set(
92                             i,
93                             createMember(member, i, resultList, evaluator));
94                     }
95                 }
96             }
97             return resultList;
98         }
99
100         private VisualTotalMember createMember(
101                 Member member,
102                 int i,
103                 final List JavaDoc<Member> list,
104                 Evaluator evaluator)
105         {
106             final String JavaDoc name;
107             if (stringCalc != null) {
108                 final String JavaDoc namePattern = stringCalc.evaluateString(evaluator);
109                 name = substitute(namePattern, member.getName());
110             } else {
111                 name = member.getName();
112             }
113             final List JavaDoc<Member> childMemberList =
114                 followingDescendants(member, i + 1, list);
115             final Exp exp = makeExpr(childMemberList);
116             final Validator validator = evaluator.getQuery().createValidator();
117             final Exp validatedExp = exp.accept(validator);
118             return new VisualTotalMember(member, name, validatedExp);
119         }
120
121         private List JavaDoc<Member> followingDescendants(
122             Member member, int i, final List JavaDoc<Member> list)
123         {
124             List JavaDoc<Member> childMemberList = new ArrayList JavaDoc<Member>();
125             while (i < list.size()) {
126                 Member descendant = list.get(i);
127                 if (descendant == member) {
128                     // strict descendants only
129
break;
130                 }
131                 if (!descendant.isChildOrEqualTo(member)) {
132                     break;
133                 }
134                 if (descendant instanceof VisualTotalMember) {
135                     // Add the visual total member, but skip over its children.
136
VisualTotalMember visualTotalMember =
137                             (VisualTotalMember) descendant;
138                     childMemberList.add(visualTotalMember);
139                     i = lastChildIndex(visualTotalMember.member, i, list);
140                     continue;
141                 }
142                 childMemberList.add(descendant);
143                 ++i;
144             }
145             return childMemberList;
146         }
147
148         private int lastChildIndex(Member member, int start, List JavaDoc list) {
149             int i = start;
150             while (true) {
151                 ++i;
152                 if (i >= list.size()) {
153                     break;
154                 }
155                 Member descendant = (Member) list.get(i);
156                 if (descendant == member) {
157                     // strict descendants only
158
break;
159                 }
160                 if (!descendant.isChildOrEqualTo(member)) {
161                     break;
162                 }
163             }
164             return i;
165         }
166
167         private Exp makeExpr(final List JavaDoc childMemberList) {
168             Exp[] memberExprs = new Exp[childMemberList.size()];
169             for (int i = 0; i < childMemberList.size(); i++) {
170                 final Member childMember = (Member) childMemberList.get(i);
171                 memberExprs[i] = new MemberExpr(childMember);
172             }
173             return new UnresolvedFunCall(
174                     "Aggregate",
175                     new Exp[] {
176                         new UnresolvedFunCall(
177                                 "{}",
178                                 Syntax.Braces,
179                                 memberExprs)
180                     });
181         }
182     }
183
184     /**
185      * Calculated member for <code>VisualTotals</code> function.
186      *
187      * It corresponds to a real member, and most of its properties are similar.
188      * The main differences are:<ul>
189      * <li>its name is derived from the VisualTotals pattern, e.g.
190      * "*Subtotal - Dairy" as opposed to "Dairy"
191      * <li>its value is a calculation computed by aggregating all of the
192      * members which occur following it in the list</ul></p>
193      */

194     private static class VisualTotalMember extends RolapMember {
195         private final Member member;
196         private final Exp exp;
197
198         VisualTotalMember(
199                 Member member,
200                 String JavaDoc name,
201                 final Exp exp) {
202             super(
203                 (RolapMember) member.getParentMember(),
204                 (RolapLevel) member.getLevel(),
205                 null, name, MemberType.FORMULA);
206             this.member = member;
207             this.exp = exp;
208         }
209
210         public boolean isCalculated() {
211             return true;
212         }
213
214         public int getSolveOrder() {
215             // high solve order, so it is expanded after other calculations
216
return 99;
217         }
218
219         public Exp getExpression() {
220             return exp;
221         }
222
223         public int getOrdinal() {
224             throw new UnsupportedOperationException JavaDoc();
225         }
226
227         public Member getDataMember() {
228             return member;
229         }
230
231         public OlapElement lookupChild(SchemaReader schemaReader, String JavaDoc s) {
232             throw new UnsupportedOperationException JavaDoc();
233         }
234
235         public OlapElement lookupChild(
236             SchemaReader schemaReader, String JavaDoc s, MatchType matchType) {
237             throw new UnsupportedOperationException JavaDoc();
238         }
239
240         public String JavaDoc getQualifiedName() {
241             throw new UnsupportedOperationException JavaDoc();
242         }
243     }
244
245     /**
246      * Substitutes a name into a pattern.<p/>
247      *
248      * Asterisks are replaced with the name,
249      * double-asterisks are replaced with a single asterisk.
250      * For example,
251      * <blockquote><code>substitute("** Subtotal - *", "Dairy")</code></blockquote>
252      * returns
253      * <blockquote><code>"* Subtotal - Dairy"</code></blockquote>
254      *
255      * @param namePattern Pattern
256      * @param name Name to substitute into pattern
257      * @return Substituted pattern
258      */

259     static String JavaDoc substitute(String JavaDoc namePattern, String JavaDoc name) {
260         final StringBuilder JavaDoc buf = new StringBuilder JavaDoc(256);
261         final int namePatternLen = namePattern.length();
262         int startIndex = 0;
263
264         while (true) {
265             int endIndex = namePattern.indexOf('*', startIndex);
266
267             if (endIndex == -1) { // No '*' left
268
// append the rest of namePattern from startIndex onwards
269
buf.append(namePattern.substring(startIndex));
270                 break;
271             }
272
273             // endIndex now points to the '*'; check for '**'
274
++endIndex;
275             if (endIndex < namePatternLen && namePattern.charAt(endIndex) == '*') { // Found '**', replace with '*'
276
buf.append(namePattern.substring(startIndex, endIndex)); // Include first '*'
277
++endIndex; // Skip over 2nd '*'
278
} else { // Found single '*' - substitute (omitting the '*')
279
buf.append(namePattern.substring(startIndex, endIndex - 1)); // Exclude '*'
280
buf.append(name);
281             }
282
283             startIndex = endIndex;
284         }
285
286         return buf.toString();
287     }
288
289 }
290
291 // End VisualTotalsFunDef.java
292
Popular Tags