1 13 package com.tonbeller.jpivot.olap.query; 14 15 import java.util.ArrayList ; 16 import java.util.Arrays ; 17 import java.util.Collection ; 18 import java.util.Collections ; 19 import java.util.Comparator ; 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.Map ; 24 25 import org.apache.log4j.Logger; 26 27 import com.tonbeller.jpivot.olap.model.Dimension; 28 import com.tonbeller.jpivot.olap.model.Hierarchy; 29 import com.tonbeller.jpivot.olap.model.Level; 30 import com.tonbeller.jpivot.olap.model.Member; 31 import com.tonbeller.jpivot.olap.model.Position; 32 import com.tonbeller.jpivot.olap.navi.CalcSet; 33 import com.tonbeller.jpivot.util.TreeNode; 34 import com.tonbeller.jpivot.util.TreeNodeCallback; 35 36 public class Quax { 37 38 static Logger logger = Logger.getLogger(Quax.class); 39 40 protected int nDimension; 41 42 private Hierarchy[] hiers; 43 44 private boolean[] containsUF; 48 private List [] ufMemberLists; protected TreeNode posTreeRoot = null; 52 private int ordinal; private boolean qubonMode = false; 54 private boolean hierarchizeNeeded = false; 55 56 private int nHierExclude = 0; 64 private int generateMode = 0; 65 private int generateIndex = -1; private Object expGenerate = null; 67 private Collection changeListeners = new ArrayList (); 68 private QuaxUti uti; 69 private Map canExpandMemberMap = new HashMap (); 70 private Map canExpandPosMap = new HashMap (); 71 private Map canCollapseMemberMap = new HashMap (); 72 private Map canCollapsePosMap = new HashMap (); 73 74 79 public Quax(int ordinal) { 80 this.ordinal = ordinal; 81 qubonMode = false; 82 } 83 84 89 public void addChangeListener(QuaxChangeListener listener) { 90 changeListeners.add(listener); 91 } 92 93 98 public void removeChangeListener(QuaxChangeListener listener) { 99 changeListeners.remove(listener); 100 } 101 102 110 public void changed(Object source, boolean changedMemberSet) { 111 for (Iterator iter = changeListeners.iterator(); iter.hasNext();) { 112 QuaxChangeListener listener = (QuaxChangeListener) iter.next(); 113 listener.quaxChanged(this, source, changedMemberSet); 114 } 115 canExpandMemberMap.clear(); 116 canExpandPosMap.clear(); 117 canCollapseMemberMap.clear(); 118 canCollapsePosMap.clear(); 119 120 } 121 122 127 public void init(List positions) { 128 Member[][] aPosMem; 129 int nDimension = 0; 130 hierarchizeNeeded = false; 131 nHierExclude = 0; 132 qubonMode = true; 133 134 if (positions.size() == 0) { 135 aPosMem = new Member[0][0]; 137 setHiers(new Hierarchy[0]); 138 setHiers(hiers); 139 return; 140 } else { 141 nDimension = ((Position) positions.get(0)).getMembers().length; 142 aPosMem = new Member[positions.size()][nDimension]; 143 144 int j = 0; 145 PositionLoop: for (Iterator iter = positions.iterator(); iter.hasNext();) { 146 Position pos = (Position) iter.next(); 147 aPosMem[j++] = pos.getMembers(); 148 } 149 } 150 Hierarchy[] hiers = new Hierarchy[nDimension]; 151 for (int j = 0; j < hiers.length; j++) { 152 Member m = aPosMem[0][j]; 153 hiers[j] = m.getLevel().getHierarchy(); 154 } 155 setHiers(hiers); 156 initPositions(aPosMem); 157 158 posTreeRoot.walkTree(new TreeNodeCallback() { 162 163 166 public int handleTreeNode(TreeNode node) { 167 int iDim = node.getLevel(); 168 169 if (iDim == Quax.this.nDimension) 170 return TreeNodeCallback.BREAK; 172 if (node.getChildren().size() == 1) { 173 return TreeNodeCallback.CONTINUE; } else { 175 Quax.this.qubonMode = false; 177 return TreeNodeCallback.BREAK; 178 } 179 } 180 }); 181 182 if (qubonMode) 183 nHierExclude = nDimension - 1; 185 } 186 187 192 private void initPositions(Member[][] aPosMemStart) { 193 if (aPosMemStart.length == 0) { 195 posTreeRoot = null; 196 return; 197 } 198 199 204 205 posTreeRoot = new TreeNode(null); int iEnd = addToPosTree(aPosMemStart, 0, aPosMemStart.length, 0, posTreeRoot); 208 while (iEnd < aPosMemStart.length) { 209 iEnd = addToPosTree(aPosMemStart, iEnd, aPosMemStart.length, 0, posTreeRoot); 210 } 211 212 posTreeRoot.walkTree(new TreeNodeCallback() { 214 215 218 public int handleTreeNode(TreeNode node) { 219 int iDim1 = node.getLevel(); 220 221 if (iDim1 == Quax.this.nDimension - 1) { 222 if (node.getChildren().size() <= 1) 223 return TreeNodeCallback.CONTINUE_SIBLING; Object [] memArray = new Object [node.getChildren().size()]; 229 int i = 0; 230 for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { 231 TreeNode child = (TreeNode) iter.next(); 232 memArray[i++] = child.getReference(); 233 } 234 node.getChildren().clear(); 235 Object oFun = uti.createFunCall("{}", memArray, QuaxUti.FUNTYPE_BRACES); 236 TreeNode newChild = new TreeNode(oFun); 237 node.addChildNode(newChild); 238 return TreeNodeCallback.CONTINUE_SIBLING; } 241 return TreeNodeCallback.CONTINUE; 242 } 243 }); 244 245 containsUF = new boolean[nDimension]; ufMemberLists = new List [nDimension]; 247 248 if (logger.isDebugEnabled()) 249 logger.debug("after initPositions " + this.toString()); 250 } 251 252 267 protected int addToPosTree(Member[][] aPosMem, int iStartPos, int iEndPos, int iDim, 268 TreeNode parentNode) { 269 Member currentOfDim = aPosMem[iStartPos][iDim]; 270 Object o = uti.objForMember(currentOfDim); 271 TreeNode newNode = new TreeNode(o); 272 parentNode.addChildNode(newNode); 273 274 int iEndRange = iStartPos + 1; 276 for (; iEndRange < iEndPos; iEndRange++) { 277 if (aPosMem[iEndRange][iDim] != aPosMem[iStartPos][iDim]) 278 break; 279 } 280 int nextDim = iDim + 1; 281 if (nextDim < nDimension) { 282 int iEndChild = addToPosTree(aPosMem, iStartPos, iEndRange, nextDim, newNode); 283 while (iEndChild < iEndRange) { 284 iEndChild = addToPosTree(aPosMem, iEndChild, iEndRange, nextDim, newNode); 285 } 286 } 287 return iEndRange; 288 } 289 290 296 public int dimIdx(Dimension dim) { 297 if (hiers == null || hiers.length == 0) 298 return -1; for (int i = 0; i < hiers.length; i++) { 300 if (hiers[i].getDimension().equals(dim)) 301 return i; 302 } 303 return -1; 304 } 305 306 312 public void regeneratePosTree(Object [] sets, boolean hiersChanged) { 313 if (hiersChanged) { 314 nDimension = sets.length; 315 hiers = new Hierarchy[nDimension]; 316 for (int i = 0; i < nDimension; i++) { 317 try { 318 hiers[i] = uti.hierForExp(sets[i]); 319 } catch (CannotHandleException e) { 320 logger.fatal("could not determine Hierarchy for set"); 321 logger.fatal(e); 322 throw new IllegalArgumentException (e.getMessage()); 323 } 324 } 325 326 containsUF = new boolean[nDimension]; ufMemberLists = new List [nDimension]; 328 generateIndex = 0; 329 generateMode = 0; 330 } 331 if (posTreeRoot == null) 332 return; 333 posTreeRoot.getChildren().clear(); 334 TreeNode current = posTreeRoot; 335 nHierExclude = 0; 341 int nChildrenFound = 0; 342 boolean childrenFound = false; 343 for (int i = 0; i < nDimension; i++) { 344 TreeNode newNode; 345 if (sets[i] instanceof SetExp) { 346 SetExp setx = (SetExp) sets[i]; 347 newNode = new TreeNode(setx.getOExp()); 348 int mode = setx.getMode(); 349 if (mode > 0) { 350 generateMode = mode; 351 generateIndex = i; 352 expGenerate = setx.getOExp(); 353 } 354 } else { 355 boolean bChildrenFound = findChildrenCall(sets[i], 0); 357 if (bChildrenFound) { 358 childrenFound = true; 359 nChildrenFound = i + 1; 360 } 361 362 newNode = new TreeNode(sets[i]); 363 if (generateIndex == i && generateMode == CalcSet.STICKY) { 364 if (!sets[i].equals(expGenerate)) 367 resetGenerate(); 368 } 369 } 370 current.addChildNode(newNode); 371 current = newNode; 372 if (!uti.canHandle(newNode.getReference())) { 373 containsUF[i] = true; 377 } 378 } 379 qubonMode = true; 380 nHierExclude = nDimension - nChildrenFound; 381 382 if (!childrenFound) 383 hierarchizeNeeded = false; 384 } 385 386 389 private boolean findChildrenCall(Object oExp, int level) { 390 if (!uti.isFunCall(oExp)) 391 return false; if (level > 0 && uti.isFunCallTo(oExp, "children")) 393 return true; 394 int nArgs = uti.funCallArgCount(oExp); 395 for (int i = 0; i < nArgs; i++) { 396 if (findChildrenCall(uti.funCallArg(oExp, i), level + 1)) 397 return true; 398 } 399 return false; 400 } 401 402 406 412 public boolean canExpand(Member[] pathMembers) { 413 int iDim = pathMembers.length - 1; 414 415 if (!allowNavigate(iDim, false)) 418 return false; 419 420 List li = Arrays.asList(pathMembers); 422 if (canExpandPosMap.containsKey(li)) { 423 Boolean bCanExpand = (Boolean ) canExpandPosMap.get(li); 424 return bCanExpand.booleanValue(); 425 } 426 427 boolean childFound = checkChildPosition(pathMembers); 430 431 Boolean bool = new Boolean (!childFound); 433 canExpandPosMap.put(li, bool); 434 435 return !childFound; 436 } 437 438 443 public void expand(Member[] mPath) { 444 445 if (qubonMode) { 446 resolveUnions(); 447 if (logger.isDebugEnabled()) { 448 logger.debug("expand after resolveUnions " + this.toString()); 449 } 450 } 451 452 int iDim = mPath.length - 1; 453 454 466 TreeNode bestNode = findBestNode(mPath); 467 int bestNodeIndex = bestNode.getLevel() - 1; 468 469 481 List tailNodeList; 482 if (mPath.length < nDimension) { 483 tailNodeList = collectTailNodes(posTreeRoot, mPath); 484 } else { 485 tailNodeList = Collections.EMPTY_LIST; 486 } 487 488 TreeNode newNode; 489 Object oMember = uti.objForMember(mPath[iDim]); 490 Object fChildren = uti.createFunCall("Children", new Object [] { oMember}, 491 QuaxUti.FUNTYPE_PROPERTY); 492 TreeNode parent = bestNode; 493 494 if (bestNodeIndex == iDim) { 499 parent = bestNode.getParent(); 500 } else { 501 for (int i = bestNodeIndex + 1; i < mPath.length - 1; i++) { 502 oMember = uti.objForMember(mPath[i]); 503 newNode = new TreeNode(oMember); 504 parent.addChildNode(newNode); 505 parent = newNode; 506 } 507 } 508 509 int n = nDimension - iDim - 1; 512 if (n < nHierExclude) 513 nHierExclude = n; 514 515 newNode = new TreeNode(fChildren); 516 parent.addChildNode(newNode); 517 if (mPath.length < nDimension) { 518 for (Iterator iter = tailNodeList.iterator(); iter.hasNext();) { 519 TreeNode tailNode = (TreeNode) iter.next(); 520 newNode.addChildNode(tailNode.deepCopy()); 521 } 522 } 523 524 if (logger.isDebugEnabled()) { 525 logger.debug("after expand " + this.toString()); 526 } 527 528 qubonMode = false; 529 hierarchizeNeeded = true; 530 changed(this, false); 531 } 532 533 539 public boolean canExpand(Member member) { 540 541 if (!allowNavigate(member, false)) 544 return false; 545 546 if (canExpandMemberMap.containsKey(member)) { 548 Boolean bCanExpand = (Boolean ) canExpandMemberMap.get(member); 549 return bCanExpand.booleanValue(); 550 } 551 552 boolean b = !findMemberChild(member); 555 556 Boolean bool = new Boolean (b); 558 canExpandMemberMap.put(member, bool); 559 560 return b; 561 } 562 563 568 public void expand(final Member member) { 569 570 if (qubonMode) { 571 resolveUnions(); 572 if (logger.isDebugEnabled()) { 573 logger.debug("expand after resolveUnions " + this.toString()); 574 } 575 } 576 577 nHierExclude = 0; 579 580 final int iDim = this.dimIdx(uti.dimForMember(member)); 581 final List nodesForMember = new ArrayList (); 582 583 posTreeRoot.walkChildren(new TreeNodeCallback() { 587 588 591 public int handleTreeNode(TreeNode node) { 592 int iDimNode = node.getLevel() - 1; 593 if (iDimNode < iDim) 594 return TreeNodeCallback.CONTINUE; 597 Object oExp = node.getReference(); 600 if (uti.isMember(oExp)) { 601 if (uti.equalMember(oExp, member)) 602 nodesForMember.add(node); 603 } else { 604 if (isMemberInFunCall(oExp, member, iDim)) 606 nodesForMember.add(node); 607 } 608 return TreeNodeCallback.CONTINUE_SIBLING; } 611 }); 612 613 Object oMember = uti.objForMember(member); 615 Object fChildren = uti.createFunCall("Children", new Object [] { oMember}, 616 QuaxUti.FUNTYPE_PROPERTY); 617 for (Iterator iter = nodesForMember.iterator(); iter.hasNext();) { 618 TreeNode node = (TreeNode) iter.next(); 619 TreeNode newNode = new TreeNode(fChildren); 620 for (Iterator iterator = node.getChildren().iterator(); iterator.hasNext();) { 621 TreeNode child = (TreeNode) iterator.next(); 622 newNode.addChildNode(child.deepCopy()); 623 } 624 TreeNode parent = node.getParent(); 625 parent.addChildNode(newNode); 626 } 627 628 if (logger.isDebugEnabled()) { 629 logger.debug("after expand member " + this.toString()); 630 } 631 632 hierarchizeNeeded = true; 633 changed(this, false); 634 } 635 636 640 646 public boolean canCollapse(Member[] pathMembers) { 647 648 int iDim = pathMembers.length - 1; 649 650 if (!allowNavigate(iDim, false)) 653 return false; 654 655 List li = Arrays.asList(pathMembers); 657 if (canCollapsePosMap.containsKey(li)) { 658 Boolean bCanCollapse = (Boolean ) canCollapsePosMap.get(li); 659 return bCanCollapse.booleanValue(); 660 } 661 662 boolean childFound = checkChildPosition(pathMembers); 665 666 Boolean bool = new Boolean (childFound); 668 canCollapsePosMap.put(li, bool); 669 670 return childFound; 671 } 672 673 679 public void collapse(final Member[] mPath) { 680 681 if (qubonMode) { 682 resolveUnions(); 683 if (logger.isDebugEnabled()) { 684 logger.debug("collapse after resolveUnions " + this.toString()); 685 } 686 } 687 688 final int iDim = mPath.length - 1; 689 690 final List [] splitLists = new List [mPath.length]; 692 for (int i = 0; i < splitLists.length; i++) { 693 splitLists[i] = new ArrayList (); 694 } 695 696 posTreeRoot.walkChildren(new TreeNodeCallback() { 697 698 703 public int handleTreeNode(TreeNode node) { 704 Object oExp = node.getReference(); 706 int idi = node.getLevel() - 1; 707 if (idi < iDim) { 708 if (uti.isMember(oExp)) { 709 if (uti.equalMember(oExp, mPath[idi])) 710 return TreeNodeCallback.CONTINUE; 711 else 712 return TreeNodeCallback.CONTINUE_SIBLING; 713 } else { 714 if (isMemberInFunCall(oExp, mPath[idi], idi)) 716 return TreeNodeCallback.CONTINUE; 717 else 718 return TreeNodeCallback.CONTINUE_SIBLING; 719 } 720 } 721 boolean found = false; 724 if (uti.isMember(oExp)) { 725 if (uti.checkDescendantO(mPath[iDim], oExp)) { 727 found = true; 728 } 729 } else { 730 if (isChildOfMemberInFunCall(oExp, mPath[iDim], iDim)) 732 found = true; 733 } 734 735 if (found) { 736 int level = node.getLevel(); 739 TreeNode currentNode = node; 740 while (level > 0) { 741 Object o = currentNode.getReference(); 742 if (!uti.isMember(o)) { 743 if (!splitLists[level - 1].contains(currentNode)) 745 splitLists[level - 1].add(currentNode); 746 } 747 currentNode = currentNode.getParent(); 748 level = currentNode.getLevel(); 749 } 750 } 751 return TreeNodeCallback.CONTINUE_SIBLING; 752 } }); 754 755 for (int i = splitLists.length - 1; i >= 0; i--) { 758 for (Iterator iter = splitLists[i].iterator(); iter.hasNext();) { 759 TreeNode n = (TreeNode) iter.next(); 760 splitFunCall(n, mPath[i], i); 761 } 762 } 763 764 final List removeList = new ArrayList (); 767 posTreeRoot.walkChildren(new TreeNodeCallback() { 768 771 public int handleTreeNode(TreeNode node) { 772 Object oExp = node.getReference(); 774 int idi = node.getLevel() - 1; 775 if (idi < iDim) { 776 if (uti.isMember(oExp)) { 777 if (uti.equalMember(oExp, mPath[idi])) 778 return TreeNodeCallback.CONTINUE; 779 else 780 return TreeNodeCallback.CONTINUE_SIBLING; 781 } else { 782 return TreeNodeCallback.CONTINUE_SIBLING; 785 } 786 } else if (idi == iDim) { 787 if (!uti.isMember(oExp)) { 789 if (uti.isFunCallTo(oExp, "Children")) { 791 Object oMember = uti.funCallArg(oExp, 0); 792 if (uti.objForMember(mPath[iDim]).equals(oMember) 793 || uti.checkDescendantO(mPath[iDim], oMember)) 794 removeList.add(node); } else if (uti.isFunCallTo(oExp, "{}")) { 796 int nArgs = uti.funCallArgCount(oExp); 801 List removeMembers = new ArrayList (); 802 for (int i = 0; i < nArgs; i++) { 803 Object oSetMember = uti.funCallArg(oExp, i); 804 if (uti.checkDescendantO(mPath[iDim], oSetMember)) { 805 removeMembers.add(oSetMember); 806 } 807 } 808 int nRemove = removeMembers.size(); 809 if (nRemove == nArgs) { 810 removeList.add(node); } else if (nRemove > 0) { 813 Object [] remaining = new Object [nArgs - nRemove]; 815 int j = 0; 816 for (int i = 0; i < nArgs; i++) { 817 Object oSetMember = uti.funCallArg(oExp, i); 818 if (!removeMembers.contains(oSetMember)) 819 remaining[j++] = oSetMember; 820 } 821 if (remaining.length == 1) { 822 node.setReference(remaining[0]); } else { 825 Object newSet = uti.createFunCall("{}", remaining, QuaxUti.FUNTYPE_BRACES); 826 node.setReference(newSet); 827 } 828 } 829 830 } else if (uti.isFunCallTo(oExp, "Union")) { 831 Object oRemain = removeDescendantsFromFunCall(oExp, mPath[iDim], iDim); 833 if (oRemain == null) 834 removeList.add(node); 835 else 836 node.setReference(oRemain); 837 } 838 return TreeNodeCallback.CONTINUE_SIBLING; 839 840 } else if (uti.isMember(oExp)) { 841 if (uti.checkDescendantO(mPath[iDim], oExp)) 842 removeList.add(node); 843 } 844 return TreeNodeCallback.CONTINUE_SIBLING; 845 } else { 847 logger.error("unexpected tree node level " + idi + " " + uti.memberString(mPath)); 849 } 850 return TreeNodeCallback.BREAK; 851 } }); 853 854 for (Iterator iter = removeList.iterator(); iter.hasNext();) { 856 TreeNode nodeToRemove = (TreeNode) iter.next(); 857 removePathToNode(nodeToRemove); 858 } 859 860 int n = nDimension - iDim - 1; 863 if (n < nHierExclude) 864 nHierExclude = n; 865 866 if (logger.isDebugEnabled()) { 867 logger.debug("after collapse " + this.toString()); 868 } 869 870 changed(this, false); 871 } 873 879 public boolean canCollapse(Member member) { 880 881 if (!allowNavigate(member, false)) 884 return false; 885 886 if (canCollapseMemberMap.containsKey(member)) { 888 Boolean bCanCollapse = (Boolean ) canCollapseMemberMap.get(member); 889 return bCanCollapse.booleanValue(); 890 } 891 892 boolean b = findMemberChild(member); 895 896 Boolean bool = new Boolean (b); 898 canCollapseMemberMap.put(member, bool); 899 900 return b; 901 } 902 903 909 public void collapse(final Member member) { 910 911 if (qubonMode) { 912 resolveUnions(); 913 if (logger.isDebugEnabled()) { 914 logger.debug("collapse member after resolveUnions " + this.toString()); 915 } 916 } 917 918 final int iDim = this.dimIdx(uti.dimForMember(member)); 919 920 final List nodesForMember = new ArrayList (); 921 922 posTreeRoot.walkChildren(new TreeNodeCallback() { 926 927 930 public int handleTreeNode(TreeNode node) { 931 int iDimNode = node.getLevel() - 1; 932 if (iDimNode < iDim) 933 return TreeNodeCallback.CONTINUE; 936 Object oExp = node.getReference(); 939 if (uti.isMember(oExp)) { 940 if (uti.checkDescendantO(member, oExp)) 941 nodesForMember.add(node); 942 } else { 943 945 if (isDescendantOfMemberInFunCall(oExp, member, iDimNode)) 946 nodesForMember.add(node); 947 } 948 return TreeNodeCallback.CONTINUE_SIBLING; } 951 }); 952 953 for (Iterator iter = nodesForMember.iterator(); iter.hasNext();) { 954 TreeNode node = (TreeNode) iter.next(); 955 Object oExp = node.getReference(); 956 if (uti.isMember(oExp)) { 957 removePathToNode(node); 958 } else { 959 Object oComplement = removeDescendantsFromFunCall(oExp, member, iDim); 961 if (oComplement == null) 962 removePathToNode(node); 963 else 964 node.setReference(oComplement); } 966 } 967 if (logger.isDebugEnabled()) { 968 logger.debug("after collapse " + this.toString()); 969 } 970 971 changed(this, false); 972 } 974 978 981 public boolean canDrillDown(Member member) { 982 return allowNavigate(member, true); 983 } 984 985 991 public void drillDown(Member member) { 992 final int iDim = this.dimIdx(uti.dimForMember(member)); 993 994 Object [] sets = new Object [nDimension]; 996 Object oMember = uti.objForMember(member); 997 Object fChildren = uti.createFunCall("Children", new Object [] { oMember}, 998 QuaxUti.FUNTYPE_PROPERTY); 999 DimensionLoop: for (int i = 0; i < nDimension; i++) { 1000 if (i == iDim) { 1001 sets[i] = fChildren; 1003 } else { 1004 sets[i] = genExpForDim(i); 1006 } 1007 } 1009 regeneratePosTree(sets, false); 1011 1012 changed(this, false); 1013 } 1014 1015 1019 1023 public boolean canDrillUp(Hierarchy hier) { 1024 final int iDim = this.dimIdx(hier.getDimension()); 1025 1026 if (!allowNavigate(iDim, true)) 1027 return false; 1028 1029 int ret = posTreeRoot.walkChildren(new TreeNodeCallback() { 1030 1031 1034 public int handleTreeNode(TreeNode node) { 1035 int iDimNode = node.getLevel() - 1; 1036 if (iDimNode < iDim) 1037 return TreeNodeCallback.CONTINUE; 1038 Object oExp = node.getReference(); 1040 if (!uti.isMember(oExp)) { 1041 if (isFunCallNotTopLevel(oExp, iDimNode)) 1043 return TreeNodeCallback.BREAK; else 1045 return TreeNodeCallback.CONTINUE_SIBLING; 1046 } else { 1047 1049 if (uti.levelDepthForMember(oExp) > 0) 1050 return TreeNodeCallback.BREAK; else 1052 return TreeNodeCallback.CONTINUE_SIBLING; 1053 } 1055 } }); 1057 1058 return (ret == TreeNodeCallback.BREAK); 1059 } 1060 1061 1067 public void drillUp(Hierarchy hier) { 1068 1069 int iDim = dimIdx(hier.getDimension()); 1070 1071 Object [] sets = new Object [nDimension]; 1073 1074 DimensionLoop: for (int i = 0; i < nDimension; i++) { 1075 if (i == iDim) { 1076 sets[i] = drillupExp(iDim, hier); 1078 } else { 1079 sets[i] = genExpForDim(i); 1080 } 1081 } 1083 regeneratePosTree(sets, false); 1085 1086 changed(this, false); 1087 } 1088 1089 1093 1099 public Object genExp(boolean genHierarchize) { 1100 1101 if (generateMode > 0 && generateIndex > 0) 1102 return genGenerateExp(genHierarchize); 1103 else 1104 return genNormalExp(genHierarchize); 1105 } 1106 1107 1112 private Object genNormalExp(boolean genHierarchize) { 1113 1114 ExpGenerator expGenerator = new ExpGenerator(uti); 1115 1116 if (!genHierarchize) { 1117 expGenerator.init(posTreeRoot, hiers); 1119 Object exp = expGenerator.genExp(); 1120 return exp; 1121 } 1122 1123 1126 if (nHierExclude == 0) { 1127 expGenerator.init(posTreeRoot, hiers); 1129 Object exp = expGenerator.genExp(); 1130 Object eHier = uti 1132 .createFunCall("Hierarchize", new Object [] { exp}, QuaxUti.FUNTYPE_FUNCTION); 1133 return eHier; 1134 } 1135 1136 1142 return genLeftRight(expGenerator, nDimension - nHierExclude, nHierExclude); 1143 } 1144 1145 1150 private Object genLeftRight(ExpGenerator expGenerator, int nLeft, int nRight) { 1151 Object leftExp = null; 1153 if (nLeft > 0) { 1154 TreeNode leftRoot = posTreeRoot.deepCopyPrune(nLeft); 1155 leftRoot.setReference(null); 1156 Hierarchy[] leftHiers = new Hierarchy[nLeft]; 1157 for (int i = 0; i < leftHiers.length; i++) { 1158 leftHiers[i] = hiers[i]; 1159 } 1160 expGenerator.init(leftRoot, leftHiers); 1161 leftExp = expGenerator.genExp(); 1162 leftExp = uti.createFunCall("Hierarchize", new Object [] { leftExp}, QuaxUti.FUNTYPE_FUNCTION); 1163 } 1164 1165 Object rightExp = null; 1167 Hierarchy[] rightHiers = new Hierarchy[nRight]; 1168 for (int i = 0; i < nRight; i++) { 1169 rightHiers[i] = hiers[nLeft + i]; 1170 } 1171 1172 TreeNode rightRoot = new TreeNode(null); 1177 TreeNode current = posTreeRoot; 1178 for (int i = 0; i < nLeft; i++) { 1179 List list = current.getChildren(); 1180 current = (TreeNode) list.get(0); 1181 } 1182 List list = current.getChildren(); 1183 for (Iterator iter = list.iterator(); iter.hasNext();) { 1184 TreeNode node = (TreeNode) iter.next(); 1185 TreeNode cnode = node.deepCopy(); 1186 rightRoot.addChildNode(cnode); 1187 } 1188 1189 expGenerator.init(rightRoot, rightHiers); 1190 rightExp = expGenerator.genExp(); 1191 1192 if (leftExp == null) 1193 return rightExp; 1194 1195 Object exp = uti.createFunCall("CrossJoin", new Object [] { leftExp, rightExp}, 1196 QuaxUti.FUNTYPE_FUNCTION); 1197 1198 return exp; 1199 } 1200 1201 1206 private Object genGenerateExp(boolean genHierarchize) { 1207 1208 ExpGenerator expGenerator = new ExpGenerator(uti); 1209 1210 if (nDimension - generateIndex > nHierExclude) 1215 logger.warn("unexpected values: nHierExclude=" + nHierExclude + " generateIndex=" 1216 + generateIndex); 1217 1218 1235 Object leftExp = null; 1236 if (genHierarchize && nHierExclude > nDimension - generateIndex && nHierExclude < nDimension) { 1241 int nLeft = nDimension - nHierExclude; 1242 int nRight = generateIndex - nLeft; 1243 leftExp = genLeftRight(expGenerator, nLeft, nRight); 1244 } else { 1245 TreeNode leftRoot = posTreeRoot.deepCopyPrune(generateIndex); 1246 leftRoot.setReference(null); 1247 Hierarchy[] leftHiers = new Hierarchy[generateIndex]; 1248 for (int i = 0; i < leftHiers.length; i++) { 1249 leftHiers[i] = hiers[i]; 1250 } 1251 expGenerator.init(leftRoot, leftHiers); 1252 leftExp = expGenerator.genExp(); 1253 if (genHierarchize) 1254 leftExp = uti.createFunCall("Hierarchize", new Object [] { leftExp}, 1255 QuaxUti.FUNTYPE_FUNCTION); 1256 } 1257 1258 TreeNode topCountNode = posTreeRoot; 1260 for (int i = 0; i <= generateIndex; i++) { 1262 List children = topCountNode.getChildren(); 1264 topCountNode = (TreeNode) children.get(0); 1265 } 1266 Object topcount = topCountNode.getReference(); 1267 Object origTopcountSet = uti.funCallArg(topcount, 0); 1269 Object currentMembersTuple = genCurrentTuple(); 1271 Object ocj = uti.createFunCall("Crossjoin", 1272 new Object [] { currentMembersTuple, origTopcountSet}, QuaxUti.FUNTYPE_FUNCTION); 1273 String fun = uti.funCallName(topcount); 1275 int n = uti.funCallArgCount(topcount); 1276 Object [] args = new Object [n]; 1277 for (int i = 1; i < n; i++) { 1278 args[i] = uti.funCallArg(topcount, i); 1279 } 1280 args[0] = ocj; 1281 Object newTopcount = uti.createFunCall(fun, args, QuaxUti.FUNTYPE_FUNCTION); 1282 Object oGenerate = uti.createFunCall("Generate", new Object [] { leftExp, newTopcount}, 1283 QuaxUti.FUNTYPE_FUNCTION); 1284 1285 if (generateIndex + 1 == nDimension) 1286 return oGenerate; 1287 1288 int nRight = nDimension - generateIndex - 1; 1291 Hierarchy[] rightHiers = new Hierarchy[nRight]; 1292 for (int i = 1; i <= nRight; i++) { 1293 rightHiers[nRight - i] = hiers[nDimension - i]; 1294 } 1295 TreeNode root = new TreeNode(null); 1296 List list = topCountNode.getChildren(); 1297 for (Iterator iter = list.iterator(); iter.hasNext();) { 1298 TreeNode node = (TreeNode) iter.next(); 1299 root.addChildNode(node.deepCopy()); 1300 } 1301 expGenerator.init(root, rightHiers); 1302 Object rightExp = expGenerator.genExp(); 1303 1304 Object exp = uti.createFunCall("CrossJoin", new Object [] { oGenerate, rightExp}, 1305 QuaxUti.FUNTYPE_FUNCTION); 1306 return exp; 1307 } 1308 1309 1313 1318 private Object genCurrentTuple() { 1319 Object [] currentsOfDim = new Object [generateIndex]; 1320 for (int i = 0; i < currentsOfDim.length; i++) { 1321 Dimension dim = hiers[i].getDimension(); 1322 currentsOfDim[i] = uti.createFunCall("CurrentMember", new Object [] { uti.objForDim(dim)}, 1323 QuaxUti.FUNTYPE_PROPERTY); 1324 } 1325 Object oTuple; 1326 if (generateIndex > 1) 1327 oTuple = uti.createFunCall("()", currentsOfDim, QuaxUti.FUNTYPE_TUPLE); 1328 else 1329 oTuple = currentsOfDim[0]; Object oSet = uti.createFunCall("{}", new Object [] { oTuple}, QuaxUti.FUNTYPE_BRACES); 1332 return oSet; 1333 } 1334 1335 1338 private boolean checkChildPosition(final Member[] mPath) { 1339 1340 int ret = posTreeRoot.walkChildren(new TreeNodeCallback() { 1341 1342 1345 public int handleTreeNode(TreeNode node) { 1346 int iDim = mPath.length - 1; 1347 int iDimNode = node.getLevel() - 1; 1348 Object oExp = node.getReference(); 1349 if (iDimNode < iDim) { 1350 if (uti.isMember(oExp)) { 1352 if (uti.equalMember(oExp, mPath[iDimNode])) 1353 return TreeNodeCallback.CONTINUE; 1354 else 1355 return TreeNodeCallback.CONTINUE_SIBLING; } else { 1359 if (isMemberInFunCall(oExp, mPath[iDimNode], iDimNode)) 1361 return TreeNodeCallback.CONTINUE; 1362 else 1363 return TreeNodeCallback.CONTINUE_SIBLING; } 1367 } 1368 1369 if (uti.isMember(oExp)) { 1372 if (uti.checkParent(mPath[iDimNode], oExp)) 1373 return TreeNodeCallback.BREAK; else 1375 return TreeNodeCallback.CONTINUE_SIBLING; } else { 1379 if (isChildOfMemberInFunCall(oExp, mPath[iDimNode], iDimNode)) 1381 return TreeNodeCallback.BREAK; else 1383 return TreeNodeCallback.CONTINUE_SIBLING; } 1387 } 1388 }); 1389 1390 if (ret == TreeNodeCallback.BREAK) 1391 return true; else 1393 return false; 1394 } 1396 1399 private void resolveUnions() { 1400 final List [] setLists = new List [nDimension]; 1401 for (int i = 0; i < setLists.length; i++) { 1402 setLists[i] = new ArrayList (); 1403 } 1404 posTreeRoot.walkChildren(new TreeNodeCallback() { 1405 1406 1409 public int handleTreeNode(TreeNode node) { 1410 int iDimNode = node.getLevel() - 1; 1411 Object oExp = node.getReference(); 1412 if (!uti.isMember(oExp)) { 1413 funToList(oExp, setLists[iDimNode]); 1415 } else { 1416 setLists[iDimNode].add(oExp); 1418 } 1419 return TreeNodeCallback.CONTINUE; 1420 } }); 1422 1423 posTreeRoot = new TreeNode(null); 1425 crossJoinTree(setLists, posTreeRoot, 0); 1426 1427 qubonMode = false; 1428 } 1429 1430 1433 private TreeNode findBestNode(final Member[] mPath) { 1434 final TreeNode[] bestNode = new TreeNode[1]; 1435 bestNode[0] = posTreeRoot; 1436 posTreeRoot.walkChildren(new TreeNodeCallback() { 1437 1438 1441 public int handleTreeNode(TreeNode node) { 1442 int iDim = mPath.length - 1; 1443 int iDimNode = node.getLevel() - 1; 1444 Object oExp = node.getReference(); 1445 if (!uti.isMember(oExp)) 1446 return TreeNodeCallback.CONTINUE_SIBLING; if (uti.equalMember(oExp, mPath[iDimNode])) { 1449 if (iDimNode == iDim) { 1451 bestNode[0] = node; 1453 return TreeNodeCallback.BREAK; 1454 } else { 1455 bestNode[0] = node; 1457 return TreeNodeCallback.CONTINUE; 1458 } 1459 } else { 1460 return TreeNodeCallback.CONTINUE_SIBLING; } 1464 } 1465 }); 1466 1467 return bestNode[0]; 1468 } 1469 1470 1473 private List collectTailNodes(TreeNode startNode, final Member[] mPath) { 1474 1475 final List tailNodes = new ArrayList (); 1476 startNode.walkChildren(new TreeNodeCallback() { 1477 1478 1481 public int handleTreeNode(TreeNode node) { 1482 int iDim = mPath.length - 1; 1483 int iDimNode = node.getLevel() - 1; 1484 Object oExp = node.getReference(); 1485 boolean match = false; 1486 if (uti.isMember(oExp)) { 1487 if (uti.equalMember(oExp, mPath[iDimNode])) 1489 match = true; 1490 } else { 1491 if (isMemberInFunCall(oExp, mPath[iDimNode], iDimNode)) 1493 match = true; 1494 } 1495 1496 if (match) { 1497 if (iDimNode == iDim) { 1498 tailNodes.addAll(node.getChildren()); 1500 return TreeNodeCallback.CONTINUE_SIBLING; 1501 } else { 1502 return TreeNodeCallback.CONTINUE; 1504 } 1505 } else 1506 return TreeNodeCallback.CONTINUE_SIBLING; 1510 } }); 1512 1513 return tailNodes; 1514 } 1515 1516 private boolean findMemberChild(final Member member) { 1517 1518 final int iDim = this.dimIdx(uti.dimForMember(member)); 1519 1520 int ret = posTreeRoot.walkChildren(new TreeNodeCallback() { 1521 1522 1525 public int handleTreeNode(TreeNode node) { 1526 int iDimNode = node.getLevel() - 1; 1527 if (iDimNode < iDim) 1528 return TreeNodeCallback.CONTINUE; 1531 Object oExp = node.getReference(); 1534 if (uti.isMember(oExp)) { 1535 if (uti.checkParent(member, oExp)) 1536 return TreeNodeCallback.BREAK; } else { 1538 if (isChildOfMemberInFunCall(oExp, member, iDimNode)) 1540 return TreeNodeCallback.BREAK; } 1542 return TreeNodeCallback.CONTINUE_SIBLING; } 1545 }); 1546 1547 return (ret == TreeNodeCallback.BREAK); 1548 } 1549 1550 1553 public String toString() { 1554 final StringBuffer sbPosTree = new StringBuffer (); 1555 sbPosTree.append("number of hierarchies excluded from HIEARARCHIZE=" + nHierExclude); 1556 sbPosTree.append('\n'); 1557 if (posTreeRoot == null) { 1558 sbPosTree.append("Root=null"); 1559 return sbPosTree.toString(); 1560 } 1561 posTreeRoot.walkChildren(new TreeNodeCallback() { 1562 1563 1566 public int handleTreeNode(TreeNode node) { 1567 int iDimNode = node.getLevel() - 1; 1568 sbPosTree.append("\n"); 1569 for (int i = 0; i < iDimNode - 1; i++) { 1570 sbPosTree.append(" "); 1571 } 1572 if (iDimNode > 0) { 1573 sbPosTree.append("+--"); 1574 } 1575 1576 Object oExp = node.getReference(); 1577 if (!uti.isMember(oExp)) { 1578 sbPosTree.append(uti.funString(oExp)); 1580 } else { 1581 sbPosTree.append(uti.getMemberUniqueName(oExp)); 1583 } 1584 return TreeNodeCallback.CONTINUE; 1585 } }); 1587 return sbPosTree.toString(); 1588 } 1589 1590 1596 private void crossJoinTree(List [] setLists, TreeNode currentNode, int iDim) { 1597 for (Iterator iter = setLists[iDim].iterator(); iter.hasNext();) { 1598 Object oExp = iter.next(); 1599 TreeNode newNode = new TreeNode(oExp); 1600 if (iDim < nDimension - 1) 1601 crossJoinTree(setLists, newNode, iDim + 1); 1602 currentNode.addChildNode(newNode); 1603 } 1604 } 1605 1606 1609 private void splitFunCall(TreeNode nFunCall, Member member, int iHier) { 1610 1611 Object oExp = nFunCall.getReference(); 1612 1613 if (!isMemberInFunCall(oExp, member, nFunCall.getLevel() - 1)) 1617 return; Object oComplement = createComplement(oExp, member, iHier); if (oComplement == null) { 1620 nFunCall.setReference(uti.objForMember(member)); 1623 return; 1625 } 1626 1627 TreeNode newNodeComplement = new TreeNode(oComplement); 1629 TreeNode newNodeMember = new TreeNode(uti.objForMember(member)); 1630 for (Iterator iter = nFunCall.getChildren().iterator(); iter.hasNext();) { 1632 TreeNode nChild = (TreeNode) iter.next(); 1633 newNodeComplement.addChildNode(nChild.deepCopy()); 1634 newNodeMember.addChildNode(nChild.deepCopy()); 1635 } 1636 1637 TreeNode nInsert = nFunCall.getParent(); 1638 nFunCall.remove(); 1639 nInsert.addChildNode(newNodeComplement); 1640 nInsert.addChildNode(newNodeMember); 1641 } 1643 1648 private void removePathToNode(TreeNode nodeToRemove) { 1649 if (nodeToRemove.getParent().getChildren().size() > 1) { 1650 nodeToRemove.remove(); 1652 } else { 1653 TreeNode parent = nodeToRemove.getParent(); 1655 while (parent.getParent().getChildren().size() == 1) { 1656 parent = parent.getParent(); 1657 } 1658 if (parent.getLevel() > 0) parent.remove(); 1660 } 1661 } 1662 1663 1669 public Object genExpForDim(int iDimension) { 1670 if (generateIndex >= 0 && generateIndex == iDimension && generateMode > CalcSet.SIMPLE) { 1672 TreeNode topCountNode = (TreeNode) posTreeRoot.getChildren().get(0); 1673 for (int i = 0; i < generateIndex; i++) { 1674 List children = topCountNode.getChildren(); 1677 topCountNode = (TreeNode) children.get(0); 1678 } 1679 Object topcount = topCountNode.getReference(); 1680 SetExp setexp = new SetExp(generateMode, topcount, hiers[iDimension]); 1681 return setexp; 1682 } 1683 List funCallList = collectFunCalls(iDimension); 1684 List memberList = collectMembers(iDimension); 1685 cleanupMemberList(funCallList, memberList, iDimension); 1686 1687 if (funCallList.size() == 0 && memberList.size() == 1) 1688 return memberList.get(0); 1690 Object mSet = null; 1691 if (memberList.size() > 0) { 1692 Object [] aExp = memberList.toArray(new Object [0]); 1693 mSet = uti.createFunCall("{}", aExp, QuaxUti.FUNTYPE_BRACES); 1694 } 1695 if (funCallList.size() == 0) 1696 return mSet; 1697 1698 if (funCallList.size() == 1 && mSet == null) 1699 return funCallList.get(0); 1700 1701 Object set; 1702 int start; 1703 if (mSet != null) { 1704 set = mSet; 1705 start = 0; 1706 } else { 1707 set = funCallList.get(0); 1708 start = 1; 1709 } 1710 for (int j = start; j < funCallList.size(); j++) { 1711 set = uti.createFunCall("Union", new Object [] { set, funCallList.get(j)}, 1712 QuaxUti.FUNTYPE_FUNCTION); 1713 } 1714 return set; 1715 } 1716 1717 1724 private Object drillupExp(int iDim, Hierarchy hier) { 1725 1726 1735 final int[] maxLevel = new int[1]; 1736 maxLevel[0] = 0; 1737 1738 List drillupList = collectDrillup(iDim, maxLevel); 1739 Object expForHier = null; 1740 if (maxLevel[0] == 0) { 1741 expForHier = uti.topLevelMembers(hier, false); 1745 } else { 1746 if (drillupList.size() == 1) { 1747 expForHier = drillupList.get(0); 1748 } else { 1749 for (Iterator iter = drillupList.iterator(); iter.hasNext();) { 1751 Object oExp = iter.next(); 1752 if (expForHier == null) 1753 expForHier = oExp; 1754 else { 1755 expForHier = uti.createFunCall("Union", new Object [] { expForHier, oExp}, 1756 QuaxUti.FUNTYPE_FUNCTION); 1757 } 1758 } 1759 } 1760 } 1761 return expForHier; 1762 } 1763 1764 1769 private List collectDrillup(final int iDim, final int[] maxLevel) { 1770 final List drillupList = new ArrayList (); 1771 posTreeRoot.walkChildren(new TreeNodeCallback() { 1772 1773 1776 public int handleTreeNode(TreeNode node) { 1777 int iDimNode = node.getLevel() - 1; 1778 if (iDimNode < iDim) 1779 return TreeNodeCallback.CONTINUE; 1780 Object oExp = node.getReference(); 1782 if (!uti.isMember(oExp)) { 1783 addFunCallToDrillup(drillupList, oExp, maxLevel); 1785 } else { 1786 Member m = uti.memberForObj(oExp); 1788 uti.addMemberUncles(drillupList, m, maxLevel); 1789 } return TreeNodeCallback.CONTINUE_SIBLING; 1791 } }); 1793 return drillupList; 1794 } 1795 1796 1801 private List collectFunCalls(final int iDim) { 1802 if (posTreeRoot == null) 1803 return Collections.EMPTY_LIST; 1804 final List funCallList = new ArrayList (); 1805 posTreeRoot.walkChildren(new TreeNodeCallback() { 1806 1807 1810 public int handleTreeNode(TreeNode node) { 1811 int iDimNode = node.getLevel() - 1; 1812 if (iDimNode < iDim) 1813 return TreeNodeCallback.CONTINUE; 1814 Object oExp = node.getReference(); 1816 if (!uti.isMember(oExp)) { 1817 String unique = uti.funString(oExp).toString(); 1820 if (!funCallList.contains(unique)) { 1821 funCallList.add(oExp); 1822 funCallList.add(unique); 1823 } 1824 } 1825 return TreeNodeCallback.CONTINUE_SIBLING; 1826 } }); 1828 1829 for (Iterator iter = funCallList.iterator(); iter.hasNext();) { 1831 Object element = iter.next(); 1832 if (element instanceof String ) 1833 iter.remove(); 1834 } 1835 1836 return funCallList; 1837 } 1838 1839 1845 private void cleanupMemberList(List funCallList, List memberList, int iDim) { 1846 if (funCallList.size() > 0 && memberList.size() > 0) { 1847 MemberLoop: for (Iterator itMem = memberList.iterator(); itMem.hasNext();) { 1848 Object oMember = itMem.next(); 1849 Member m = uti.memberForObj(oMember); 1850 for (Iterator itFun = funCallList.iterator(); itFun.hasNext();) { 1851 Object oFun = itFun.next(); 1852 if (isMemberInFunCall(oFun, m, iDim)) { 1853 itMem.remove(); 1854 continue MemberLoop; 1855 } 1856 } 1857 } } 1859 } 1860 1861 1866 List collectMembers(final int iDim) { 1867 if (posTreeRoot == null) 1868 return Collections.EMPTY_LIST; 1869 final List memberList = new ArrayList (); 1870 posTreeRoot.walkChildren(new TreeNodeCallback() { 1871 1872 1875 public int handleTreeNode(TreeNode node) { 1876 int iDimNode = node.getLevel() - 1; 1877 if (iDimNode < iDim) 1878 return TreeNodeCallback.CONTINUE; 1879 Object oExp = node.getReference(); 1881 if (uti.isMember(oExp) && !memberList.contains(oExp)) 1882 memberList.add(oExp); 1883 return TreeNodeCallback.CONTINUE_SIBLING; 1884 } }); 1886 return memberList; 1887 } 1888 1889 1892 private void addFunCallToDrillup(List list, Object oFun, int[] maxLevel) { 1893 if (uti.isFunCallTo(oFun, "Union")) { 1894 for (int i = 0; i < 2; i++) { 1895 Object fExp = uti.funCallArg(oFun, i); 1896 addFunCallToDrillup(list, fExp, maxLevel); 1897 } 1898 } else if (uti.isFunCallTo(oFun, "{}")) { 1899 for (int i = 0; i < uti.funCallArgCount(oFun); i++) { 1901 Object oMember = uti.funCallArg(oFun, i); 1902 Member m = uti.memberForObj(oMember); 1903 uti.addMemberUncles(list, m, maxLevel); 1904 } 1905 } else if (uti.isFunCallTo(oFun, "Children")) { 1906 Object oMember = uti.funCallArg(oFun, 0); 1907 Member m = uti.memberForObj(oMember); 1908 uti.addMemberSiblings(list, m, maxLevel); 1909 } else if (uti.isFunCallTo(oFun, "Descendants")) { 1910 Object oMember = uti.funCallArg(oFun, 0); 1911 Member m = uti.memberForObj(oMember); 1912 Object oLevel = uti.funCallArg(oFun, 1); 1913 Level lev = uti.LevelForObj(oLevel); 1914 int level = uti.levelDepthForMember(m); 1915 int levlev = ((MDXLevel) lev).getDepth(); 1916 if (levlev == level + 1) 1917 uti.addMemberSiblings(list, m, maxLevel); else if (levlev == level + 2) 1919 uti.addMemberChildren(list, m, maxLevel); else { 1921 Level parentLevel = uti.getParentLevel(lev); 1923 uti.addMemberDescendants(list, m, parentLevel, maxLevel); 1924 } 1925 } else if (uti.isFunCallTo(oFun, "Members")) { 1926 Object oLevel = uti.funCallArg(oFun, 0); 1928 Level lev = uti.LevelForObj(oLevel); 1929 int levlev = ((MDXLevel) lev).getDepth(); 1930 if (levlev == 0) 1931 return; Level parentLevel = uti.getParentLevel(lev); 1933 uti.addLevelMembers(list, parentLevel, maxLevel); 1934 } else { 1935 Object oFun2 = uti.funCallArg(oFun, 0); 1937 addFunCallToDrillup(list, oFun2, maxLevel); } 1940 } 1941 1942 1948 private void funToList(Object oFun, List list) { 1949 if (uti.isFunCallTo(oFun, "Union")) { 1950 Object oArg0 = uti.funCallArg(oFun, 0); 1951 Object oArg1 = uti.funCallArg(oFun, 1); 1952 funToList(oArg0, list); 1953 funToList(oArg1, list); 1954 } else if (uti.isFunCallTo(oFun, "{}")) { 1955 for (int i = 0; i < uti.funCallArgCount(oFun); i++) { 1956 Object oMember = uti.funCallArg(oFun, i); 1958 list.add(oMember); 1959 } 1960 } else { 1961 list.add(oFun); 1962 } 1963 } 1964 1965 1969 1972 public void hierarchizePositions(final Member[][] aPosMem) { 1974 1975 final int nDimension = aPosMem[0].length; 1976 final Map [] firstOccurrences = new HashMap [nDimension]; 1977 for (int i = 0; i < nDimension; i++) { 1978 firstOccurrences[i] = new HashMap (); 1979 } 1980 for (int i = 0; i < aPosMem.length; i++) { 1981 for (int j = 0; j < nDimension; j++) { 1982 if (!firstOccurrences[j].containsKey(aPosMem[i][j])) { 1984 firstOccurrences[j].put(aPosMem[i][j], new Integer (i)); 1985 } 1986 } } 1989 Arrays.sort(aPosMem, new Comparator () { 1990 public int compare(Object o1, Object o2) { 1991 Member[] a1 = (Member[]) o1; 1993 Member[] a2 = (Member[]) o2; 1994 1995 DimensionLoop: for (int i = 0; i < a1.length; i++) { 1996 if (a1[i].equals(a2[i])) 1997 continue DimensionLoop; 1998 int level1 = ((MDXLevel) a1[i].getLevel()).getDepth(); 2002 int level2 = ((MDXLevel) a1[i].getLevel()).getDepth(); 2003 if (level1 == level2) { 2004 int first1 = ((Integer ) firstOccurrences[i].get(a1[i])).intValue(); 2005 int first2 = ((Integer ) firstOccurrences[i].get(a2[i])).intValue(); 2006 return first1 - first2; 2007 } else { 2008 return level1 - level2; 2009 } 2010 } 2013 return 0; } 2015 }); 2016 2017 } 2018 2019 2053 2057 2060 public QuaxUti getUti() { 2061 return uti; 2062 } 2063 2064 2067 public void setUti(QuaxUti uti) { 2068 this.uti = uti; 2069 } 2070 2071 2074 public int getNDimension() { 2075 return nDimension; 2076 } 2077 2078 2081 public TreeNode getPosTreeRoot() { 2082 return posTreeRoot; 2083 } 2084 2085 2088 public boolean isHierarchizeNeeded() { 2089 return hierarchizeNeeded; 2090 } 2091 2092 2095 public void setHierarchizeNeeded(boolean b) { 2096 hierarchizeNeeded = b; 2097 } 2098 2099 2102 public void setPosTreeRoot(TreeNode posTreeRoot, boolean hiersChanged) { 2103 this.posTreeRoot = posTreeRoot; 2104 if (hiersChanged) { 2105 TreeNode firstNode = posTreeRoot; 2107 List hiersList = new ArrayList (); 2108 List children = firstNode.getChildren(); 2109 while (children.size() > 0) { 2110 firstNode = (TreeNode) children.get(0); 2111 Object oExp = firstNode.getReference(); 2112 Hierarchy hier; 2113 try { 2114 hier = uti.hierForExp(oExp); 2115 } catch (CannotHandleException e) { 2116 logger.fatal("could not determine Hierarchy for set"); 2117 logger.fatal(e); 2118 throw new IllegalArgumentException (e.getMessage()); 2119 } 2120 hiersList.add(hier); 2121 ++nDimension; 2122 children = firstNode.getChildren(); 2123 } 2124 hiers = (Hierarchy[]) hiersList.toArray(new Hierarchy[0]); 2125 nDimension = hiers.length; 2126 containsUF = new boolean[nDimension]; ufMemberLists = new List [nDimension]; 2128 2129 posTreeRoot.walkChildren(new TreeNodeCallback() { 2132 2135 public int handleTreeNode(TreeNode node) { 2136 int iDimNode = node.getLevel() - 1; 2137 Object oExp = node.getReference(); 2138 if (!uti.canHandle(oExp)) { 2139 containsUF[iDimNode] = true; 2143 } 2144 2145 return TreeNodeCallback.CONTINUE; 2146 } }); 2148 } 2149 } 2150 2151 2156 public int getOrdinal() { 2157 return ordinal; 2158 } 2159 2160 2163 public void setHiers(Hierarchy[] hierarchies) { 2164 hiers = hierarchies; 2165 nDimension = hierarchies.length; 2166 } 2167 2168 2171 public Hierarchy[] getHiers() { 2172 return hiers; 2173 } 2174 2175 2178 public boolean isQubonMode() { 2179 return qubonMode; 2180 } 2181 2182 2185 public void setQubonMode(boolean qubonMode) { 2186 this.qubonMode = qubonMode; 2187 } 2188 2189 2197 private boolean isMemberInFunCall(Object oExp, Member member, int hierIndex) { 2198 boolean b = false; 2199 try { 2200 b = uti.isMemberInFunCall(oExp, member); 2201 } catch (CannotHandleException e) { 2202 if (ufMemberLists[hierIndex] == null) 2205 throw new IllegalArgumentException ("Unknow Function - no member list, dimension=" 2206 + hierIndex + " function=" + e.getMessage()); 2207 2208 b = ufMemberLists[hierIndex].contains(member); 2209 } 2210 return b; 2211 } 2212 2213 2216 private boolean isFunCallNotTopLevel(Object oExp, int hierIndex) { 2217 boolean b = false; 2218 2219 try { 2220 b = uti.isFunCallNotTopLevel(oExp); 2221 } catch (CannotHandleException e) { 2222 if (ufMemberLists[hierIndex] == null) 2225 throw new IllegalArgumentException ("Unknow Function - no member list, dimension=" 2226 + hierIndex + " function=" + e.getMessage()); 2227 2228 for (Iterator iter = ufMemberLists[hierIndex].iterator(); iter.hasNext();) { 2229 Member m = (Member) iter.next(); 2230 if (!uti.isMemberOnToplevel(m)) { 2231 b = true; 2232 break; 2233 } 2234 } 2235 } 2236 return b; 2237 } 2238 2239 2242 private boolean isChildOfMemberInFunCall(Object oExp, Member member, int hierIndex) { 2243 boolean b = false; 2244 2245 try { 2246 b = uti.isChildOfMemberInFunCall(oExp, member); 2247 } catch (CannotHandleException e) { 2248 if (ufMemberLists[hierIndex] == null) 2251 throw new IllegalArgumentException ("Unknow Function - no member list, dimension=" 2252 + hierIndex + " function=" + e.getMessage()); 2253 2254 for (Iterator iter = ufMemberLists[hierIndex].iterator(); iter.hasNext();) { 2255 Member m = (Member) iter.next(); 2256 if (uti.checkParent(member, uti.objForMember(m))) { 2257 b = true; 2258 break; 2259 } 2260 } 2261 } 2262 return b; 2263 } 2264 2265 2268 private boolean isDescendantOfMemberInFunCall(Object oExp, Member member, int hierIndex) { 2269 boolean b = false; 2270 2271 try { 2272 b = uti.isDescendantOfMemberInFunCall(oExp, member); 2273 } catch (CannotHandleException e) { 2274 if (ufMemberLists[hierIndex] == null) 2277 throw new IllegalArgumentException ("Unknow Function - no member list, dimension=" 2278 + hierIndex + " function=" + e.getMessage()); 2279 2280 for (Iterator iter = ufMemberLists[hierIndex].iterator(); iter.hasNext();) { 2281 Member m = (Member) iter.next(); 2282 if (uti.checkDescendantM(member, m)) { 2283 b = true; 2284 break; 2285 } 2286 } 2287 } 2288 return b; 2289 } 2290 2291 2295 private Object removeDescendantsFromFunCall(Object oFun, Member member, int iHier) { 2296 try { 2297 return removeDescendantsFromFunCall(oFun, member); 2298 } catch (CannotHandleException e) { 2299 logger.error("Unkown FunCall " + uti.funCallName(oFun)); 2303 2304 if (ufMemberLists[iHier] == null) 2305 throw new IllegalArgumentException ("Unknow Function - no member list, dimension=" + iHier 2306 + " function=" + e.getMessage()); 2307 2308 List newList = new ArrayList (); 2309 for (Iterator iter = ufMemberLists[iHier].iterator(); iter.hasNext();) { 2310 Member m = (Member) iter.next(); 2311 if (!uti.checkDescendantM(member, m)) { 2312 newList.add(uti.objForMember(m)); 2313 } 2314 } 2315 return uti.createFunCall("{}", newList.toArray(), QuaxUti.FUNTYPE_BRACES); 2316 } 2317 } 2318 2319 2323 private Object removeDescendantsFromFunCall(Object oFun, Member member) 2324 throws CannotHandleException { 2325 if (uti.isFunCallTo(oFun, "Children")) { 2326 return null; 2329 } else if (uti.isFunCallTo(oFun, "Descendants")) { 2330 return null; 2333 } else if (uti.isFunCallTo(oFun, "Members")) { 2334 Level level = member.getLevel(); 2335 Object [] members = uti.getLevelMembers(level); 2336 List remainder = new ArrayList (); 2337 for (int i = 0; i < members.length; i++) { 2338 if (!uti.checkDescendantO(member, members[i])) 2339 remainder.add(members[i]); 2340 } 2341 return uti.createMemberSet(remainder); 2342 } else if (uti.isFunCallTo(oFun, "{}")) { 2343 List remainder = new ArrayList (); 2344 for (int i = 0; i < uti.funCallArgCount(oFun); i++) { 2345 Object om = uti.funCallArg(oFun, i); 2346 if (!uti.checkDescendantO(member, om)) 2347 remainder.add(om); 2348 } 2349 return uti.createMemberSet(remainder); 2350 } else if (uti.isFunCallTo(oFun, "Union")) { 2351 Object [] uargs = new Object [2]; 2352 uargs[0] = removeDescendantsFromFunCall(uti.funCallArg(oFun, 0), member); 2353 uargs[1] = removeDescendantsFromFunCall(uti.funCallArg(oFun, 0), member); 2354 if (uargs[0] == null && uargs[1] == null) 2355 return null; 2356 if (uargs[1] == null) 2357 return uargs[0]; 2358 if (uargs[0] == null) 2359 return uargs[1]; 2360 if (uti.isMember(uargs[0])) { 2361 uargs[0] = uti.createFunCall("{}", new Object [] { uargs[0]}, QuaxUti.FUNTYPE_BRACES); 2362 } 2363 if (uti.isMember(uargs[1])) { 2364 uargs[1] = uti.createFunCall("{}", new Object [] { uargs[1]}, QuaxUti.FUNTYPE_BRACES); 2365 } 2366 if (uti.isFunCallTo(uargs[0], "{}") && uti.isFunCallTo(uargs[1], "{}")) 2367 return unionOfSets(uargs[0], uargs[1]); 2368 2369 return uti.createFunCall("Union", uargs, QuaxUti.FUNTYPE_FUNCTION); 2370 } 2371 throw new CannotHandleException(uti.funCallName(oFun)); 2372 2373 } 2374 2375 2378 private Object createComplement(Object oFun, Member member, int iHier) { 2379 try { 2380 return createComplement(oFun, member); 2381 } catch (CannotHandleException e) { 2382 logger.error("Unkown FunCall " + uti.funCallName(oFun)); 2386 if (ufMemberLists[iHier] == null) 2387 throw new IllegalArgumentException ("Unknow Function - no member list, dimension=" + iHier 2388 + " function=" + e.getMessage()); 2389 2390 List newList = new ArrayList (); 2391 for (Iterator iter = ufMemberLists[iHier].iterator(); iter.hasNext();) { 2392 Member m = (Member) iter.next(); 2393 if (!member.equals(m)) { 2394 newList.add(uti.objForMember(m)); 2395 } 2396 } 2397 return uti.createFunCall("{}", newList.toArray(), QuaxUti.FUNTYPE_BRACES); 2398 } 2399 } 2400 2401 2405 private Object createComplement(Object oFun, Member member) throws CannotHandleException { 2406 if (uti.isFunCallTo(oFun, "Children")) { 2407 Object oParent = uti.funCallArg(oFun, 0); 2408 Object oMember = uti.objForMember(member); 2410 if (!uti.checkChild(member, oParent)) 2411 return oFun; 2412 Object [] oChildren = uti.getChildren(oParent); 2413 if (oChildren.length < 2) 2414 return null; 2415 Object [] mComplement = new Object [oChildren.length - 1]; 2416 int ii = 0; 2417 for (int i = 0; i < oChildren.length; i++) { 2418 if (!(oChildren[i].equals(oMember))) 2419 mComplement[ii++] = oChildren[i]; 2420 } 2421 if (mComplement.length == 1) 2422 return mComplement[0]; Object oComplement = uti.createFunCall("{}", mComplement, QuaxUti.FUNTYPE_BRACES); 2424 return oComplement; 2425 2426 } else if (uti.isFunCallTo(oFun, "{}")) { 2427 int nComp = 0; 2428 int nArg = uti.funCallArgCount(oFun); 2429 Object oMember = uti.objForMember(member); 2430 for (int i = 0; i < nArg; i++) { 2431 Object o = uti.funCallArg(oFun, i); 2432 if (!(o.equals(oMember))) 2433 ++nComp; 2434 } 2435 if (nComp == 0) 2436 return null; 2437 if (nComp == nArg) { 2438 return oFun; 2440 } 2441 2442 Object [] mComplement = new Object [nComp]; 2443 int ii = 0; 2444 for (int i = 0; i < nArg; i++) { 2445 Object o = uti.funCallArg(oFun, i); 2446 if (!(o.equals(oMember))) 2447 mComplement[ii++] = o; 2448 } 2449 if (mComplement.length == 1) 2450 return mComplement[0]; Object oComplement = uti.createFunCall("{}", mComplement, QuaxUti.FUNTYPE_BRACES); 2452 return oComplement; 2453 } else if (uti.isFunCallTo(oFun, "Union")) { 2454 Object [] complements = new Object [2]; 2457 for (int i = 0; i < 2; i++) { 2458 Object o = uti.funCallArg(oFun, i); 2459 complements[i] = createComplement(o, member); 2460 } 2461 if (complements[0] == null && complements[1] == null) 2462 return null; 2463 else if (complements[0] != null && complements[1] == null) 2464 return complements[0]; else if (complements[0] == null && complements[1] != null) 2466 return complements[1]; else { 2468 if (!uti.isFunCall(complements[0])) { 2470 complements[0] = uti.createFunCall("{}", new Object [] { complements[0]}, 2471 QuaxUti.FUNTYPE_BRACES); 2472 } 2473 if (!uti.isFunCall(complements[1])) { 2474 complements[1] = uti.createFunCall("{}", new Object [] { complements[1]}, 2475 QuaxUti.FUNTYPE_BRACES); 2476 } 2477 2478 if (uti.isFunCallTo(complements[0], "{}") && uti.isFunCallTo(complements[1], "{}")) { 2479 return unionOfSets(complements[0], complements[1]); 2481 } 2482 Object newUnion = uti.createFunCall("Union", complements, QuaxUti.FUNTYPE_FUNCTION); 2483 return newUnion; 2484 } 2485 } 2486 throw new CannotHandleException(uti.funCallName(oFun)); 2488 2489 } 2490 2491 2493 public int getGenerateIndex() { 2494 return generateIndex; 2495 } 2496 2497 2499 public void setGenerateIndex(int i) { 2500 generateIndex = i; 2501 } 2502 2503 2505 public int getGenerateMode() { 2506 return generateMode; 2507 } 2508 2509 2511 public void setGenerateMode(int i) { 2512 generateMode = i; 2513 } 2514 2515 2518 public void resetGenerate() { 2519 generateMode = 0; 2520 generateIndex = -1; 2521 expGenerate = null; 2522 } 2523 2524 2527 public int getNHierExclude() { 2528 return nHierExclude; 2529 } 2530 2531 2535 public void setNHierExclude(int hierExclude) { 2536 nHierExclude = hierExclude; 2537 } 2538 2539 2542 private boolean allowNavigate(Member member, boolean qubon) { 2543 int iDim = dimIdx(uti.dimForMember(member)); 2544 return allowNavigate(iDim, qubon); 2545 } 2546 2547 2550 private boolean allowNavigate(int iDim, boolean qubon) { 2551 if (qubon && generateIndex >= 0 && generateMode == CalcSet.STICKY && iDim == generateIndex) 2552 return false; 2553 else if (!qubon && generateIndex >= 0 && generateMode == CalcSet.STICKY 2554 && iDim >= generateIndex) 2555 return false; 2556 else 2557 return true; 2558 } 2559 2560 2563 private Object unionOfSets(Object set1, Object set2) { 2564 int n1 = uti.funCallArgCount(set1); 2566 int n2 = uti.funCallArgCount(set2); 2567 Object [] newSet = new Object [n1 + n2]; 2568 int i = 0; 2569 for (int j = 0; j < n1; j++) { 2570 newSet[i++] = uti.funCallArg(set1, j); 2571 } 2572 for (int j = 0; j < n2; j++) { 2573 newSet[i++] = uti.funCallArg(set2, j); 2574 } 2575 return uti.createFunCall("{}", newSet, QuaxUti.FUNTYPE_BRACES); 2576 } 2577 2578 2582 public void setHierMemberList(int iHier, List list) { 2583 ufMemberLists[iHier] = list; 2584 } 2585 2586 2591 public boolean isUnknownFunction( int iHier) { 2592 return containsUF[iHier]; 2593 } 2594 2595 2598 public static class CannotHandleException extends Exception { 2599 2600 2605 public CannotHandleException(String arg0) { 2606 super(arg0); 2607 } 2608 } 2610} | Popular Tags |