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) 2000-2005 Julian Hyde
008// Copyright (C) 2005-2011 Pentaho and others
009// All Rights Reserved.
010*/
011package mondrian.olap;
012
013import mondrian.calc.*;
014import mondrian.calc.impl.AbstractListCalc;
015import mondrian.calc.impl.GenericCalc;
016import mondrian.mdx.MemberExpr;
017import mondrian.olap.type.*;
018
019import java.util.List;
020
021/**
022 * Implementation of {@link Parameter}.
023 *
024 * @author jhyde
025 * @since Jul 22, 2006
026 */
027public class ParameterImpl
028    implements Parameter, ParameterCompilable
029{
030    private final String name;
031    private String description;
032    private Exp defaultExp;
033    private Type type;
034    private ParameterSlot slot = new ParameterSlot() {
035        Object value;
036        boolean assigned;
037
038        public Object getCachedDefaultValue() {
039            throw new UnsupportedOperationException();
040        }
041
042        public Calc getDefaultValueCalc() {
043            throw new UnsupportedOperationException();
044        }
045
046        public int getIndex() {
047            throw new UnsupportedOperationException();
048        }
049
050        public Parameter getParameter() {
051            return ParameterImpl.this;
052        }
053
054        public Object getParameterValue() {
055            return value;
056        }
057
058        public boolean isParameterSet() {
059            return assigned;
060        }
061
062        public void unsetParameterValue() {
063            this.assigned = false;
064            this.value = null;
065        }
066
067        public void setCachedDefaultValue(Object value) {
068            throw new UnsupportedOperationException();
069        }
070
071        public void setParameterValue(Object value, boolean assigned) {
072            this.assigned = true;
073            this.value = value;
074
075            // make sure caller called convert first
076            assert !(value instanceof List && !(value instanceof TupleList));
077            assert !(value instanceof MemberExpr);
078            assert !(value instanceof Literal);
079        }
080    };
081
082    public ParameterImpl(
083        String name,
084        Exp defaultExp,
085        String description,
086        Type type)
087    {
088        this.name = name;
089        this.defaultExp = defaultExp;
090        this.description = description;
091        this.type = type;
092        assert defaultExp != null;
093        assert type instanceof StringType
094            || type instanceof NumericType
095            || type instanceof MemberType;
096    }
097
098    public Scope getScope() {
099        return Scope.Statement;
100    }
101
102    public Type getType() {
103        return type;
104    }
105
106    public Exp getDefaultExp() {
107        return defaultExp;
108    }
109
110    public String getName() {
111        return name;
112    }
113
114    public Object getValue() {
115        if (slot == null) {
116            // query has not been resolved yet, so it's not possible for the
117            // parameter to have a value
118            return null;
119        } else {
120            final Object value = slot.getParameterValue();
121            return convertBack(value);
122        }
123    }
124
125    public void setValue(Object value) {
126        slot.setParameterValue(convert(value), true);
127    }
128
129    public boolean isSet() {
130        return slot != null
131            && slot.isParameterSet();
132    }
133
134    public void unsetValue() {
135        slot.unsetParameterValue();
136    }
137
138    public String getDescription() {
139        return description;
140    }
141
142    // For the purposes of type inference and expression substitution, a
143    // parameter is atomic; therefore, we ignore the child member, if any.
144    public Object[] getChildren() {
145        return null;
146    }
147
148    /**
149     * Returns whether this parameter is equal to another, based upon name,
150     * type and value
151     */
152    public boolean equals(Object other) {
153        if (!(other instanceof ParameterImpl)) {
154            return false;
155        }
156        ParameterImpl that = (ParameterImpl) other;
157        return that.getName().equals(this.getName())
158            && that.defaultExp.equals(this.defaultExp);
159    }
160
161    public int hashCode() {
162        return Util.hash(getName().hashCode(), defaultExp.hashCode());
163    }
164
165    /**
166     * Returns whether the parameter can be modified.
167     */
168    public boolean isModifiable() {
169        return true;
170    }
171
172    public void setDescription(String description) {
173        this.description = description;
174    }
175
176    public void setType(Type type) {
177        assert type instanceof StringType
178            || type instanceof NumericType
179            || type instanceof MemberType
180            || (type instanceof SetType
181                && ((SetType) type).getElementType() instanceof MemberType)
182            : type;
183        this.type = type;
184    }
185
186    public void setDefaultExp(Exp defaultExp) {
187        assert defaultExp != null;
188        this.defaultExp = defaultExp;
189    }
190
191    public Calc compile(ExpCompiler compiler) {
192        final ParameterSlot slot = compiler.registerParameter(this);
193        if (this.slot != null) {
194            // save previous value
195            if (this.slot.isParameterSet()) {
196                slot.setParameterValue(
197                    this.slot.getParameterValue(),
198                    true);
199            }
200        }
201        this.slot = slot;
202        if (type instanceof SetType) {
203            return new MemberListParameterCalc(slot);
204        } else {
205            return new ParameterCalc(slot);
206        }
207    }
208
209    protected Object convert(Object value) {
210        // Convert from old-style tuple list (list of member or member[])
211        // to new-style list (TupleList).
212        if (value instanceof List && !(value instanceof TupleList)) {
213            List list = (List) value;
214            return TupleCollections.asTupleList(list);
215        }
216        if (value instanceof MemberExpr) {
217            return ((MemberExpr) value).getMember();
218        }
219        if (value instanceof Literal) {
220            return ((Literal) value).getValue();
221        }
222        return value;
223    }
224
225    public static Object convertBack(Object value) {
226        if (value instanceof TupleList) {
227            TupleList tupleList = (TupleList) value;
228            if (tupleList.getArity() == 1) {
229                return tupleList.slice(0);
230            } else {
231                return TupleCollections.asMemberArrayList(tupleList);
232            }
233        }
234        return value;
235    }
236
237    /**
238     * Compiled expression which yields the value of a scalar, member, level,
239     * hierarchy or dimension parameter.
240     *
241     * <p>It uses a slot which has a unique id within the execution environment.
242     *
243     * @see MemberListParameterCalc
244     */
245    private static class ParameterCalc
246        extends GenericCalc
247    {
248        private final ParameterSlot slot;
249
250        /**
251         * Creates a ParameterCalc.
252         *
253         * @param slot Slot
254         */
255        public ParameterCalc(ParameterSlot slot) {
256            super(new DummyExp(slot.getParameter().getType()), new Calc[0]);
257            this.slot = slot;
258        }
259
260        public Object evaluate(Evaluator evaluator) {
261            Object value = evaluator.getParameterValue(slot);
262            if (!slot.isParameterSet()) {
263                // save value if not set (setting the default value)
264                slot.setParameterValue(value, false);
265            }
266            return value;
267        }
268    }
269
270    /**
271     * Compiled expression which yields the value of parameter whose type is
272     * a list of members.
273     *
274     * <p>It uses a slot which has a unique id within the execution environment.
275     *
276     * @see ParameterCalc
277     */
278    private static class MemberListParameterCalc
279        extends AbstractListCalc
280    {
281        private final ParameterSlot slot;
282
283        /**
284         * Creates a MemberListParameterCalc.
285         *
286         * @param slot Slot
287         */
288        public MemberListParameterCalc(ParameterSlot slot) {
289            super(new DummyExp(slot.getParameter().getType()), new Calc[0]);
290            this.slot = slot;
291        }
292
293        public TupleList evaluateList(Evaluator evaluator) {
294            TupleList value = (TupleList) evaluator.getParameterValue(slot);
295            if (!slot.isParameterSet()) {
296                // save value if not set (setting the default value)
297                slot.setParameterValue(value, false);
298            }
299            return value;
300        }
301    }
302}
303
304// End ParameterImpl.java