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