KickJava   Java API By Example, From Geeks To Geeks.

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


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

13 package mondrian.olap.fun;
14
15 import mondrian.olap.*;
16 import mondrian.olap.type.MemberType;
17 import mondrian.olap.type.Type;
18 import mondrian.resource.MondrianResource;
19 import mondrian.calc.*;
20 import mondrian.calc.impl.AbstractMemberCalc;
21 import mondrian.calc.impl.DimensionCurrentMemberCalc;
22 import mondrian.mdx.ResolvedFunCall;
23
24 /**
25  * Definition of the <code>OpeningPeriod</code> and <code>ClosingPeriod</code>
26  * builtin functions.
27  *
28  * @author jhyde
29  * @since 2005/8/14
30  * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/OpeningClosingPeriodFunDef.java#8 $
31  */

32 class OpeningClosingPeriodFunDef extends FunDefBase {
33     private final boolean opening;
34
35     static final Resolver OpeningPeriodResolver = new MultiResolver(
36             "OpeningPeriod",
37             "OpeningPeriod([<Level>[, <Member>]])",
38             "Returns the first descendant of a member at a level.",
39             new String JavaDoc[] {"fm", "fml", "fmlm"}) {
40         protected FunDef createFunDef(
41                 Exp[] args, FunDef dummyFunDef) {
42             return new OpeningClosingPeriodFunDef(
43                     dummyFunDef, true);
44         }
45     };
46
47     static final Resolver ClosingPeriodResolver = new MultiResolver(
48             "ClosingPeriod",
49             "ClosingPeriod([<Level>[, <Member>]])",
50             "Returns the last descendant of a member at a level.",
51             new String JavaDoc[] {"fm", "fml", "fmlm", "fmm"}) {
52         protected FunDef createFunDef(
53                 Exp[] args, FunDef dummyFunDef) {
54             return new OpeningClosingPeriodFunDef(
55                     dummyFunDef, false);
56         }
57     };
58
59     public OpeningClosingPeriodFunDef(
60             FunDef dummyFunDef,
61             boolean opening) {
62         super(dummyFunDef);
63         this.opening = opening;
64     }
65
66     public Type getResultType(Validator validator, Exp[] args) {
67         if (args.length == 0) {
68             // With no args, the default implementation cannot
69
// guess the hierarchy, so we supply the Time
70
// dimension.
71
Hierarchy hierarchy = validator.getQuery()
72                     .getCube().getTimeDimension()
73                     .getHierarchy();
74             return MemberType.forHierarchy(hierarchy);
75         }
76         return super.getResultType(validator, args);
77     }
78
79     public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
80         final Exp[] args = call.getArgs();
81         final LevelCalc levelCalc;
82         final MemberCalc memberCalc;
83         switch (args.length) {
84         case 0:
85             memberCalc = new DimensionCurrentMemberCalc(
86                     compiler.getEvaluator().getCube().getTimeDimension());
87             levelCalc = null;
88             break;
89         case 1:
90             levelCalc = compiler.compileLevel(call.getArg(0));
91             memberCalc = new DimensionCurrentMemberCalc(
92                     compiler.getEvaluator().getCube().getTimeDimension());
93             break;
94         default:
95             levelCalc = compiler.compileLevel(call.getArg(0));
96             memberCalc = compiler.compileMember(call.getArg(1));
97             break;
98         }
99
100         // Make sure the member and the level come from the same dimension.
101
//
102
final Dimension memberDimension = memberCalc.getType().getDimension();
103         final Dimension levelDimension;
104         if (levelCalc == null) {
105             levelDimension = memberDimension;
106         } else {
107             levelDimension = levelCalc.getType().getDimension();
108             if (!memberDimension.equals(levelDimension)) {
109                 throw MondrianResource.instance().
110                         FunctionMbrAndLevelHierarchyMismatch.ex(
111                                 opening ? "OpeningPeriod" : "ClosingPeriod",
112                                 levelDimension.getUniqueName(),
113                                 memberDimension.getUniqueName());
114             }
115         }
116         return new AbstractMemberCalc(call, new Calc[] {levelCalc, memberCalc}) {
117             public Member evaluateMember(Evaluator evaluator) {
118                 Member member = memberCalc.evaluateMember(evaluator);
119
120                 // If the level argument is present, use it. Otherwise use the
121
// level immediately after that of the member argument.
122
Level level;
123                 if (levelCalc == null) {
124                     int targetDepth = member.getLevel().getDepth() + 1;
125                     Level[] levels = member.getHierarchy().getLevels();
126
127                     if (levels.length <= targetDepth) {
128                         return member.getHierarchy().getNullMember();
129                     }
130                     level = levels[targetDepth];
131                 } else {
132                     level = levelCalc.evaluateLevel(evaluator);
133                 }
134
135                 // Shortcut if the level is above the member.
136
if (level.getDepth() < member.getLevel().getDepth()) {
137                     return member.getHierarchy().getNullMember();
138                 }
139
140                 // Shortcut if the level is the same as the member
141
if (level == member.getLevel()) {
142                     return member;
143                 }
144
145                 return getDescendant(evaluator.getSchemaReader(), member,
146                         level, opening);
147             }
148         };
149     }
150
151     /**
152      * Returns the first or last descendant of the member at the target level.
153      * This method is the implementation of both OpeningPeriod and ClosingPeriod.
154      * @param schemaReader The schema reader to use to evaluate the function.
155      * @param member The member from which the descendant is to be found.
156      * @param targetLevel The level to stop at.
157      * @param returnFirstDescendant Flag indicating whether to return the first
158      * or last descendant of the member.
159      * @return A member.
160      * @pre member.getLevel().getDepth() < level.getDepth();
161      */

162     static Member getDescendant(
163             SchemaReader schemaReader,
164             Member member,
165             Level targetLevel,
166             boolean returnFirstDescendant) {
167         Member[] children;
168
169         final int targetLevelDepth = targetLevel.getDepth();
170         assertPrecondition(member.getLevel().getDepth() < targetLevelDepth,
171                 "member.getLevel().getDepth() < targetLevel.getDepth()");
172
173         for (;;) {
174             children = schemaReader.getMemberChildren(member);
175
176             if (children.length == 0) {
177                 return targetLevel.getHierarchy().getNullMember();
178             }
179
180             member = children[returnFirstDescendant ? 0 : (children.length - 1)];
181
182             if (member.getLevel().getDepth() == targetLevelDepth) {
183                 if (member.isHidden()) {
184                     return member.getHierarchy().getNullMember();
185                 } else {
186                     return member;
187                 }
188             }
189         }
190     }
191
192 }
193
194 // End OpeningClosingPeriodFunDef.java
195
Popular Tags