KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/olap/fun/FunDefBase.java#27 $
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.*;
17 import mondrian.olap.type.LevelType;
18 import mondrian.olap.type.DimensionType;
19 import mondrian.calc.Calc;
20 import mondrian.calc.ExpCompiler;
21 import mondrian.mdx.ResolvedFunCall;
22
23 import java.io.PrintWriter JavaDoc;
24
25 /**
26  * <code>FunDefBase</code> is the default implementation of {@link FunDef}.
27  *
28  * <h3>Signatures</h3>
29  *
30  * <p>A function is defined by the following:</p>
31  *
32  * <table border="1">
33  * <tr><th>Parameter</th><th>Meaning</th><th>Example</th></tr>
34  * <tr>
35  * <td>name</td><td>Name of the function</td><td>"Members"</td>
36  * </tr>
37  * <tr>
38  * <td>signature</td>
39  * <td>Signature of the function</td>
40  * <td>"&lt;Dimension&gt;.Members"</td>
41  * </tr>
42  * <tr>
43  * <td>description</td>
44  * <td>Description of the function</td>
45  * <td>"Returns the set of all members in a dimension."</td>
46  * </tr>
47  * <tr>
48  * <td>flags</td>
49  * <td>Encoding of the syntactic type, return type, and parameter
50  * types of this operator. The encoding is described below.</td>
51  * <td>"pxd"</tr>
52  * </table>
53  *
54  * The <code>flags</code> field is an string which encodes
55  * the syntactic type, return type, and parameter types of this operator.
56  * <ul>
57  * <li>The first character determines the syntactic type, as described by
58  * {@link FunUtil#decodeSyntacticType(String)}.
59  * <li>The second character determines the return type, as described by
60  * {@link FunUtil#decodeReturnCategory(String)}.
61  * <li>The third and subsequence characters determine the types of the
62  * arguments arguments, as described by
63  * {@link FunUtil#decodeParameterCategories(String)}.
64  * </ul><p/>
65  *
66  * For example, <code>"pxd"</code> means "an operator with
67  * {@link Syntax#Property property} syntax (p) which returns a set
68  * (x) and takes a dimension (d) as its argument".<p/>
69  *
70  * The arguments are always read from left to right, regardless of the
71  * syntactic type of the operator. For example, the
72  * <code>"&lt;Set&gt;.Item(&lt;Index&gt;)"</code> operator
73  * (signature <code>"mmxn"</code>) has the
74  * syntax of a method-call, and takes two parameters:
75  * a set (x) and a numeric (n).<p/>
76  *
77  * @author jhyde
78  * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/FunDefBase.java#27 $
79  * @since 26 February, 2002
80  */

81 public abstract class FunDefBase extends FunUtil implements FunDef {
82     protected final int flags;
83     private final String JavaDoc name;
84     private final String JavaDoc description;
85     protected final int returnCategory;
86     protected final int[] parameterCategories;
87
88     /**
89      * Creates an operator.
90      *
91      * @param name Name of the function, for example "Members".
92      * @param signature Signature of the function, for example
93      * "&lt;Dimension&gt;.Members".
94      * @param description Description of the function, for example
95      * "Returns the set of all members in a dimension."
96      * @param syntax Syntactic type of the operator (for example, function,
97      * method, infix operator)
98      * @param returnCategory The {@link Category} of the value returned by this
99      * operator.
100      * @param parameterCategories An array of {@link Category} codes, one for
101      * each parameter.
102      */

103     FunDefBase(
104             String JavaDoc name,
105             String JavaDoc signature,
106             String JavaDoc description,
107             Syntax syntax,
108             int returnCategory,
109             int[] parameterCategories) {
110         this.name = name;
111         Util.discard(signature);
112         this.description = description;
113         this.flags = syntax.ordinal();
114         this.returnCategory = returnCategory;
115         this.parameterCategories = parameterCategories;
116     }
117
118     /**
119      * Creates an operator.
120      *
121      * @param name Name of the function, for example "Members".
122      * @param signature Signature of the function, for example
123      * "&lt;Dimension&gt;.Members".
124      * @param description Description of the function, for example
125      * "Returns the set of all members in a dimension."
126      * @param flags Encoding of the syntactic type, return type, and parameter
127      * types of this operator. The "Members" operator has a syntactic
128      * type "pxd" which means "an operator with
129      * {@link Syntax#Property property} syntax (p) which returns a set
130      * (x) and takes a dimension (d) as its argument".
131      * See {@link FunUtil#decodeSyntacticType(String)},
132      * {@link FunUtil#decodeReturnCategory(String)},
133      * {@link FunUtil#decodeParameterCategories(String)}.
134      */

135     protected FunDefBase(String JavaDoc name,
136             String JavaDoc signature,
137             String JavaDoc description,
138             String JavaDoc flags) {
139         this(name,
140                 signature,
141                 description,
142                 decodeSyntacticType(flags),
143                 decodeReturnCategory(flags),
144                 decodeParameterCategories(flags));
145     }
146
147     /**
148      * Convenience constructor when we are created by a {@link Resolver}.
149      */

150     FunDefBase(Resolver resolver, int returnType, int[] parameterTypes) {
151         this(resolver.getName(),
152                 null,
153                 null,
154                 resolver.getSyntax(),
155                 returnType,
156                 parameterTypes);
157     }
158
159     /**
160      * Copy constructor.
161      */

162     FunDefBase(FunDef funDef) {
163         this(funDef.getName(), funDef.getSignature(),
164                 funDef.getDescription(), funDef.getSyntax(),
165                 funDef.getReturnCategory(), funDef.getParameterCategories());
166     }
167
168     public String JavaDoc getName() {
169         return name;
170     }
171
172     public String JavaDoc getDescription() {
173         return description;
174     }
175
176     public Syntax getSyntax() {
177         return Syntax.class.getEnumConstants()[flags];
178     }
179
180     public int getReturnCategory() {
181         return returnCategory;
182     }
183
184     public int[] getParameterCategories() {
185         return parameterCategories;
186     }
187
188     public Exp createCall(Validator validator, Exp[] args) {
189         int[] categories = getParameterCategories();
190         Util.assertTrue(categories.length == args.length);
191         for (int i = 0; i < args.length; i++) {
192             args[i] = validateArg(validator, args, i, categories[i]);
193         }
194         final Type type = getResultType(validator, args);
195         if (type == null) {
196             throw Util.newInternal("could not derive type");
197         }
198         return new ResolvedFunCall(this, args, type);
199     }
200
201     /**
202      * Validates an argument to a call to this function.
203      *
204      * <p>The default implementation of this method adds an implicit
205      * conversion to the correct type. Derived classes may override.
206      *
207      * @param validator Validator
208      * @param args Arguments to this function
209      * @param i Ordinal of argument
210      * @param category Expected {@link Category category} of argument
211      * @return Validated argument
212      */

213     protected Exp validateArg(
214             Validator validator,
215             Exp[] args,
216             int i,
217             int category) {
218         return args[i];
219     }
220
221     /**
222      * Returns a first approximation as to the type of a function call,
223      * assuming that the return type is in some way related to the type of
224      * the first argument.<p/>
225      *
226      * So, this function serves as a good default implementation for
227      * {@link #getResultType}. Methods whose arguments don't follow the
228      * requirements of this implementation should use a different
229      * implementation.<p/>
230      *
231      * If the function definition says it returns a literal type (numeric,
232      * string, symbol) then it's a fair guess that the function call
233      * returns the same kind of value.<p/>
234      *
235      * If the function definition says it returns an object type (cube,
236      * dimension, hierarchy, level, member) then we check the first
237      * argument of the function. Suppose that the function definition says
238      * that it returns a hierarchy, and the first argument of the function
239      * happens to be a member. Then it's reasonable to assume that this
240      * function returns a member.
241      */

242     static Type guessResultType(Exp[] args, int category, String JavaDoc name) {
243         switch (category) {
244         case Category.Logical:
245             return new BooleanType();
246         case Category.Numeric:
247             return new NumericType();
248         case Category.Numeric | Category.Integer:
249             return new DecimalType(Integer.MAX_VALUE, 0);
250         case Category.String:
251             return new StringType();
252         case Category.Symbol:
253             return new SymbolType();
254         case Category.Value:
255             return new ScalarType();
256         case Category.Cube:
257             if (args.length > 0 && args[0] instanceof Cube) {
258                 return new CubeType((Cube) args[0]);
259             }
260             break;
261         case Category.Dimension:
262             if (args.length > 0) {
263                 final Type type = args[0].getType();
264                 return DimensionType.forType(type);
265             }
266             break;
267         case Category.Hierarchy:
268             if (args.length > 0) {
269                 final Type type = args[0].getType();
270                 return HierarchyType.forType(type);
271             }
272             break;
273         case Category.Level:
274             if (args.length > 0) {
275                 final Type type = args[0].getType();
276                 return LevelType.forType(type);
277             }
278             break;
279         case Category.Member:
280             if (args.length > 0) {
281                 final Type type = args[0].getType();
282                 final MemberType memberType = TypeUtil.toMemberType(type);
283                 if (memberType != null) {
284                     return memberType;
285                 }
286             }
287             // Take a wild guess.
288
return MemberType.Unknown;
289         case Category.Tuple:
290             if (args.length > 0) {
291                 final Type type = args[0].getType();
292                 final Type memberType = TypeUtil.toMemberOrTupleType(type);
293                 if (memberType != null) {
294                     return memberType;
295                 }
296             }
297             break;
298         case Category.Set:
299             if (args.length > 0) {
300                 final Type type = args[0].getType();
301                 final Type memberType = TypeUtil.toMemberOrTupleType(type);
302                 if (memberType != null) {
303                     return new SetType(memberType);
304                 }
305             }
306             break;
307         default:
308             throw Category.instance.badValue(category);
309         }
310         throw Util.newInternal("Cannot deduce type of call to function '" +
311                 name + "'");
312     }
313
314     /**
315      * Returns the type of a call to this function with a given set of
316      * arguments.
317      */

318     public Type getResultType(Validator validator, Exp[] args) {
319         return guessResultType(args, getReturnCategory(), this.name);
320     }
321
322     public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
323         throw Util.newInternal("function '" + getSignature() +
324                 "' has not been implemented");
325     }
326
327     public String JavaDoc getSignature() {
328         return getSyntax().getSignature(getName(), getReturnCategory(),
329                 getParameterCategories());
330     }
331
332     public void unparse(Exp[] args, PrintWriter JavaDoc pw) {
333         getSyntax().unparse(getName(), args, pw);
334     }
335 }
336
337 // End FunDefBase.java
338
Popular Tags