001 /*
002 // $Id: //open/mondrian-release/3.0/src/main/mondrian/calc/ExpCompiler.java#2 $
003 // This software is subject to the terms of the Common Public License
004 // Agreement, available at the following URL:
005 // http://www.opensource.org/licenses/cpl.html.
006 // Copyright (C) 2006-2007 Julian Hyde
007 // All Rights Reserved.
008 // You must accept the terms of that agreement to use this software.
009 */
010 package mondrian.calc;
011
012 import org.eigenbase.util.property.StringProperty;
013 import mondrian.olap.*;
014 import mondrian.olap.type.Type;
015 import mondrian.util.ObjectFactory;
016 import mondrian.util.CreationException;
017 import mondrian.calc.impl.BetterExpCompiler;
018
019 import java.util.List;
020
021 /**
022 * Mediates the compilation of an expression ({@link mondrian.olap.Exp})
023 * into a compiled expression ({@link Calc}).
024 *
025 * @author jhyde
026 * @version $Id: //open/mondrian-release/3.0/src/main/mondrian/calc/ExpCompiler.java#2 $
027 * @since Sep 28, 2005
028 */
029 public interface ExpCompiler {
030
031 /**
032 * Returns the evaluator to be used for evaluating expressions during the
033 * compilation process.
034 */
035 Evaluator getEvaluator();
036
037 /**
038 * Returns the validator which was used to validate this expression.
039 *
040 * @return validator
041 */
042 Validator getValidator();
043
044 /**
045 * Compiles an expression.
046 *
047 * @param exp Expression
048 * @return Compiled expression
049 */
050 Calc compile(Exp exp);
051
052 /**
053 * Compiles an expression to a given result type.
054 *
055 * <p>If <code>resultType</code> is not null, casts the expression to that
056 * type. Throws an exception if that conversion is not allowed by the
057 * type system.
058 *
059 * <p>The <code>preferredResultStyles</code> parameter specifies a list
060 * of desired result styles. It must not be null, but may be empty.
061 *
062 * @param exp Expression
063 *
064 * @param resultType Desired result type, or null to use expression's
065 * current type
066 *
067 * @param preferredResultStyles List of result types, in descending order
068 * of preference. Never null.
069 *
070 * @return Compiled expression, or null if none can satisfy
071 */
072 Calc compileAs(
073 Exp exp,
074 Type resultType,
075 List<ResultStyle> preferredResultStyles);
076
077 /**
078 * Compiles an expression which yields a {@link Member} result.
079 */
080 MemberCalc compileMember(Exp exp);
081
082 /**
083 * Compiles an expression which yields a {@link Level} result.
084 */
085 LevelCalc compileLevel(Exp exp);
086
087 /**
088 * Compiles an expression which yields a {@link Dimension} result.
089 */
090 DimensionCalc compileDimension(Exp exp);
091
092 /**
093 * Compiles an expression which yields a {@link Hierarchy} result.
094 */
095 HierarchyCalc compileHierarchy(Exp exp);
096
097 /**
098 * Compiles an expression which yields an <code>int</code> result.
099 * The expression is implicitly converted into a scalar.
100 */
101 IntegerCalc compileInteger(Exp exp);
102
103 /**
104 * Compiles an expression which yields a {@link String} result.
105 * The expression is implicitly converted into a scalar.
106 */
107 StringCalc compileString(Exp exp);
108
109 /**
110 * Compiles an expression which yields a {@link java.util.Date} result.
111 * The expression is implicitly converted into a scalar.
112 */
113 DateTimeCalc compileDateTime(Exp exp);
114
115 /**
116 * Compiles an expression which yields an immutable {@link java.util.List}
117 * result.
118 *
119 * <p>Always equivalent to <code>{@link #compileList}(exp, false)</code>.
120 */
121 ListCalc compileList(Exp exp);
122
123 /**
124 * Compiles an expression which yields {@link java.util.List} result.
125 *
126 * <p>Such an expression is generally a list of {@link Member} objects or a
127 * list of tuples (each represented by a {@link Member} array).
128 *
129 * <p>See {@link #compileList(mondrian.olap.Exp)}.
130 *
131 * @param exp Expression
132 * @param mutable Whether resulting list is mutable
133 */
134 ListCalc compileList(Exp exp, boolean mutable);
135
136 /**
137 * Compiles an expression which yields an immutable {@link Iterable} result.
138 *
139 * @param exp Expression
140 * @return Calculator which yields an Iterable
141 */
142 IterCalc compileIter(Exp exp);
143
144 /**
145 * Compiles an expression which yields a <code>boolean</code> result.
146 *
147 * @param exp Expression
148 * @return Calculator which yields a boolean
149 */
150 BooleanCalc compileBoolean(Exp exp);
151
152 /**
153 * Compiles an expression which yields a <code>double</code> result.
154 *
155 * @param exp Expression
156 * @return Calculator which yields a double
157 */
158 DoubleCalc compileDouble(Exp exp);
159
160 /**
161 * Compiles an expression which yields a tuple result.
162 *
163 * @param exp Expression
164 * @return Calculator which yields a tuple
165 */
166 TupleCalc compileTuple(Exp exp);
167
168 /**
169 * Compiles an expression to yield a scalar result.
170 *
171 * <p>If the expression yields a member or tuple, the calculator will
172 * automatically apply that member or tuple to the current dimensional
173 * context and return the value of the current measure.
174 *
175 * @param exp Expression
176 * @param specific Whether to try to use the specific compile method for
177 * scalar types. For example, if <code>specific</code> is true and
178 * <code>exp</code> is a string expression, calls
179 * {@link #compileString(mondrian.olap.Exp)}
180 * @return Calculation which returns the scalar value of the expression
181 */
182 Calc compileScalar(Exp exp, boolean specific);
183
184 /**
185 * Implements a parameter, returning a unique slot which will hold the
186 * parameter's value.
187 *
188 * @param parameter Parameter
189 * @return Slot
190 */
191 ParameterSlot registerParameter(Parameter parameter);
192
193 /**
194 * Returns a list of the {@link ResultStyle}s
195 * acceptable to the caller.
196 */
197 List<ResultStyle> getAcceptableResultStyles();
198
199 /**
200 * The <code>ExpCompiler.Factory</code> is used to access
201 * <code>ExpCompiler</code> implementations. Each call returns
202 * a new instance. This factory supports overriding the default
203 * instance by use of a <code>ThreadLocal</code> and by defining a
204 * <code>System</code> property with the <code>ExpCompiler</code>
205 * class name.
206 */
207 public static final class Factory extends ObjectFactory<ExpCompiler> {
208 private static final Factory factory;
209 private static final Class[] CLASS_ARRAY;
210 static {
211 factory = new Factory();
212 CLASS_ARRAY = new Class[] {
213 Evaluator.class,
214 Validator.class,
215 ResultStyle[].class
216 };
217 }
218
219 /**
220 * Create a <code>ExpCompiler</code> instance, each call returns a
221 * new compiler.
222 *
223 * @param evaluator the <code>Evaluator</code> to use with the compiler
224 * @param validator the <code>Validator</code> to use with the compiler
225 * @return the new <code>ExpCompiler</code> compiler
226 * @throws CreationException if the compiler can not be created
227 */
228 public static ExpCompiler getExpCompiler(
229 final Evaluator evaluator,
230 final Validator validator)
231 throws CreationException {
232 return getExpCompiler(evaluator, validator, ResultStyle.ANY_LIST);
233 }
234
235 /**
236 *
237 *
238 * @param evaluator the <code>Evaluator</code> to use with the compiler
239 * @param validator the <code>Validator</code> to use with the compiler
240 * @param resultStyles the initial <code>ResultStyle</code> array
241 * for the compiler
242 * @return the new <code>ExpCompiler</code> compiler
243 * @throws CreationException if the compiler can not be created
244 */
245 public static ExpCompiler getExpCompiler(
246 final Evaluator evaluator,
247 final Validator validator,
248 final List<ResultStyle> resultStyles)
249 throws CreationException
250 {
251 return factory.getObject(
252 CLASS_ARRAY,
253 new Object[] {
254 evaluator,
255 validator,
256 resultStyles
257 });
258 }
259
260 /**
261 * <code>ThreadLocal</code> used to hold the class name of an
262 * <code>ExpCompiler</code> implementation.
263 * Generally, this should only be used for testing.
264 */
265 private static final ThreadLocal<String> ClassName =
266 new ThreadLocal<String>();
267
268 /**
269 * Get the class name of a <code>ExpCompiler</code> implementation
270 * or null.
271 *
272 * @return the class name or null.
273 */
274 public static String getThreadLocalClassName() {
275 return ClassName.get();
276 }
277 /**
278 * Sets the class name of a <code>ExpCompiler</code> implementation.
279 * This should be called (obviously) before calling the
280 * <code>ExpCompiler.Factory</code> <code>getExpCompiler</code>
281 * method to get the <code>ExpCompiler</code> implementation.
282 * Generally, this is only used for testing.
283 *
284 * @param className Class name
285 */
286 public static void setThreadLocalClassName(String className) {
287 ClassName.set(className);
288 }
289 /**
290 * Clears the class name (regardless of whether a class name was set).
291 * When a class name is set using <code>setThreadLocalClassName</code>,
292 * the setting whould be done in a try-block and a call to this
293 * clear method should be in the finally-clause of that try-block.
294 */
295 public static void clearThreadLocalClassName() {
296 ClassName.set(null);
297 }
298
299 /**
300 * The constructor for the <code>ExpCompiler.Factory</code>.
301 * This passes the <code>ExpCompiler</code> class to the
302 * <code>ObjectFactory</code> base class.
303 */
304 private Factory() {
305 super(ExpCompiler.class);
306 }
307 /**
308 * Get the class name set in the <code>ThreadLocal</code> or null.
309 *
310 * @return class name or null.
311 */
312 protected String getClassName() {
313 return getThreadLocalClassName();
314 }
315
316 /**
317 * Return the <code>ExpCompiler.Factory</code property name.
318 *
319 * @return <code>ExpCompiler.Factory</code> property name
320 */
321 protected StringProperty getStringProperty() {
322 return MondrianProperties.instance().ExpCompilerClass;
323 }
324 /**
325 * The <code>ExpCompiler.Factory</code>'s implementation of the
326 * <code>ObjectFactory</code>'s abstract method which returns
327 * the default <code>ExpCompiler</code> instance.
328 *
329 * @param parameterTypes array of classes: Evaluator, Validator and
330 * ResultStyle
331 * @param parameterValues the Evaluator, Validator and ResultStyle
332 * values
333 * @return <code>ExpCompiler</code> instance
334 * @throws CreationException if the <code>ExpCompiler</code> can not be
335 * created.
336 */
337 protected ExpCompiler getDefault(
338 final Class[] parameterTypes,
339 final Object[] parameterValues)
340 throws CreationException
341 {
342 // Strong typed above so don't need to check here
343 Evaluator evaluator = (Evaluator) parameterValues[0];
344 Validator validator = (Validator) parameterValues[1];
345 List<ResultStyle> resultStyles =
346 (List<ResultStyle>) parameterValues[2];
347
348 // Here there is bleed-through from the "calc.impl" implementation
349 // directory into the "calc" interface definition directory.
350 // This can be avoided if we were to use reflection to
351 // create this the default ExpCompiler implementation.
352 return new BetterExpCompiler(
353 evaluator, validator, resultStyles);
354 }
355
356 /**
357 * Get the underlying Factory object.
358 * <p>
359 * This is for testing only.
360 *
361 * @return the <code>ExpCompiler.Factory</code> object
362 */
363 public static Factory getFactory() {
364 return factory;
365 }
366
367 /**
368 * Get the current override contect.
369 * <p>
370 * This is for testing only.
371 *
372 * @return the override context object.
373 */
374 public Object removeContext() {
375 return new Context();
376 }
377
378 /**
379 * Restore the current overrides.
380 * <p>
381 * This is for testing only.
382 *
383 * @param context the current override object.
384 */
385 public void restoreContext(final Object context) {
386 if (context instanceof Context) {
387 ((Context) context).restore();
388 }
389 }
390
391 /**
392 * The <code>ExpCompiler</code> only has two override mechanisms: the
393 * <code>ThreadLocal</code> and <code>System</code>
394 * <code>Properties</code>. This class captures and clears the current
395 * values for both in the constructor and then replaces them
396 * in the <code>restore</code> method.
397 * <p>
398 * This is for testing only.
399 */
400 public static class Context implements ObjectFactory.Context {
401 private final String threadLocalClassName;
402 private final String systemPropertyClassName;
403
404 /**
405 * Creates a Context.
406 */
407 Context() {
408 this.threadLocalClassName =
409 ExpCompiler.Factory.getThreadLocalClassName();
410 if (this.threadLocalClassName != null) {
411 ExpCompiler.Factory.clearThreadLocalClassName();
412 }
413
414 this.systemPropertyClassName =
415 System.getProperty(ExpCompiler.class.getName());
416 if (this.systemPropertyClassName != null) {
417 System.getProperties().remove(ExpCompiler.class.getName());
418 }
419 }
420
421 /**
422 * Restores the previous context.
423 */
424 private void restore() {
425 if (this.threadLocalClassName != null) {
426 ExpCompiler.Factory.setThreadLocalClassName(
427 this.threadLocalClassName);
428 }
429 if (this.systemPropertyClassName != null) {
430 System.setProperty(ExpCompiler.class.getName(),
431 this.systemPropertyClassName);
432 }
433 }
434 }
435 }
436 }
437
438 // End ExpCompiler.java