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