001 /* 002 // $Id: //open/mondrian/src/main/mondrian/calc/impl/AbstractCalc.java#11 $ 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) 2006-2007 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.calc.impl; 011 012 import mondrian.olap.*; 013 import mondrian.olap.type.Type; 014 import mondrian.calc.Calc; 015 import mondrian.calc.CalcWriter; 016 import mondrian.calc.ResultStyle; 017 import mondrian.mdx.ResolvedFunCall; 018 019 import java.io.PrintWriter; 020 import java.util.List; 021 import java.util.Collections; 022 023 /** 024 * Abstract implementation of the {@link mondrian.calc.Calc} interface. 025 * 026 * @author jhyde 027 * @version $Id: //open/mondrian/src/main/mondrian/calc/impl/AbstractCalc.java#11 $ 028 * @since Sep 27, 2005 029 */ 030 public abstract class AbstractCalc implements Calc { 031 protected final Type type; 032 protected final Exp exp; 033 034 protected AbstractCalc(Exp exp) { 035 assert exp != null; 036 this.exp = exp; 037 this.type = exp.getType(); 038 } 039 040 public Type getType() { 041 return type; 042 } 043 044 public void accept(CalcWriter calcWriter) { 045 final PrintWriter pw = calcWriter.getWriter(); 046 String name = getName(); 047 pw.print(name); 048 final Calc[] calcs = getCalcs(); 049 final List<Object> argumentList = getArguments(); 050 if (calcs.length > 0 || !argumentList.isEmpty()) { 051 pw.print("("); 052 int k = 0; 053 for (Calc calc : calcs) { 054 if (k++ > 0) { 055 pw.print(", "); 056 } 057 calc.accept(calcWriter); 058 } 059 for (Object o : argumentList) { 060 if (k++ > 0) { 061 pw.print(", "); 062 } 063 pw.print(o); 064 } 065 pw.print(")"); 066 } 067 } 068 069 /** 070 * Returns the name of this expression type, used when serializing an 071 * expression to a string. 072 * 073 * <p>The default implementation tries to extract a name from a function call, 074 * if any, then prints the last part of the class name. 075 */ 076 protected String getName() { 077 String name; 078 if (exp instanceof ResolvedFunCall) { 079 ResolvedFunCall funCall = (ResolvedFunCall) exp; 080 name = funCall.getFunDef().getName(); 081 } else { 082 name = getClass().getName(); 083 int dot = name.lastIndexOf('.'); 084 int dollar = name.lastIndexOf('$'); 085 int dotDollar = Math.max(dot, dollar); 086 if (dotDollar >= 0) { 087 name = name.substring(dotDollar + 1); 088 } 089 } 090 return name; 091 } 092 093 /** 094 * Returns this expression's child expressions. 095 */ 096 public abstract Calc[] getCalcs(); 097 098 public boolean dependsOn(Dimension dimension) { 099 return anyDepends(getCalcs(), dimension); 100 } 101 102 /** 103 * Returns true if one of the calcs depends on the given dimension. 104 */ 105 public static boolean anyDepends(Calc[] calcs, Dimension dimension) { 106 for (Calc calc : calcs) { 107 if (calc != null && calc.dependsOn(dimension)) { 108 return true; 109 } 110 } 111 return false; 112 } 113 114 /** 115 * Returns true if calc[0] depends on dimension, 116 * else false if calc[0] returns dimension, 117 * else true if any of the other calcs depend on dimension. 118 * 119 * <p>Typical application: <code>Aggregate({Set}, {Value Expression})</code> 120 * depends upon everything {Value Expression} depends upon, except the 121 * dimensions of {Set}. 122 */ 123 public static boolean anyDependsButFirst( 124 Calc[] calcs, Dimension dimension) { 125 if (calcs.length == 0) { 126 return false; 127 } 128 if (calcs[0].dependsOn(dimension)) { 129 return true; 130 } 131 if (calcs[0].getType().usesDimension(dimension, true)) { 132 return false; 133 } 134 for (int i = 1; i < calcs.length; i++) { 135 Calc calc = calcs[i]; 136 if (calc != null && calc.dependsOn(dimension)) { 137 return true; 138 } 139 } 140 return false; 141 } 142 143 /** 144 * Returns true if any of the calcs depend on dimension, 145 * else false if any of the calcs return dimension, 146 * else true. 147 */ 148 public static boolean butDepends( 149 Calc[] calcs, Dimension dimension) { 150 boolean result = true; 151 for (Calc calc : calcs) { 152 if (calc != null) { 153 if (calc.dependsOn(dimension)) { 154 return true; 155 } 156 if (calc.getType().usesDimension(dimension, true)) { 157 result = false; 158 } 159 } 160 } 161 return result; 162 } 163 164 /** 165 * Returns any other arguments to this calc. 166 * The default implementation returns the empty list. 167 */ 168 public List<Object> getArguments() { 169 return Collections.emptyList(); 170 } 171 172 /** 173 * Returns a simplified evalator whose context is the same for every 174 * dimension which an expression depends on, and the default member for 175 * every dimension which it does not depend on. 176 * 177 * <p>The default member is often the 'all' member, so this evaluator is 178 * usually the most efficient context in which to evaluate the expression. 179 * 180 * @param calc 181 * @param evaluator 182 */ 183 public static Evaluator simplifyEvaluator(Calc calc, Evaluator evaluator) { 184 if (evaluator.isNonEmpty()) { 185 // If NON EMPTY is present, we cannot simplify the context, because 186 // we have to assume that the expression depends on everything. 187 // TODO: Bug 1456418: Convert 'NON EMPTY Crossjoin' to 188 // 'NonEmptyCrossJoin'. 189 return evaluator; 190 } 191 int changeCount = 0; 192 Evaluator ev = evaluator; 193 final Dimension[] dimensions = evaluator.getCube().getDimensions(); 194 for (Dimension dimension : dimensions) { 195 final Member member = ev.getContext(dimension); 196 if (member.isAll()) { 197 continue; 198 } 199 if (calc.dependsOn(dimension)) { 200 continue; 201 } 202 final Member unconstrainedMember = 203 member.getHierarchy().getDefaultMember(); 204 if (member == unconstrainedMember) { 205 // This is a hierarchy without an 'all' member, and the context 206 // is already the default member. 207 continue; 208 } 209 if (changeCount++ == 0) { 210 ev = evaluator.push(unconstrainedMember); 211 } else { 212 ev.setContext(unconstrainedMember); 213 } 214 } 215 return ev; 216 } 217 218 public ResultStyle getResultStyle() { 219 return ResultStyle.VALUE; 220 } 221 } 222 223 // End AbstractCalc.java