1 11 package mondrian.olap.fun; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.List ; 16 17 import mondrian.olap.*; 18 import mondrian.olap.type.NumericType; 19 import mondrian.calc.*; 20 import mondrian.calc.impl.AbstractListCalc; 21 import mondrian.mdx.ResolvedFunCall; 22 23 30 class DescendantsFunDef extends FunDefBase { 31 32 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 33 "Descendants", 34 "Descendants(<Member>[, <Level>[, <Desc_flag>]])", 35 "Returns the set of descendants of a member at a specified level, optionally including or excluding descendants in other levels.", 36 new String []{"fxm", "fxml", "fxmly", "fxmn", "fxmny"}, 37 DescendantsFunDef.class, 38 Flag.getNames()); 39 40 public DescendantsFunDef(FunDef dummyFunDef) { 41 super(dummyFunDef); 42 43 } 44 45 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 46 final MemberCalc memberCalc = compiler.compileMember(call.getArg(0)); 47 Flag flag = Flag.SELF; 48 if (call.getArgCount() == 1) { 49 flag = Flag.SELF_BEFORE_AFTER; 50 } 51 final boolean depthSpecified = call.getArgCount() >= 2 && 52 call.getArg(1).getType() instanceof NumericType; 53 if (call.getArgCount() >= 3) { 54 flag = FunUtil.getLiteralArg(call, 2, Flag.SELF, Flag.class); 55 } 56 57 if (depthSpecified && flag.leaves) { 58 final IntegerCalc depthCalc = call.getArgCount() > 1 ? 59 compiler.compileInteger(call.getArg(1)) : 60 null; 61 return new AbstractListCalc(call, new Calc[] {memberCalc, depthCalc}) { 62 public List evaluateList(Evaluator evaluator) { 63 final Member member = memberCalc.evaluateMember(evaluator); 64 List <Member> result = new ArrayList <Member>(); 65 int depth = depthCalc.evaluateInteger(evaluator); 66 if (depth < 0) { 67 depth = -1; } 69 final SchemaReader schemaReader = evaluator.getSchemaReader(); 70 descendantsLeavesByDepth( 71 member, result, schemaReader, depth); 72 hierarchize(result, false); 73 return result; 74 } 75 }; 76 } else if (depthSpecified) { 77 final IntegerCalc depthCalc = call.getArgCount() > 1 ? 78 compiler.compileInteger(call.getArg(1)) : 79 null; 80 final Flag flag1 = flag; 81 return new AbstractListCalc(call, new Calc[] {memberCalc, depthCalc}) { 82 public List evaluateList(Evaluator evaluator) { 83 final Member member = memberCalc.evaluateMember(evaluator); 84 List result = new ArrayList (); 85 final int depth = depthCalc.evaluateInteger(evaluator); 86 final SchemaReader schemaReader = evaluator.getSchemaReader(); 87 descendantsByDepth( 88 member, result, schemaReader, 89 depth, flag1.before, flag1.self, flag1.after, evaluator); 90 hierarchize(result, false); 91 return result; 92 } 93 }; 94 } else { 95 final LevelCalc levelCalc = call.getArgCount() > 1 ? 96 compiler.compileLevel(call.getArg(1)) : 97 null; 98 final Flag flag2 = flag; 99 return new AbstractListCalc(call, new Calc[] {memberCalc, levelCalc}) { 100 public List evaluateList(Evaluator evaluator) { 101 final Evaluator context = 102 evaluator.isNonEmpty() ? evaluator : null; 103 final Member member = memberCalc.evaluateMember(evaluator); 104 List <Member> result = new ArrayList <Member>(); 105 final SchemaReader schemaReader = evaluator.getSchemaReader(); 106 final Level level = levelCalc != null ? 107 levelCalc.evaluateLevel(evaluator) : 108 member.getLevel(); 109 descendantsByLevel( 110 schemaReader, member, level, result, 111 flag2.before, flag2.self, 112 flag2.after, flag2.leaves, context); 113 hierarchize(result, false); 114 return result; 115 } 116 }; 117 } 118 } 119 120 private static void descendantsByDepth( 121 Member member, 122 List result, 123 final SchemaReader schemaReader, 124 final int depthLimitFinal, 125 final boolean before, 126 final boolean self, 127 final boolean after, 128 final Evaluator context) { 129 Member[] children = {member}; 130 for (int depth = 0;; ++depth) { 131 if (depth == depthLimitFinal) { 132 if (self) { 133 addAll(result, children); 134 } 135 if (!after) { 136 break; } 138 } else if (depth < depthLimitFinal) { 139 if (before) { 140 addAll(result, children); 141 } 142 } else { 143 if (after) { 144 addAll(result, children); 145 } else { 146 break; } 148 } 149 150 children = schemaReader.getMemberChildren(children, context); 151 if (children.length == 0) { 152 break; 153 } 154 } 155 } 156 157 162 private static void descendantsLeavesByDepth( 163 final Member member, 164 final List <Member> result, 165 final SchemaReader schemaReader, 166 final int depthLimit) { 167 if (!schemaReader.isDrillable(member)) { 168 if (depthLimit >= 0) { 169 result.add(member); 170 } 171 return; 172 } 173 Member[] children = {member}; 174 for (int depth = 0; depthLimit == -1 || depth <= depthLimit; ++depth) { 175 children = schemaReader.getMemberChildren(children); 176 if (children.length == 0) { 177 throw Util.newInternal("drillable member must have children"); 178 } 179 List <Member> nextChildren = new ArrayList <Member>(); 180 for (Member child : children) { 181 if (schemaReader.isDrillable(child)) { 186 nextChildren.add(child); 187 } else { 188 result.add(child); 189 } 190 } 191 if (nextChildren.isEmpty()) { 192 return; 193 } 194 children = nextChildren.toArray(new Member[nextChildren.size()]); 195 } 196 } 197 198 213 static void descendantsByLevel( 214 SchemaReader schemaReader, 215 Member ancestor, 216 Level level, 217 List <Member> result, 218 boolean before, 219 boolean self, 220 boolean after, 221 boolean leaves, 222 Evaluator context) { 223 final int levelDepth = level.getDepth(); 239 Member[] members = {ancestor}; 240 if (leaves) { 245 assert !before && !self && !after; 246 do { 247 List <Member> nextMembers = new ArrayList <Member>(); 248 for (Member member : members) { 249 final int currentDepth = member.getLevel().getDepth(); 250 Member[] childMembers = 251 schemaReader.getMemberChildren(member, context); 252 if (childMembers.length == 0) { 253 if (currentDepth == levelDepth) { 255 result.add(member); 256 } 257 continue; 258 } else { 259 if (currentDepth <= levelDepth) { 262 nextMembers.addAll(Arrays.asList(childMembers)); 263 } 264 } 265 } 266 members = nextMembers.toArray(new Member[nextMembers.size()]); 267 } 268 while (members.length > 0); 269 } else { 270 List <Member> fertileMembers = new ArrayList <Member>(); 271 do { 272 fertileMembers.clear(); 273 for (Member member : members) { 274 final int currentDepth = member.getLevel().getDepth(); 275 if (currentDepth == levelDepth) { 276 if (self) { 277 result.add(member); 278 } 279 if (after) { 280 fertileMembers.add(member); 282 } 283 } else if (currentDepth < levelDepth) { 284 if (before) { 285 result.add(member); 286 } 287 fertileMembers.add(member); 288 } else { 289 if (after) { 290 result.add(member); 291 fertileMembers.add(member); 292 } 293 } 294 } 295 members = new Member[fertileMembers.size()]; 296 members = fertileMembers.toArray(members); 297 members = schemaReader.getMemberChildren(members, context); 298 } 299 while (members.length > 0); 300 } 301 } 302 303 307 enum Flag { 308 SELF(true, false, false, false), 309 AFTER(false, true, false, false), 310 BEFORE(false, false, true, false), 311 BEFORE_AND_AFTER(false, true, true, false), 312 SELF_AND_AFTER(true, true, false, false), 313 SELF_AND_BEFORE(true, false, true, false), 314 SELF_BEFORE_AFTER(true, true, true, false), 315 LEAVES(false, false, false, true); 316 317 private final boolean self; 318 private final boolean after; 319 private final boolean before; 320 private final boolean leaves; 321 322 Flag(boolean self, boolean after, boolean before, boolean leaves) { 323 this.self = self; 324 this.after = after; 325 this.before = before; 326 this.leaves = leaves; 327 } 328 329 public static String [] getNames() { 330 List <String > names = new ArrayList <String >(); 331 for (Flag flags : Flag.class.getEnumConstants()) { 332 names.add(flags.name()); 333 } 334 return names.toArray(new String [names.size()]); 335 } 336 } 337 } 338 339 | Popular Tags |