001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/ParameterImpl.java#7 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2000-2002 Kana Software, Inc.
007    // Copyright (C) 2001-2007 Julian Hyde and others
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    //
011    // leonardk, 10 January, 2000
012    */
013    
014    package mondrian.olap;
015    import mondrian.olap.type.Type;
016    import mondrian.olap.type.NumericType;
017    import mondrian.olap.type.StringType;
018    import mondrian.olap.type.MemberType;
019    import mondrian.mdx.MemberExpr;
020    import mondrian.calc.*;
021    import mondrian.calc.impl.GenericCalc;
022    
023    /**
024     * Implementation of {@link Parameter}.
025     *
026     * @author jhyde
027     * @version $Id: //open/mondrian/src/main/mondrian/olap/ParameterImpl.java#7 $
028     * @since Jul 22, 2006
029     */
030    public class ParameterImpl
031        implements Parameter, ParameterCompilable {
032    
033        private final String name;
034        private String description;
035        private Exp defaultExp;
036        private Type type;
037        private ParameterSlot slot = new ParameterSlot() {
038          Object value;
039          public Object getCachedDefaultValue() {
040            throw new UnsupportedOperationException();
041          }
042    
043          public Calc getDefaultValueCalc() {
044            throw new UnsupportedOperationException();
045          }
046    
047          public int getIndex() {
048            throw new UnsupportedOperationException();
049          }
050    
051          public Parameter getParameter() {
052            return ParameterImpl.this;
053          }
054    
055          public Object getParameterValue() {
056            return value;
057          }
058    
059          public void setCachedDefaultValue(Object value) {
060            throw new UnsupportedOperationException();
061          }
062    
063          public void setParameterValue(Object value) {
064            this.value = value;
065          }
066    
067        };
068    
069        public ParameterImpl(
070            String name,
071            Exp defaultExp,
072            String description,
073            Type type)
074        {
075            this.name = name;
076            this.defaultExp = defaultExp;
077            this.description = description;
078            this.type = type;
079            assert defaultExp != null;
080            assert type instanceof StringType ||
081                type instanceof NumericType ||
082                type instanceof MemberType;
083        }
084    
085        public Scope getScope() {
086            return Scope.Statement;
087        }
088    
089        public Type getType() {
090            return type;
091        }
092    
093        public Exp getDefaultExp() {
094            return defaultExp;
095        }
096    
097        public String getName() {
098            return name;
099        }
100    
101        public Object getValue() {
102            if (slot == null) {
103                // query has not been resolved yet, so it's not possible for the
104                // parameter to have a value
105                return null;
106            } else {
107                return slot.getParameterValue();
108            }
109        }
110    
111        public void setValue(Object value) {
112            if (value instanceof MemberExpr) {
113                slot.setParameterValue(((MemberExpr) value).getMember());
114            } else if (value instanceof Literal) {
115                slot.setParameterValue(((Literal) value).getValue());
116            } else {
117                slot.setParameterValue(value);
118            }
119        }
120    
121        public String getDescription() {
122            return description;
123        }
124    
125        // For the purposes of type inference and expression substitution, a
126        // parameter is atomic; therefore, we ignore the child member, if any.
127        public Object[] getChildren() {
128            return null;
129        }
130    
131        /**
132         * Returns whether this parameter is equal to another, based upon name,
133         * type and value
134         */
135        public boolean equals(Object other) {
136            if (!(other instanceof ParameterImpl)) {
137                return false;
138            }
139            ParameterImpl that = (ParameterImpl) other;
140            return that.getName().equals(this.getName()) &&
141                that.defaultExp.equals(this.defaultExp);
142        }
143    
144        public int hashCode() {
145            return Util.hash(getName().hashCode(), defaultExp.hashCode());
146        }
147    
148        /**
149         * Returns whether the parameter can be modified.
150         */
151        public boolean isModifiable() {
152            return true;
153        }
154    
155        public void setDescription(String description) {
156            this.description = description;
157        }
158    
159        public void setType(Type type) {
160            assert type instanceof StringType ||
161                type instanceof NumericType ||
162                type instanceof MemberType;
163            this.type = type;
164        }
165    
166        public void setDefaultExp(Exp defaultExp) {
167            assert defaultExp != null;
168            this.defaultExp = defaultExp;
169        }
170    
171        public Calc compile(ExpCompiler compiler) {
172            final ParameterSlot slot = compiler.registerParameter(this);
173            if (this.slot != null) {
174                // save previous value
175                slot.setParameterValue(this.slot.getParameterValue());
176            }
177            this.slot = slot;
178            return new ParameterCalc(slot);
179        }
180    
181        /**
182         * Compiled expression which yields the value of a parameter.
183         * It uses a slot which has a unique id within the execution environment.
184         */
185        private static class ParameterCalc
186            extends GenericCalc {
187            private final ParameterSlot slot;
188    
189            public ParameterCalc(ParameterSlot slot) {
190                super(new DummyExp(slot.getParameter().getType()));
191                this.slot = slot;
192            }
193    
194            public Calc[] getCalcs() {
195                return new Calc[0];
196            }
197    
198            public Object evaluate(Evaluator evaluator) {
199                Object value = evaluator.getParameterValue(slot);
200                if (slot.getParameterValue() == null) {
201                    // save value if not set (setting the default value)
202                    slot.setParameterValue(value);
203                }
204                return value;
205            }
206        }
207    }
208    
209    // End ParameterImpl.java
210