1 10 package mondrian.olap.fun; 11 12 import mondrian.calc.*; 13 import mondrian.calc.impl.AbstractListCalc; 14 import mondrian.mdx.*; 15 import mondrian.olap.*; 16 import mondrian.olap.type.*; 17 import mondrian.rolap.RolapLevel; 18 import mondrian.rolap.RolapMember; 19 import mondrian.resource.MondrianResource; 20 21 import java.util.ArrayList ; 22 import java.util.List ; 23 24 31 public class VisualTotalsFunDef extends FunDefBase { 32 static final Resolver Resolver = new ReflectiveMultiResolver( 33 "VisualTotals", 34 "VisualTotals(<Set>[, <Pattern>])", 35 "Dynamically totals child members specified in a set using a pattern for the total label in the result set.", 36 new String [] {"fxx", "fxxS"}, 37 VisualTotalsFunDef.class); 38 39 public VisualTotalsFunDef(FunDef dummyFunDef) { 40 super(dummyFunDef); 41 } 42 43 protected Exp validateArg( 44 Validator validator, Exp[] args, int i, int category) { 45 final Exp validatedArg = super.validateArg(validator, args, i, category); 46 if (i == 0) { 47 final SetType setType = (SetType) validatedArg.getType(); 50 final Type elementType = setType.getElementType(); 51 if (!(elementType instanceof MemberType)) { 52 throw MondrianResource.instance(). 53 VisualTotalsAppliedToTuples.ex(); 54 } 55 } 56 return validatedArg; 57 } 58 59 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 60 final ListCalc listCalc = compiler.compileList(call.getArg(0)); 61 final StringCalc stringCalc = call.getArgCount() > 1 ? 62 compiler.compileString(call.getArg(1)) : 63 null; 64 return new CalcImpl(call, listCalc, stringCalc); 65 } 66 67 70 private static class CalcImpl extends AbstractListCalc { 71 private final ListCalc listCalc; 72 private final StringCalc stringCalc; 73 74 public CalcImpl( 75 ResolvedFunCall call, ListCalc listCalc, StringCalc stringCalc) { 76 super(call, new Calc[] {listCalc, stringCalc}); 77 this.listCalc = listCalc; 78 this.stringCalc = stringCalc; 79 } 80 81 public List evaluateList(Evaluator evaluator) { 82 final List <Member> list = listCalc.evaluateList(evaluator); 83 final List <Member> resultList = new ArrayList <Member>(list); 84 final int memberCount = list.size(); 85 for (int i = memberCount - 1; i >= 0; --i) { 86 Member member = list.get(i); 87 if (i + 1 < memberCount) { 88 Member nextMember = resultList.get(i + 1); 89 if (nextMember != member && 90 nextMember.isChildOrEqualTo(member)) { 91 resultList.set( 92 i, 93 createMember(member, i, resultList, evaluator)); 94 } 95 } 96 } 97 return resultList; 98 } 99 100 private VisualTotalMember createMember( 101 Member member, 102 int i, 103 final List <Member> list, 104 Evaluator evaluator) 105 { 106 final String name; 107 if (stringCalc != null) { 108 final String namePattern = stringCalc.evaluateString(evaluator); 109 name = substitute(namePattern, member.getName()); 110 } else { 111 name = member.getName(); 112 } 113 final List <Member> childMemberList = 114 followingDescendants(member, i + 1, list); 115 final Exp exp = makeExpr(childMemberList); 116 final Validator validator = evaluator.getQuery().createValidator(); 117 final Exp validatedExp = exp.accept(validator); 118 return new VisualTotalMember(member, name, validatedExp); 119 } 120 121 private List <Member> followingDescendants( 122 Member member, int i, final List <Member> list) 123 { 124 List <Member> childMemberList = new ArrayList <Member>(); 125 while (i < list.size()) { 126 Member descendant = list.get(i); 127 if (descendant == member) { 128 break; 130 } 131 if (!descendant.isChildOrEqualTo(member)) { 132 break; 133 } 134 if (descendant instanceof VisualTotalMember) { 135 VisualTotalMember visualTotalMember = 137 (VisualTotalMember) descendant; 138 childMemberList.add(visualTotalMember); 139 i = lastChildIndex(visualTotalMember.member, i, list); 140 continue; 141 } 142 childMemberList.add(descendant); 143 ++i; 144 } 145 return childMemberList; 146 } 147 148 private int lastChildIndex(Member member, int start, List list) { 149 int i = start; 150 while (true) { 151 ++i; 152 if (i >= list.size()) { 153 break; 154 } 155 Member descendant = (Member) list.get(i); 156 if (descendant == member) { 157 break; 159 } 160 if (!descendant.isChildOrEqualTo(member)) { 161 break; 162 } 163 } 164 return i; 165 } 166 167 private Exp makeExpr(final List childMemberList) { 168 Exp[] memberExprs = new Exp[childMemberList.size()]; 169 for (int i = 0; i < childMemberList.size(); i++) { 170 final Member childMember = (Member) childMemberList.get(i); 171 memberExprs[i] = new MemberExpr(childMember); 172 } 173 return new UnresolvedFunCall( 174 "Aggregate", 175 new Exp[] { 176 new UnresolvedFunCall( 177 "{}", 178 Syntax.Braces, 179 memberExprs) 180 }); 181 } 182 } 183 184 194 private static class VisualTotalMember extends RolapMember { 195 private final Member member; 196 private final Exp exp; 197 198 VisualTotalMember( 199 Member member, 200 String name, 201 final Exp exp) { 202 super( 203 (RolapMember) member.getParentMember(), 204 (RolapLevel) member.getLevel(), 205 null, name, MemberType.FORMULA); 206 this.member = member; 207 this.exp = exp; 208 } 209 210 public boolean isCalculated() { 211 return true; 212 } 213 214 public int getSolveOrder() { 215 return 99; 217 } 218 219 public Exp getExpression() { 220 return exp; 221 } 222 223 public int getOrdinal() { 224 throw new UnsupportedOperationException (); 225 } 226 227 public Member getDataMember() { 228 return member; 229 } 230 231 public OlapElement lookupChild(SchemaReader schemaReader, String s) { 232 throw new UnsupportedOperationException (); 233 } 234 235 public OlapElement lookupChild( 236 SchemaReader schemaReader, String s, MatchType matchType) { 237 throw new UnsupportedOperationException (); 238 } 239 240 public String getQualifiedName() { 241 throw new UnsupportedOperationException (); 242 } 243 } 244 245 259 static String substitute(String namePattern, String name) { 260 final StringBuilder buf = new StringBuilder (256); 261 final int namePatternLen = namePattern.length(); 262 int startIndex = 0; 263 264 while (true) { 265 int endIndex = namePattern.indexOf('*', startIndex); 266 267 if (endIndex == -1) { buf.append(namePattern.substring(startIndex)); 270 break; 271 } 272 273 ++endIndex; 275 if (endIndex < namePatternLen && namePattern.charAt(endIndex) == '*') { buf.append(namePattern.substring(startIndex, endIndex)); ++endIndex; } else { buf.append(namePattern.substring(startIndex, endIndex - 1)); buf.append(name); 281 } 282 283 startIndex = endIndex; 284 } 285 286 return buf.toString(); 287 } 288 289 } 290 291 | Popular Tags |