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-2010 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.calc.impl;
011
012import mondrian.calc.*;
013import mondrian.olap.*;
014import mondrian.olap.fun.FunUtil;
015
016import java.util.Date;
017
018/**
019 * Adapter which computes a scalar or tuple expression and converts it to any
020 * required type.
021 *
022 * @see mondrian.calc.impl.GenericIterCalc
023 *
024 * @author jhyde
025 * @since Sep 26, 2005
026 */
027public abstract class GenericCalc
028    extends AbstractCalc
029    implements TupleCalc,
030    StringCalc, IntegerCalc, DoubleCalc, BooleanCalc, DateTimeCalc,
031    VoidCalc, MemberCalc, LevelCalc, HierarchyCalc, DimensionCalc
032{
033    /**
034     * Creates a GenericCalc without specifying child calculated expressions.
035     *
036     * <p>Subclass should override {@link #getCalcs()}.
037     *
038     * @param exp Source expression
039     */
040    protected GenericCalc(Exp exp) {
041        super(exp, null);
042    }
043
044    /**
045     * Creates an GenericCalc.
046     *
047     * @param exp Source expression
048     * @param calcs Child compiled expressions
049     */
050    protected GenericCalc(Exp exp, Calc[] calcs) {
051        super(exp, calcs);
052    }
053
054    public Member[] evaluateTuple(Evaluator evaluator) {
055        return (Member[]) evaluate(evaluator);
056    }
057
058    private String msg(TypeEnum expectedType, Object o) {
059        final TypeEnum actualType = actualType(o);
060        return "Expected value of type " + expectedType + "; got value '" + o
061           + "' (" + (actualType == null ? o.getClass() : actualType) + ")";
062    }
063
064    private static TypeEnum actualType(Object o) {
065        if (o == null) {
066            return TypeEnum.NULL;
067        } else if (o instanceof String) {
068            return TypeEnum.STRING;
069        } else if (o instanceof Boolean) {
070            return TypeEnum.BOOLEAN;
071        } else if (o instanceof Number) {
072            return TypeEnum.NUMERIC;
073        } else if (o instanceof Date) {
074            return TypeEnum.DATETIME;
075        } else if (o instanceof Member) {
076            return TypeEnum.MEMBER;
077        } else if (o instanceof Level) {
078            return TypeEnum.LEVEL;
079        } else if (o instanceof Hierarchy) {
080            return TypeEnum.HIERARCHY;
081        } else if (o instanceof Dimension) {
082            return TypeEnum.DIMENSION;
083        } else {
084            return null;
085        }
086    }
087
088    public String evaluateString(Evaluator evaluator) {
089        final Object o = evaluate(evaluator);
090        try {
091            return (String) o;
092        } catch (ClassCastException e) {
093            throw evaluator.newEvalException(null, msg(TypeEnum.STRING, o));
094        }
095    }
096
097    public int evaluateInteger(Evaluator evaluator) {
098        Object o = evaluate(evaluator);
099        try {
100            final Number number = (Number) o;
101            return number == null
102                ? FunUtil.IntegerNull
103                : number.intValue();
104        } catch (ClassCastException e) {
105            throw evaluator.newEvalException(null, msg(TypeEnum.NUMERIC, o));
106        }
107    }
108
109    public double evaluateDouble(Evaluator evaluator) {
110        final Object o = evaluate(evaluator);
111        try {
112            final Number number = (Number) o;
113            return numberToDouble(number);
114        } catch (ClassCastException e) {
115            throw evaluator.newEvalException(null, msg(TypeEnum.NUMERIC, o));
116        }
117    }
118
119    public static double numberToDouble(Number number) {
120        return number == null
121            ? FunUtil.DoubleNull
122            : number.doubleValue();
123    }
124
125    public boolean evaluateBoolean(Evaluator evaluator) {
126        final Object o = evaluate(evaluator);
127        try {
128            return (Boolean) o;
129        } catch (ClassCastException e) {
130            throw evaluator.newEvalException(null, msg(TypeEnum.BOOLEAN, o));
131        }
132    }
133
134    public Date evaluateDateTime(Evaluator evaluator) {
135        final Object o = evaluate(evaluator);
136        try {
137            return (Date) o;
138        } catch (ClassCastException e) {
139            throw evaluator.newEvalException(null, msg(TypeEnum.DATETIME, o));
140        }
141    }
142
143    public void evaluateVoid(Evaluator evaluator) {
144        final Object result = evaluate(evaluator);
145        assert result == null;
146    }
147
148    public Member evaluateMember(Evaluator evaluator) {
149        final Object o = evaluate(evaluator);
150        try {
151            return (Member) o;
152        } catch (ClassCastException e) {
153            throw evaluator.newEvalException(null, msg(TypeEnum.MEMBER, o));
154        }
155    }
156
157    public Level evaluateLevel(Evaluator evaluator) {
158        final Object o = evaluate(evaluator);
159        try {
160            return (Level) o;
161        } catch (ClassCastException e) {
162            throw evaluator.newEvalException(null, msg(TypeEnum.LEVEL, o));
163        }
164    }
165
166    public Hierarchy evaluateHierarchy(Evaluator evaluator) {
167        final Object o = evaluate(evaluator);
168        try {
169            return (Hierarchy) o;
170        } catch (ClassCastException e) {
171            throw evaluator.newEvalException(null, msg(TypeEnum.HIERARCHY, o));
172        }
173    }
174
175    public Dimension evaluateDimension(Evaluator evaluator) {
176        final Object o = evaluate(evaluator);
177        try {
178            return (Dimension) o;
179        } catch (ClassCastException e) {
180            throw evaluator.newEvalException(null, msg(TypeEnum.DIMENSION, o));
181        }
182    }
183
184    private enum TypeEnum {
185        NULL,
186        BOOLEAN, STRING, NUMERIC, DATETIME,
187        MEMBER, LEVEL, HIERARCHY, DIMENSION
188    }
189}
190
191// End GenericCalc.java