001 /*
002 // $Id: //open/mondrian-release/3.2/src/main/mondrian/calc/ExpCompiler.java#1 $
003 // This software is subject to the terms of the Eclipse Public License v1.0
004 // Agreement, available at the following URL:
005 // http://www.eclipse.org/legal/epl-v10.html.
006 // Copyright (C) 2006-2009 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.2/src/main/mondrian/calc/ExpCompiler.java#1 $
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 {
233 return getExpCompiler(evaluator, validator, ResultStyle.ANY_LIST);
234 }
235
236 /**
237 *
238 *
239 * @param evaluator the <code>Evaluator</code> to use with the compiler
240 * @param validator the <code>Validator</code> to use with the compiler
241 * @param resultStyles the initial <code>ResultStyle</code> array
242 * for the compiler
243 * @return the new <code>ExpCompiler</code> compiler
244 * @throws CreationException if the compiler can not be created
245 */
246 public static ExpCompiler getExpCompiler(
247 final Evaluator evaluator,
248 final Validator validator,
249 final List<ResultStyle> resultStyles)
250 throws CreationException
251 {
252 return factory.getObject(
253 CLASS_ARRAY,
254 new Object[] {
255 evaluator,
256 validator,
257 resultStyles
258 });
259 }
260
261 /**
262 * <code>ThreadLocal</code> used to hold the class name of an
263 * <code>ExpCompiler</code> implementation.
264 * Generally, this should only be used for testing.
265 */
266 private static final ThreadLocal<String> ClassName =
267 new ThreadLocal<String>();
268
269 /**
270 * Get the class name of a <code>ExpCompiler</code> implementation
271 * or null.
272 *
273 * @return the class name or null.
274 */
275 public static String getThreadLocalClassName() {
276 return ClassName.get();
277 }
278 /**
279 * Sets the class name of a <code>ExpCompiler</code> implementation.
280 * This should be called (obviously) before calling the
281 * <code>ExpCompiler.Factory</code> <code>getExpCompiler</code>
282 * method to get the <code>ExpCompiler</code> implementation.
283 * Generally, this is only used for testing.
284 *
285 * @param className Class name
286 */
287 public static void setThreadLocalClassName(String className) {
288 ClassName.set(className);
289 }
290 /**
291 * Clears the class name (regardless of whether a class name was set).
292 * When a class name is set using <code>setThreadLocalClassName</code>,
293 * the setting whould be done in a try-block and a call to this
294 * clear method should be in the finally-clause of that try-block.
295 */
296 public static void clearThreadLocalClassName() {
297 ClassName.set(null);
298 }
299
300 /**
301 * The constructor for the <code>ExpCompiler.Factory</code>.
302 * This passes the <code>ExpCompiler</code> class to the
303 * <code>ObjectFactory</code> base class.
304 */
305 private Factory() {
306 super(ExpCompiler.class);
307 }
308 /**
309 * Get the class name set in the <code>ThreadLocal</code> or null.
310 *
311 * @return class name or null.
312 */
313 protected String getClassName() {
314 return getThreadLocalClassName();
315 }
316
317 /**
318 * Return the <code>ExpCompiler.Factory</code property name.
319 *
320 * @return <code>ExpCompiler.Factory</code> property name
321 */
322 protected StringProperty getStringProperty() {
323 return MondrianProperties.instance().ExpCompilerClass;
324 }
325 /**
326 * The <code>ExpCompiler.Factory</code>'s implementation of the
327 * <code>ObjectFactory</code>'s abstract method which returns
328 * the default <code>ExpCompiler</code> instance.
329 *
330 * @param parameterTypes array of classes: Evaluator, Validator and
331 * ResultStyle
332 * @param parameterValues the Evaluator, Validator and ResultStyle
333 * values
334 * @return <code>ExpCompiler</code> instance
335 * @throws CreationException if the <code>ExpCompiler</code> can not be
336 * created.
337 */
338 protected ExpCompiler getDefault(
339 final Class[] parameterTypes,
340 final Object[] parameterValues)
341 throws CreationException
342 {
343 // Strong typed above so don't need to check here
344 Evaluator evaluator = (Evaluator) parameterValues[0];
345 Validator validator = (Validator) parameterValues[1];
346 List<ResultStyle> resultStyles =
347 (List<ResultStyle>) parameterValues[2];
348
349 // Here there is bleed-through from the "calc.impl" implementation
350 // directory into the "calc" interface definition directory.
351 // This can be avoided if we were to use reflection to
352 // create this the default ExpCompiler implementation.
353 return new BetterExpCompiler(
354 evaluator, validator, resultStyles);
355 }
356
357 /**
358 * Get the underlying Factory object.
359 * <p>
360 * This is for testing only.
361 *
362 * @return the <code>ExpCompiler.Factory</code> object
363 */
364 public static Factory getFactory() {
365 return factory;
366 }
367
368 /**
369 * Get the current override contect.
370 * <p>
371 * This is for testing only.
372 *
373 * @return the override context object.
374 */
375 public Object removeContext() {
376 return new Context();
377 }
378
379 /**
380 * Restore the current overrides.
381 * <p>
382 * This is for testing only.
383 *
384 * @param context the current override object.
385 */
386 public void restoreContext(final Object context) {
387 if (context instanceof Context) {
388 ((Context) context).restore();
389 }
390 }
391
392 /**
393 * The <code>ExpCompiler</code> only has two override mechanisms: the
394 * <code>ThreadLocal</code> and <code>System</code>
395 * <code>Properties</code>. This class captures and clears the current
396 * values for both in the constructor and then replaces them
397 * in the <code>restore</code> method.
398 * <p>
399 * This is for testing only.
400 */
401 public static class Context implements ObjectFactory.Context {
402 private final String threadLocalClassName;
403 private final String systemPropertyClassName;
404
405 /**
406 * Creates a Context.
407 */
408 Context() {
409 this.threadLocalClassName =
410 ExpCompiler.Factory.getThreadLocalClassName();
411 if (this.threadLocalClassName != null) {
412 ExpCompiler.Factory.clearThreadLocalClassName();
413 }
414
415 this.systemPropertyClassName =
416 System.getProperty(ExpCompiler.class.getName());
417 if (this.systemPropertyClassName != null) {
418 System.getProperties().remove(ExpCompiler.class.getName());
419 }
420 }
421
422 /**
423 * Restores the previous context.
424 */
425 private void restore() {
426 if (this.threadLocalClassName != null) {
427 ExpCompiler.Factory.setThreadLocalClassName(
428 this.threadLocalClassName);
429 }
430 if (this.systemPropertyClassName != null) {
431 System.setProperty(
432 ExpCompiler.class.getName(),
433 this.systemPropertyClassName);
434 }
435 }
436 }
437 }
438 }
439
440 // End ExpCompiler.java