1 10 package mondrian.rolap; 11 12 import mondrian.olap.*; 13 import mondrian.calc.*; 14 import mondrian.calc.impl.DelegatingExpCompiler; 15 import mondrian.calc.impl.GenericCalc; 16 17 import java.util.*; 18 import java.io.StringWriter ; 19 import java.io.PrintWriter ; 20 21 36 public class RolapDependencyTestingEvaluator extends RolapEvaluator { 37 38 41 RolapDependencyTestingEvaluator(RolapResult result, int expDeps) { 42 super(new DteRoot(result, expDeps)); 43 } 44 45 48 private RolapDependencyTestingEvaluator( 49 RolapEvaluatorRoot root, 50 RolapDependencyTestingEvaluator evaluator, 51 CellReader cellReader, 52 Member[] cloneCurrentMembers) { 53 super(root, evaluator, cellReader, cloneCurrentMembers); 54 } 55 56 public Object evaluate( 57 Calc calc, 58 Dimension[] independentDimensions, 59 String mdxString) { 60 final DteRoot dteRoot = 61 (DteRoot) root; 62 if (dteRoot.faking) { 63 ++dteRoot.fakeCallCount; 64 } else { 65 ++dteRoot.callCount; 66 } 67 final Object result = calc.evaluate(this); 69 if (dteRoot.result.isDirty()) { 70 return result; 71 } 72 73 if (dteRoot.disabled || 83 dteRoot.faking || 84 isNonEmpty() || 85 (double) dteRoot.fakeCallCount > 86 (double) dteRoot.callCount * dteRoot.random.nextDouble() * 87 2 * dteRoot.expDeps) { 88 return result; 89 } 90 if (independentDimensions.length == 0) { 91 return result; 92 } 93 dteRoot.faking = true; 94 ++dteRoot.fakeCount; 95 ++dteRoot.fakeCallCount; 96 final int i = dteRoot.random.nextInt(independentDimensions.length); 97 final Member saveMember = getContext(independentDimensions[i]); 98 final Member otherMember = 99 dteRoot.chooseOtherMember( 100 saveMember, getQuery().getSchemaReader(false)); 101 setContext(otherMember); 102 final Object otherResult = calc.evaluate(this); 103 if (false) { 104 System.out.println( 105 "original=" + saveMember.getUniqueName() + 106 ", member=" + otherMember.getUniqueName() + 107 ", originalResult=" + result + "" + 108 ", result=" + otherResult); 109 } 110 if (!equals(otherResult, result)) { 111 final Member[] members = getMembers(); 112 final StringBuilder buf = new StringBuilder (); 113 for (int j = 0; j < members.length; j++) { 114 if (j > 0) { 115 buf.append(", "); 116 } 117 buf.append(members[j].getUniqueName()); 118 } 119 throw Util.newInternal( 120 "Expression '" + mdxString + 121 "' claims to be independent of dimension " + 122 saveMember.getDimension() + " but is not; context is {" + 123 buf.toString() + "}; First result: " + 124 toString(result) + ", Second result: " + 125 toString(otherResult)); 126 } 127 setContext(saveMember); 129 dteRoot.faking = false; 130 return result; 131 } 132 133 public RolapEvaluator _push() { 134 Member[] cloneCurrentMembers = getMembers().clone(); 135 return new RolapDependencyTestingEvaluator( 136 root, 137 this, 138 cellReader, 139 cloneCurrentMembers); 140 } 141 142 143 private boolean equals(Object o1, Object o2) { 144 if (o1 == null) { 145 return o2 == null; 146 } 147 if (o2 == null) { 148 return false; 149 } 150 if (o1 instanceof Object []) { 151 if (o2 instanceof Object []) { 152 Object [] a1 = (Object []) o1; 153 Object [] a2 = (Object []) o2; 154 if (a1.length == a2.length) { 155 for (int i = 0; i < a1.length; i++) { 156 if (!equals(a1[i], a2[i])) { 157 return false; 158 } 159 } 160 return true; 161 } 162 } 163 return false; 164 } 165 if (o1 instanceof List) { 166 if (o2 instanceof List) { 167 return equals( 168 ((List) o1).toArray(), 169 ((List) o2).toArray()); 170 } 171 return false; 172 } 173 return o1.equals(o2); 174 } 175 176 private String toString(Object o) { 177 StringWriter sw = new StringWriter (); 178 PrintWriter pw = new PrintWriter (sw); 179 toString(o, pw); 180 return sw.toString(); 181 } 182 183 private void toString(Object o, PrintWriter pw) { 184 if (o instanceof Object []) { 185 Object [] a = (Object []) o; 186 pw.print("{"); 187 for (int i = 0; i < a.length; i++) { 188 Object o1 = a[i]; 189 if (i > 0) { 190 pw.print(", "); 191 } 192 toString(o1, pw); 193 } 194 pw.print("}"); 195 } else if (o instanceof List) { 196 List list = (List) o; 197 toString(list.toArray(), pw); 198 } else if (o instanceof Member) { 199 Member member = (Member) o; 200 pw.print(member.getUniqueName()); 201 } else { 202 pw.print(o); 203 } 204 } 205 206 209 static class DteRoot extends RolapResult.RolapResultEvaluatorRoot { 210 final int expDeps; 211 final RolapResult result; 212 int callCount; 213 int fakeCallCount; 214 int fakeCount; 215 boolean faking; 216 boolean disabled; 217 final Random random = Util.createRandom( 218 MondrianProperties.instance().TestSeed.get()); 219 220 DteRoot(RolapResult result, int expDeps) { 221 super(result); 222 this.expDeps = expDeps; 223 this.result = result; 224 } 225 226 234 private Member chooseOtherMember( 235 final Member save, SchemaReader schemaReader) { 236 final Hierarchy hierarchy = save.getHierarchy(); 237 int attempt = 0; 238 while (true) { 239 final Level[] levels = hierarchy.getLevels(); 241 final int levelDepth = random.nextInt(levels.length) + 1; 242 Member member = null; 243 for (int i = 0; i < levelDepth; i++) { 244 Member[] members; 245 if (i == 0) { 246 members = schemaReader.getLevelMembers(levels[i], false); 247 } else { 248 members = schemaReader.getMemberChildren(member); 249 } 250 if (members.length == 0) { 251 break; 252 } 253 member = members[random.nextInt(members.length)]; 254 } 255 if (member != save || ++attempt > 100) { 259 return member; 260 } 261 } 262 } 263 } 264 265 268 private static class DteCalcImpl extends GenericCalc { 269 private final Calc calc; 270 private final Dimension[] independentDimensions; 271 private final boolean mutableList; 272 private final String mdxString; 273 274 DteCalcImpl( 275 Calc calc, 276 Dimension[] independentDimensions, 277 boolean mutableList, 278 String mdxString) { 279 super(new DummyExp(calc.getType())); 280 this.calc = calc; 281 this.independentDimensions = independentDimensions; 282 this.mutableList = mutableList; 283 this.mdxString = mdxString; 284 } 285 286 public Calc[] getCalcs() { 287 return new Calc[] {calc}; 288 } 289 290 public Object evaluate(Evaluator evaluator) { 291 RolapDependencyTestingEvaluator dtEval = 292 (RolapDependencyTestingEvaluator) evaluator; 293 return dtEval.evaluate(calc, independentDimensions, mdxString); 294 } 295 296 public List evaluateList(Evaluator evaluator) { 297 List list = super.evaluateList(evaluator); 298 if (!mutableList) { 299 list = Collections.unmodifiableList(list); 300 } 301 return list; 302 } 303 304 public ExpCompiler.ResultStyle getResultStyle() { 305 return calc.getResultStyle(); 306 } 307 } 308 309 315 static class DteCompiler extends DelegatingExpCompiler { 316 DteCompiler(ExpCompiler compiler) { 317 super(compiler); 318 } 319 320 protected Calc afterCompile(Exp exp, Calc calc, boolean mutable) { 321 Dimension[] dimensions = getIndependentDimensions(calc); 322 calc = super.afterCompile(exp, calc, mutable); 323 return new DteCalcImpl( 324 calc, 325 dimensions, 326 mutable, 327 Util.unparse(exp)); 328 } 329 330 333 private Dimension[] getIndependentDimensions(Calc calc) { 334 List<Dimension> indDimList = new ArrayList<Dimension>(); 335 final Dimension[] dims = 336 getValidator().getQuery().getCube().getDimensions(); 337 for (Dimension dim : dims) { 338 if (!calc.dependsOn(dim)) { 339 indDimList.add(dim); 340 } 341 } 342 return indDimList.toArray(new Dimension[indDimList.size()]); 343 } 344 } 345 } 346 347 | Popular Tags |