001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2006-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.calc.impl; 011 012import mondrian.calc.*; 013import mondrian.mdx.MdxVisitor; 014import mondrian.olap.*; 015import mondrian.olap.type.Type; 016 017import java.io.PrintWriter; 018import java.util.List; 019 020/** 021 * Abstract implementation of {@link mondrian.calc.ExpCompiler} 022 * 023 * @author jhyde 024 * @since Jan 2, 2006 025 */ 026public class DelegatingExpCompiler implements ExpCompiler { 027 private final ExpCompiler parent; 028 029 protected DelegatingExpCompiler(ExpCompiler parent) { 030 this.parent = parent; 031 } 032 033 /** 034 * Hook for post-processing. 035 * 036 * @param exp Expression to compile 037 * @param calc Calculator created by compiler 038 * @param mutable Whether the result is mutuable 039 * @return Calculator after post-processing 040 */ 041 protected Calc afterCompile(Exp exp, Calc calc, boolean mutable) { 042 return calc; 043 } 044 045 public Evaluator getEvaluator() { 046 return parent.getEvaluator(); 047 } 048 049 public Validator getValidator() { 050 return parent.getValidator(); 051 } 052 053 public Calc compile(Exp exp) { 054 final Calc calc = parent.compile(wrap(exp)); 055 return afterCompile(exp, calc, false); 056 } 057 058 public Calc compileAs( 059 Exp exp, 060 Type resultType, 061 List<ResultStyle> preferredResultTypes) 062 { 063 return parent.compileAs(wrap(exp), resultType, preferredResultTypes); 064 } 065 066 public MemberCalc compileMember(Exp exp) { 067 MemberCalc calc = parent.compileMember(wrap(exp)); 068 return (MemberCalc) afterCompile(exp, calc, false); 069 } 070 071 public LevelCalc compileLevel(Exp exp) { 072 final LevelCalc calc = parent.compileLevel(wrap(exp)); 073 return (LevelCalc) afterCompile(exp, calc, false); 074 } 075 076 public DimensionCalc compileDimension(Exp exp) { 077 final DimensionCalc calc = parent.compileDimension(wrap(exp)); 078 return (DimensionCalc) afterCompile(exp, calc, false); 079 } 080 081 public HierarchyCalc compileHierarchy(Exp exp) { 082 final HierarchyCalc calc = parent.compileHierarchy(wrap(exp)); 083 return (HierarchyCalc) afterCompile(exp, calc, false); 084 } 085 086 public IntegerCalc compileInteger(Exp exp) { 087 final IntegerCalc calc = parent.compileInteger(wrap(exp)); 088 return (IntegerCalc) afterCompile(exp, calc, false); 089 } 090 091 public StringCalc compileString(Exp exp) { 092 final StringCalc calc = parent.compileString(wrap(exp)); 093 return (StringCalc) afterCompile(exp, calc, false); 094 } 095 096 public DateTimeCalc compileDateTime(Exp exp) { 097 final DateTimeCalc calc = parent.compileDateTime(wrap(exp)); 098 return (DateTimeCalc) afterCompile(exp, calc, false); 099 } 100 101 public final ListCalc compileList(Exp exp) { 102 return compileList(exp, false); 103 } 104 105 public ListCalc compileList(Exp exp, boolean mutable) { 106 final ListCalc calc = parent.compileList(wrap(exp), mutable); 107 return (ListCalc) afterCompile(exp, calc, mutable); 108 } 109 110 public IterCalc compileIter(Exp exp) { 111 final IterCalc calc = parent.compileIter(wrap(exp)); 112 return (IterCalc) afterCompile(exp, calc, false); 113 } 114 115 public BooleanCalc compileBoolean(Exp exp) { 116 final BooleanCalc calc = parent.compileBoolean(wrap(exp)); 117 return (BooleanCalc) afterCompile(exp, calc, false); 118 } 119 120 public DoubleCalc compileDouble(Exp exp) { 121 final DoubleCalc calc = parent.compileDouble(wrap(exp)); 122 return (DoubleCalc) afterCompile(exp, calc, false); 123 } 124 125 public TupleCalc compileTuple(Exp exp) { 126 final TupleCalc calc = parent.compileTuple(wrap(exp)); 127 return (TupleCalc) afterCompile(exp, calc, false); 128 } 129 130 public Calc compileScalar(Exp exp, boolean scalar) { 131 final Calc calc = parent.compileScalar(wrap(exp), scalar); 132 return afterCompile(exp, calc, false); 133 } 134 135 public ParameterSlot registerParameter(Parameter parameter) { 136 return parent.registerParameter(parameter); 137 } 138 139 public List<ResultStyle> getAcceptableResultStyles() { 140 return parent.getAcceptableResultStyles(); 141 } 142 143 /** 144 * Wrapping an expression ensures that when it is visited, it calls 145 * back to this compiler rather than our parent (wrapped) compiler. 146 * 147 * <p>All methods that pass an expression to the delegate compiler should 148 * wrap expressions in this way. Hopefully the delegate compiler doesn't 149 * use {@code instanceof}; it should be using the visitor pattern instead. 150 * 151 * <p>If we didn't do this, the decorator would get forgotten at the first 152 * level of recursion. It's not pretty, and I thought about other ways 153 * of combining Visitor + Decorator. For instance, I tried replacing 154 * {@link #afterCompile(mondrian.olap.Exp, mondrian.calc.Calc, boolean)} 155 * with a callback (Strategy), but the exit points in ExpCompiler not 156 * clear because there are so many methods. 157 * 158 * @param e Expression to be wrapped 159 * @return wrapper expression 160 */ 161 private Exp wrap(Exp e) { 162 return new WrapExp(e, this); 163 } 164 165 /** 166 * See {@link mondrian.calc.impl.DelegatingExpCompiler#wrap}. 167 */ 168 private static class WrapExp implements Exp { 169 private final Exp e; 170 private final ExpCompiler wrappingCompiler; 171 172 WrapExp( 173 Exp e, 174 ExpCompiler wrappingCompiler) 175 { 176 this.e = e; 177 this.wrappingCompiler = wrappingCompiler; 178 } 179 180 public Exp clone() { 181 throw new UnsupportedOperationException(); 182 } 183 184 public int getCategory() { 185 return e.getCategory(); 186 } 187 188 public Type getType() { 189 return e.getType(); 190 } 191 192 public void unparse(PrintWriter pw) { 193 e.unparse(pw); 194 } 195 196 public Exp accept(Validator validator) { 197 return e.accept(validator); 198 } 199 200 public Calc accept(ExpCompiler compiler) { 201 return e.accept(wrappingCompiler); 202 } 203 204 public Object accept(MdxVisitor visitor) { 205 return e.accept(visitor); 206 } 207 } 208} 209 210// End DelegatingExpCompiler.java