1 28 package net.sf.jasperreports.crosstabs.fill.calculation; 29 30 import java.util.ArrayList ; 31 import java.util.Collections ; 32 import java.util.Iterator ; 33 import java.util.LinkedList ; 34 import java.util.List ; 35 import java.util.ListIterator ; 36 import java.util.Map ; 37 import java.util.TreeMap ; 38 import java.util.Map.Entry; 39 40 import net.sf.jasperreports.crosstabs.fill.calculation.BucketDefinition.Bucket; 41 import net.sf.jasperreports.crosstabs.fill.calculation.MeasureDefinition.MeasureValue; 42 import net.sf.jasperreports.engine.JRException; 43 import net.sf.jasperreports.engine.JRVariable; 44 import net.sf.jasperreports.engine.fill.JRCalculable; 45 46 52 public class BucketingService 53 { 54 protected static final byte DIMENSION_ROW = 0; 55 56 protected static final byte DIMENSION_COLUMN = 1; 57 58 protected static final int DIMENSIONS = 2; 59 60 protected final BucketDefinition[] allBuckets; 61 protected final BucketDefinition[][] buckets; 62 63 protected final int rowBucketCount; 64 protected final int colBucketCount; 65 66 protected final boolean[][] retrieveTotal; 67 private boolean[] rowRetrTotals; 68 private int rowRetrTotalMin; 69 private int rowRetrTotalMax; 70 private int[] rowRetrColMax; 71 72 protected final MeasureDefinition[] measures; 73 protected final int origMeasureCount; 74 protected final int[] measureIndexes; 75 76 protected final boolean sorted; 77 78 protected final BucketMap bucketValueMap; 79 protected long dataCount; 80 protected boolean processed; 81 82 protected HeaderCell[][] colHeaders; 83 protected HeaderCell[][] rowHeaders; 84 protected CrosstabCell[][] cells; 85 86 private final MeasureValue[] zeroUserMeasureValues; 87 88 89 90 99 public BucketingService(List rowBuckets, List columnBuckets, List measures, boolean sorted, boolean[][] retrieveTotal) 100 { 101 this.sorted = sorted; 102 103 buckets = new BucketDefinition[DIMENSIONS][]; 104 105 rowBucketCount = rowBuckets.size(); 106 buckets[DIMENSION_ROW] = new BucketDefinition[rowBucketCount]; 107 rowBuckets.toArray(buckets[DIMENSION_ROW]); 108 109 colBucketCount = columnBuckets.size(); 110 buckets[DIMENSION_COLUMN] = new BucketDefinition[colBucketCount]; 111 columnBuckets.toArray(buckets[DIMENSION_COLUMN]); 112 113 allBuckets = new BucketDefinition[rowBucketCount + colBucketCount]; 114 System.arraycopy(buckets[DIMENSION_ROW], 0, allBuckets, 0, rowBucketCount); 115 System.arraycopy(buckets[DIMENSION_COLUMN], 0, allBuckets, rowBucketCount, colBucketCount); 116 117 origMeasureCount = measures.size(); 118 List measuresList = new ArrayList (measures.size() * 2); 119 List measureIndexList = new ArrayList (measures.size() * 2); 120 for (int i = 0; i < measures.size(); ++i) 121 { 122 MeasureDefinition measure = (MeasureDefinition) measures.get(i); 123 addMeasure(measure, i, measuresList, measureIndexList); 124 } 125 this.measures = new MeasureDefinition[measuresList.size()]; 126 measuresList.toArray(this.measures); 127 this.measureIndexes = new int[measureIndexList.size()]; 128 for (int i = 0; i < measureIndexes.length; ++i) 129 { 130 measureIndexes[i] = ((Integer ) measureIndexList.get(i)).intValue(); 131 } 132 133 this.retrieveTotal = retrieveTotal; 134 checkTotals(); 135 136 bucketValueMap = createBucketMap(0); 137 138 zeroUserMeasureValues = initUserMeasureValues(); 139 } 140 141 142 protected void checkTotals() 143 { 144 rowRetrTotalMin = rowBucketCount + 1; 145 rowRetrTotalMax = -1; 146 rowRetrTotals = new boolean[rowBucketCount + 1]; 147 rowRetrColMax = new int[rowBucketCount + 1]; 148 for (int row = 0; row <= rowBucketCount; ++row) 149 { 150 rowRetrColMax[row] = -1; 151 boolean total = false; 152 for (int col = 0; col <= colBucketCount; ++col) 153 { 154 if (retrieveTotal[row][col]) 155 { 156 total = true; 157 rowRetrColMax[row] = col; 158 } 159 } 160 161 rowRetrTotals[row] = total; 162 if (total) 163 { 164 if (row < rowRetrTotalMin) 165 { 166 rowRetrTotalMin = row; 167 } 168 rowRetrTotalMax = row; 169 170 if (row < rowBucketCount) 171 { 172 allBuckets[row].setComputeTotal(); 173 } 174 } 175 } 176 177 for (int col = 0; col < colBucketCount; ++col) 178 { 179 BucketDefinition colBucket = allBuckets[rowBucketCount + col]; 180 if (!colBucket.computeTotal()) 181 { 182 boolean total = false; 183 for (int row = 0; !total && row <= rowBucketCount; ++row) 184 { 185 total = retrieveTotal[row][col]; 186 } 187 188 if (total) 189 { 190 colBucket.setComputeTotal(); 191 } 192 } 193 } 194 195 for (int d = 0; d < DIMENSIONS; ++d) 196 { 197 boolean dTotal = false; 198 199 for (int i = 0; i < buckets[d].length; ++i) 200 { 201 if (dTotal) 202 { 203 buckets[d][i].setComputeTotal(); 204 } 205 else 206 { 207 dTotal = buckets[d][i].computeTotal(); 208 } 209 } 210 } 211 } 212 213 214 217 public void clear() 218 { 219 bucketValueMap.clear(); 220 processed = false; 221 dataCount = 0; 222 } 223 224 protected BucketMap createBucketMap(int level) 225 { 226 BucketMap map; 227 if (sorted) 228 { 229 map = new BucketListMap(level, false); 230 } 231 else 232 { 233 map = new BucketTreeMap(level); 234 } 235 return map; 236 } 237 238 protected BucketListMap createCollectBucketMap(int level) 239 { 240 return new BucketListMap(level, true); 241 } 242 243 protected void addMeasure(MeasureDefinition measure, int index, List measuresList, List measureIndexList) 244 { 245 switch (measure.getCalculation()) 246 { 247 case JRVariable.CALCULATION_AVERAGE: 248 case JRVariable.CALCULATION_VARIANCE: 249 { 250 MeasureDefinition sumMeasure = MeasureDefinition.createHelperMeasure(measure, JRVariable.CALCULATION_SUM); 251 addMeasure(sumMeasure, index, measuresList, measureIndexList); 252 MeasureDefinition countMeasure = MeasureDefinition.createHelperMeasure(measure, JRVariable.CALCULATION_COUNT); 253 addMeasure(countMeasure, index, measuresList, measureIndexList); 254 break; 255 } 256 case JRVariable.CALCULATION_STANDARD_DEVIATION: 257 { 258 MeasureDefinition varianceMeasure = MeasureDefinition.createHelperMeasure(measure, JRVariable.CALCULATION_VARIANCE); 259 addMeasure(varianceMeasure, index, measuresList, measureIndexList); 260 break; 261 } 262 case JRVariable.CALCULATION_DISTINCT_COUNT: 263 { 264 MeasureDefinition countMeasure = MeasureDefinition.createDistinctCountHelperMeasure(measure); 265 addMeasure(countMeasure, index, measuresList, measureIndexList); 266 break; 267 } 268 } 269 270 measuresList.add(measure); 271 measureIndexList.add(new Integer (index)); 272 } 273 274 275 282 public void addData(Object [] bucketValues, Object [] measureValues) throws JRException 283 { 284 if (processed) 285 { 286 throw new JRException("Crosstab data has already been processed."); 287 } 288 289 ++dataCount; 290 291 Bucket[] bucketVals = getBucketValues(bucketValues); 292 293 MeasureValue[] values = bucketValueMap.insertMeasureValues(bucketVals); 294 295 for (int i = 0; i < measures.length; ++i) 296 { 297 values[i].addValue(measureValues[measureIndexes[i]]); 298 } 299 } 300 301 protected Bucket[] getBucketValues(Object [] bucketValues) 302 { 303 Bucket[] bucketVals = new Bucket[allBuckets.length]; 304 305 for (int i = 0; i < allBuckets.length; ++i) 306 { 307 BucketDefinition bucket = allBuckets[i]; 308 Object value = bucketValues[i]; 309 bucketVals[i] = bucket.create(value); 310 } 311 312 return bucketVals; 313 } 314 315 protected MeasureValue[] initMeasureValues() 316 { 317 MeasureValue[] values; 318 values = new MeasureValue[measures.length]; 319 320 for (int i = 0; i < measures.length; ++i) 321 { 322 MeasureDefinition measure = measures[i]; 323 values[i] = measure.new MeasureValue(); 324 325 switch (measure.getCalculation()) 326 { 327 case JRVariable.CALCULATION_AVERAGE: 328 case JRVariable.CALCULATION_VARIANCE: 329 { 330 values[i].setHelper(values[i - 2], JRCalculable.HELPER_SUM); 331 values[i].setHelper(values[i - 1], JRCalculable.HELPER_COUNT); 332 break; 333 } 334 case JRVariable.CALCULATION_STANDARD_DEVIATION: 335 { 336 values[i].setHelper(values[i - 1], JRCalculable.HELPER_VARIANCE); 337 } 338 case JRVariable.CALCULATION_DISTINCT_COUNT: 339 { 340 values[i].setHelper(values[i - 1], JRCalculable.HELPER_COUNT); 341 } 342 } 343 } 344 return values; 345 } 346 347 protected MeasureValue[] initUserMeasureValues() 348 { 349 MeasureValue[] vals = new MeasureValue[origMeasureCount]; 350 351 for (int c = 0, i = 0; i < measures.length; ++i) 352 { 353 if (!measures[i].isSystemDefined()) 354 { 355 vals[c] = measures[i].new MeasureValue(); 356 ++c; 357 } 358 } 359 360 return vals; 361 } 362 363 364 372 public void processData() throws JRException 373 { 374 if (!processed) 375 { 376 if (dataCount > 0) 377 { 378 if (allBuckets[rowBucketCount - 1].computeTotal() || allBuckets[allBuckets.length - 1].computeTotal()) 379 { 380 computeTotals(bucketValueMap); 381 } 382 383 createCrosstab(); 384 } 385 386 processed = true; 387 } 388 } 389 390 391 396 public boolean hasData() 397 { 398 return dataCount > 0; 399 } 400 401 402 409 public HeaderCell[][] getColumnHeaders() 410 { 411 return colHeaders; 412 } 413 414 415 422 public HeaderCell[][] getRowHeaders() 423 { 424 return rowHeaders; 425 } 426 427 428 435 public CrosstabCell[][] getCrosstabCells() 436 { 437 return cells; 438 } 439 440 441 447 public MeasureValue[] getMeasureValues(Bucket[] bucketValues) 448 { 449 BucketMap map = bucketValueMap; 450 451 for (int i = 0; map != null && i < allBuckets.length - 1; ++i) 452 { 453 map = (BucketMap) map.get(bucketValues[i]); 454 } 455 456 return map == null ? null : (MeasureValue[]) map.get(bucketValues[allBuckets.length - 1]); 457 } 458 459 protected MeasureValue[] getUserMeasureValues(MeasureValue[] values) 460 { 461 MeasureValue[] vals = new MeasureValue[origMeasureCount]; 462 463 for (int c = 0, i = 0; i < measures.length; ++i) 464 { 465 if (!measures[i].isSystemDefined()) 466 { 467 vals[c] = values[i]; 468 ++c; 469 } 470 } 471 472 return vals; 473 } 474 475 476 481 public MeasureValue[] getGrandTotals() 482 { 483 BucketMap map = bucketValueMap; 484 485 for (int i = 0; map != null && i < allBuckets.length - 1; ++i) 486 { 487 map = (BucketMap) map.getTotalEntry().getValue(); 488 } 489 490 return map == null ? null : (MeasureValue[]) map.getTotalEntry().getValue(); 491 } 492 493 494 protected void computeTotals(BucketMap bucketMap) throws JRException 495 { 496 byte dimension = bucketMap.level < rowBucketCount ? DIMENSION_ROW : DIMENSION_COLUMN; 497 498 if (dimension == DIMENSION_COLUMN && !allBuckets[allBuckets.length - 1].computeTotal()) 499 { 500 return; 501 } 502 503 if (!bucketMap.last) 504 { 505 for (Iterator it = bucketMap.entryIterator(); it.hasNext();) 506 { 507 Map.Entry entry = (Map.Entry ) it.next(); 508 509 computeTotals((BucketMap) entry.getValue()); 510 } 511 } 512 513 if (allBuckets[bucketMap.level].computeTotal()) 514 { 515 if (dimension == DIMENSION_COLUMN) 516 { 517 computeColumnTotal(bucketMap); 518 } 519 else 520 { 521 computeRowTotals(bucketMap); 522 } 523 } 524 } 525 526 527 protected void sumVals(MeasureValue[] totals, MeasureValue[] vals) throws JRException 528 { 529 for (int i = 0; i < measures.length; i++) 530 { 531 totals[i].addValue(vals[i]); 532 } 533 } 534 535 protected void computeColumnTotal(BucketMap bucketMap) throws JRException 536 { 537 MeasureValue[] totals = initMeasureValues(); 538 539 for (Iterator it = bucketMap.entryIterator(); it.hasNext();) 540 { 541 Map.Entry entry = (Map.Entry ) it.next(); 542 543 for (int i = bucketMap.level + 1; i < allBuckets.length; ++i) 544 { 545 entry = ((BucketMap) entry.getValue()).getTotalEntry(); 546 } 547 548 sumVals(totals, (MeasureValue[]) entry.getValue()); 549 } 550 551 for (int i = bucketMap.level + 1; i < allBuckets.length; ++i) 552 { 553 bucketMap = bucketMap.addTotalNextMap(); 554 } 555 556 bucketMap.addTotalEntry(totals); 557 } 558 559 560 protected void computeRowTotals(BucketMap bucketMap) throws JRException 561 { 562 BucketListMap totals = createCollectBucketMap(rowBucketCount); 563 564 for (Iterator it = bucketMap.entryIterator(); it.hasNext();) 565 { 566 Map.Entry entry = (Map.Entry ) it.next(); 567 568 for (int i = bucketMap.level + 1; i < rowBucketCount; ++i) 569 { 570 entry = ((BucketMap) entry.getValue()).getTotalEntry(); 571 } 572 573 totals.collectVals((BucketMap) entry.getValue(), true); 574 } 575 576 BucketMap totalBucketMap = bucketMap; 577 for (int i = bucketMap.level + 1; i < rowBucketCount; ++i) 578 { 579 totalBucketMap = totalBucketMap.addTotalNextMap(); 580 } 581 582 totalBucketMap.addTotalEntry(totals); 583 } 584 585 586 static protected class MapEntry implements Map.Entry , Comparable 587 { 588 final Bucket key; 589 590 final Object value; 591 592 MapEntry(Bucket key, Object value) 593 { 594 this.key = key; 595 this.value = value; 596 } 597 598 public Object getKey() 599 { 600 return key; 601 } 602 603 public Object getValue() 604 { 605 return value; 606 } 607 608 public Object setValue(Object value) 609 { 610 throw new UnsupportedOperationException (); 611 } 612 613 public int compareTo(Object o) 614 { 615 return key.compareTo(((MapEntry) o).key); 616 } 617 618 public String toString() 619 { 620 return key + ":" + value; 621 } 622 } 623 624 protected abstract class BucketMap 625 { 626 final int level; 627 final boolean last; 628 final Bucket totalKey; 629 630 BucketMap(int level) 631 { 632 this.level = level; 633 this.last = level == allBuckets.length - 1; 634 totalKey = allBuckets[level].VALUE_TOTAL; 635 } 636 637 BucketMap addTotalNextMap() 638 { 639 BucketMap nextMap = createBucketMap(level + 1); 640 addTotalEntry(nextMap); 641 return nextMap; 642 } 643 644 abstract void set(Bucket key, Object value); 645 646 abstract void clear(); 647 648 abstract Iterator entryIterator(); 649 650 abstract Object get(Bucket key); 651 652 abstract MeasureValue[] insertMeasureValues(Bucket[] bucketValues); 653 654 655 656 abstract void addTotalEntry(Object val); 657 658 abstract int size(); 659 660 abstract Map.Entry getTotalEntry(); 661 } 662 663 protected class BucketTreeMap extends BucketMap 664 { 665 TreeMap map; 666 667 BucketTreeMap(int level) 668 { 669 super(level); 670 671 map = new TreeMap (); 672 } 673 674 void clear() 675 { 676 map.clear(); 677 } 678 679 Iterator entryIterator() 680 { 681 return map.entrySet().iterator(); 682 } 683 684 Object get(Bucket key) 685 { 686 return map.get(key); 687 } 688 689 MeasureValue[] insertMeasureValues(Bucket[] bucketValues) 690 { 691 BucketTreeMap levelMap = (BucketTreeMap) bucketValueMap; 692 for (int i = 0; i < bucketValues.length - 1; i++) 693 { 694 BucketTreeMap nextMap = (BucketTreeMap) levelMap.get(bucketValues[i]); 695 if (nextMap == null) 696 { 697 nextMap = new BucketTreeMap(i + 1); 698 levelMap.map.put(bucketValues[i], nextMap); 699 } 700 701 levelMap = nextMap; 702 } 703 704 MeasureValue[] values = (MeasureValue[]) levelMap.get(bucketValues[bucketValues.length - 1]); 705 if (values == null) 706 { 707 values = initMeasureValues(); 708 levelMap.map.put(bucketValues[bucketValues.length - 1], values); 709 } 710 711 return values; 712 } 713 714 int size() 715 { 716 return map.size(); 717 } 718 719 void addTotalEntry(Object value) 720 { 721 map.put(totalKey, value); 722 } 723 724 Map.Entry getTotalEntry() 725 { 726 Object value = get(totalKey); 727 return value == null ? null : new MapEntry(totalKey, value); 728 } 729 730 731 public String toString() 732 { 733 return map.toString(); 734 } 735 736 void set(Bucket key, Object value) 737 { 738 map.put(key, value); 739 } 740 } 741 742 protected class BucketListMap extends BucketMap 743 { 744 List entries; 745 746 BucketListMap(int level, boolean linked) 747 { 748 super(level); 749 750 if (linked) 751 { 752 entries = new LinkedList (); 753 } 754 else 755 { 756 entries = new ArrayList (); 757 } 758 } 759 760 void clear() 761 { 762 entries.clear(); 763 } 764 765 Iterator entryIterator() 766 { 767 return entries.iterator(); 768 } 769 770 private void add(Bucket key, Object value) 771 { 772 entries.add(new MapEntry(key, value)); 773 } 774 775 Object get(Bucket key) 776 { 777 int idx = Collections.binarySearch(entries, new MapEntry(key, null)); 778 return idx >= 0 ? ((MapEntry) entries.get(idx)).value : null; 779 } 780 781 MeasureValue[] insertMeasureValues(Bucket[] bucketValues) 782 { 783 int i = 0; 784 Object levelObj = this; 785 BucketListMap map = null; 786 while (i < allBuckets.length) 787 { 788 map = (BucketListMap) levelObj; 789 int size = map.entries.size(); 790 if (size == 0) 791 { 792 break; 793 } 794 795 MapEntry lastEntry = (MapEntry) map.entries.get(size - 1); 796 if (!lastEntry.key.equals(bucketValues[i])) 797 { 798 break; 799 } 800 801 ++i; 802 levelObj = lastEntry.value; 803 } 804 805 if (i == allBuckets.length) 806 { 807 return (MeasureValue[]) levelObj; 808 } 809 810 while (i < allBuckets.length - 1) 811 { 812 BucketListMap nextMap = new BucketListMap(i + 1, false); 813 map.add(bucketValues[i], nextMap); 814 map = nextMap; 815 ++i; 816 } 817 818 MeasureValue[] values = initMeasureValues(); 819 map.add(bucketValues[i], values); 820 821 return values; 822 } 823 824 int size() 825 { 826 return entries.size(); 827 } 828 829 void addTotalEntry(Object value) 830 { 831 add(totalKey, value); 832 } 833 834 Map.Entry getTotalEntry() 835 { 836 MapEntry lastEntry = (MapEntry) entries.get(entries.size() - 1); 837 if (lastEntry.key.isTotal()) 838 { 839 return lastEntry; 840 } 841 842 return null; 843 } 844 845 void set(Bucket key, Object value) 846 { 847 MapEntry mapEntry = new MapEntry(key, value); 848 int idx = Collections.binarySearch(entries, mapEntry); 849 int ins = -idx - 1; 850 entries.add(ins, mapEntry); 851 } 852 853 854 void collectVals(BucketMap map, boolean sum) throws JRException 855 { 856 ListIterator totalIt = entries.listIterator(); 857 MapEntry totalItEntry = totalIt.hasNext() ? (MapEntry) totalIt.next() : null; 858 859 Iterator it = map.entryIterator(); 860 Map.Entry entry = it.hasNext() ? (Map.Entry ) it.next() : null; 861 while(entry != null) 862 { 863 Bucket key = (Bucket) entry.getKey(); 864 865 int compare = totalItEntry == null ? -1 : key.compareTo(totalItEntry.key); 866 if (compare <= 0) 867 { 868 Object addVal = null; 869 870 if (last) 871 { 872 if (sum) 873 { 874 MeasureValue[] totalVals = compare == 0 ? (MeasureValue[]) totalItEntry.value : null; 875 876 if (totalVals == null) 877 { 878 totalVals = initMeasureValues(); 879 addVal = totalVals; 880 } 881 882 sumVals(totalVals, (MeasureValue[]) entry.getValue()); 883 } 884 } 885 else 886 { 887 BucketListMap nextTotals = compare == 0 ? (BucketListMap) totalItEntry.value : null; 888 889 if (nextTotals == null) 890 { 891 nextTotals = createCollectBucketMap(level + 1); 892 addVal = nextTotals; 893 } 894 895 nextTotals.collectVals((BucketMap) entry.getValue(), sum); 896 } 897 898 if (compare < 0) 899 { 900 if (totalItEntry != null) 901 { 902 totalIt.previous(); 903 } 904 totalIt.add(new MapEntry(key, addVal)); 905 if (totalItEntry != null) 906 { 907 totalIt.next(); 908 } 909 } 910 911 entry = it.hasNext() ? (Map.Entry ) it.next() : null; 912 } 913 914 if (compare >= 0) 915 { 916 totalItEntry = totalIt.hasNext() ? (MapEntry) totalIt.next() : null; 917 } 918 } 919 } 920 } 921 922 923 924 protected void createCrosstab() throws JRException 925 { 926 CollectedList[] collectedHeaders = new CollectedList[BucketingService.DIMENSIONS]; 927 collectedHeaders[DIMENSION_ROW] = createHeadersList(DIMENSION_ROW, bucketValueMap, 0, false); 928 929 BucketListMap collectedCols; 930 if (allBuckets[0].computeTotal()) 931 { 932 BucketMap map = bucketValueMap; 933 for (int i = 0; i < rowBucketCount; ++i) 934 { 935 map = (BucketMap) map.getTotalEntry().getValue(); 936 } 937 collectedCols = (BucketListMap) map; 938 } 939 else 940 { 941 collectedCols = createCollectBucketMap(rowBucketCount); 942 collectCols(collectedCols, bucketValueMap); 943 } 944 collectedHeaders[DIMENSION_COLUMN] = createHeadersList(DIMENSION_COLUMN, collectedCols, 0, false); 945 946 colHeaders = createHeaders(BucketingService.DIMENSION_COLUMN, collectedHeaders); 947 rowHeaders = createHeaders(BucketingService.DIMENSION_ROW, collectedHeaders); 948 949 cells = new CrosstabCell[collectedHeaders[BucketingService.DIMENSION_ROW].span][collectedHeaders[BucketingService.DIMENSION_COLUMN].span]; 950 fillCells(collectedHeaders, bucketValueMap, 0, new int[]{0, 0}, new ArrayList (), new ArrayList ()); 951 } 952 953 954 protected void collectCols(BucketListMap collectedCols, BucketMap bucketMap) throws JRException 955 { 956 if (allBuckets[bucketMap.level].computeTotal()) 957 { 958 BucketMap map = bucketMap; 959 for (int i = bucketMap.level; i < rowBucketCount; ++i) 960 { 961 map = (BucketMap) map.getTotalEntry().getValue(); 962 } 963 collectedCols.collectVals(map, false); 964 965 return; 966 } 967 968 for (Iterator it = bucketMap.entryIterator(); it.hasNext();) 969 { 970 Map.Entry entry = (Map.Entry ) it.next(); 971 BucketMap nextMap = (BucketMap) entry.getValue(); 972 if (bucketMap.level == rowBucketCount - 1) 973 { 974 collectedCols.collectVals(nextMap, false); 975 } 976 else 977 { 978 collectCols(collectedCols, nextMap); 979 } 980 } 981 } 982 983 984 protected CollectedList createHeadersList(byte dimension, BucketMap bucketMap, int level, boolean total) 985 { 986 CollectedList headers = new CollectedList(); 987 988 for (Iterator it = bucketMap.entryIterator(); it.hasNext();) 989 { 990 Map.Entry entry = (Map.Entry ) it.next(); 991 Bucket bucketValue = (Bucket) entry.getKey(); 992 993 boolean totalBucket = bucketValue.isTotal(); 994 byte totalPosition = allBuckets[bucketMap.level].getTotalPosition(); 995 boolean createHeader = !totalBucket || total || totalPosition != BucketDefinition.TOTAL_POSITION_NONE; 996 997 if (createHeader) 998 { 999 CollectedList nextHeaders; 1000 if (level + 1 < buckets[dimension].length) 1001 { 1002 BucketMap nextMap = (BucketMap) entry.getValue(); 1003 nextHeaders = createHeadersList(dimension, nextMap, level + 1, total || totalBucket); 1004 } 1005 else 1006 { 1007 nextHeaders = new CollectedList(); 1008 nextHeaders.span = 1; 1009 } 1010 nextHeaders.key = bucketValue; 1011 1012 if (totalBucket) 1013 { 1014 if (totalPosition == BucketDefinition.TOTAL_POSITION_START) 1015 { 1016 headers.addFirst(nextHeaders); 1017 } 1018 else 1019 { 1020 headers.add(nextHeaders); 1021 } 1022 } 1023 else 1024 { 1025 headers.add(nextHeaders); 1026 } 1027 } 1028 } 1029 1030 if (headers.span == 0) 1031 { 1032 headers.span = 1; 1033 } 1034 1035 return headers; 1036 } 1037 1038 protected HeaderCell[][] createHeaders(byte dimension, CollectedList[] headersLists) 1039 { 1040 HeaderCell[][] headers = new HeaderCell[buckets[dimension].length][headersLists[dimension].span]; 1041 1042 List vals = new ArrayList (); 1043 fillHeaders(dimension, headers, 0, 0, headersLists[dimension], vals); 1044 1045 return headers; 1046 } 1047 1048 1049 protected void fillHeaders(byte dimension, HeaderCell[][] headers, int level, int col, CollectedList list, List vals) 1050 { 1051 if (level == buckets[dimension].length) 1052 { 1053 return; 1054 } 1055 1056 for (Iterator it = list.iterator(); it.hasNext();) 1057 { 1058 CollectedList subList = (CollectedList) it.next(); 1059 1060 vals.add(subList.key); 1061 1062 int depthSpan = subList.key.isTotal() ? buckets[dimension].length - level : 1; 1063 Bucket[] values = new Bucket[buckets[dimension].length]; 1064 vals.toArray(values); 1065 1066 headers[level][col] = new HeaderCell(values, subList.span, depthSpan); 1067 1068 if (!subList.key.isTotal()) 1069 { 1070 fillHeaders(dimension, headers, level + 1, col, subList, vals); 1071 } 1072 1073 col += subList.span; 1074 vals.remove(vals.size() - 1); 1075 } 1076 } 1077 1078 1079 protected void fillCells(CollectedList[] collectedHeaders, BucketMap bucketMap, int level, int[] pos, List vals, List bucketMaps) 1080 { 1081 bucketMaps.add(bucketMap); 1082 1083 byte dimension = level < rowBucketCount ? DIMENSION_ROW : DIMENSION_COLUMN; 1084 boolean last = level == allBuckets.length - 1; 1085 1086 CollectedList[] nextCollected = null; 1087 if (!last) 1088 { 1089 nextCollected = new CollectedList[DIMENSIONS]; 1090 for (int d = 0; d < DIMENSIONS; ++d) 1091 { 1092 if (d != dimension) 1093 { 1094 nextCollected[d] = collectedHeaders[d]; 1095 } 1096 } 1097 } 1098 1099 boolean incrementRow = level == buckets[BucketingService.DIMENSION_ROW].length - 1; 1100 1101 CollectedList collectedList = collectedHeaders[dimension]; 1102 1103 Iterator bucketIt = bucketMap == null ? null : bucketMap.entryIterator(); 1104 Map.Entry bucketItEntry = bucketIt != null && bucketIt.hasNext() ? (Map.Entry ) bucketIt.next() : null; 1105 for (Iterator it = collectedList.iterator(); it.hasNext();) 1106 { 1107 CollectedList list = (CollectedList) it.next(); 1108 1109 Map.Entry bucketEntry = null; 1110 if (list.key.isTotal()) 1111 { 1112 if (bucketMap != null) 1113 { 1114 bucketEntry = bucketMap.getTotalEntry(); 1115 } 1116 } 1117 else 1118 { 1119 if (bucketItEntry != null && bucketItEntry.getKey().equals(list.key)) 1120 { 1121 bucketEntry = bucketItEntry; 1122 bucketItEntry = bucketIt.hasNext() ? (Map.Entry ) bucketIt.next() : null; 1123 } 1124 } 1125 1126 vals.add(list.key); 1127 if (last) 1128 { 1129 fillCell(pos, vals, bucketMaps, bucketEntry); 1130 } 1131 else 1132 { 1133 nextCollected[dimension] = list; 1134 BucketMap nextMap = bucketEntry == null ? null : (BucketMap) bucketEntry.getValue(); 1135 1136 fillCells(nextCollected, nextMap, level + 1, pos, vals, bucketMaps); 1137 } 1138 vals.remove(vals.size() - 1); 1139 1140 if (incrementRow) 1141 { 1142 ++pos[0]; 1143 pos[1] = 0; 1144 } 1145 } 1146 1147 bucketMaps.remove(bucketMaps.size() - 1); 1148 } 1149 1150 1151 protected void fillCell(int[] pos, List vals, List bucketMaps, Map.Entry bucketEntry) 1152 { 1153 Iterator valsIt = vals.iterator(); 1154 Bucket[] rowValues = new Bucket[buckets[BucketingService.DIMENSION_ROW].length]; 1155 for (int i = 0; i < rowValues.length; i++) 1156 { 1157 rowValues[i] = (Bucket) valsIt.next(); 1158 } 1159 1160 Bucket[] columnValues = new Bucket[buckets[BucketingService.DIMENSION_COLUMN].length]; 1161 for (int i = 0; i < columnValues.length; i++) 1162 { 1163 columnValues[i] = (Bucket) valsIt.next(); 1164 } 1165 1166 MeasureValue[] measureVals = bucketEntry == null ? zeroUserMeasureValues : getUserMeasureValues((MeasureValue[]) bucketEntry.getValue()); 1167 MeasureValue[][][] totals = retrieveTotals(vals, bucketMaps); 1168 cells[pos[0]][pos[1]] = new CrosstabCell(rowValues, columnValues, measureVals, totals); 1169 ++pos[1]; 1170 } 1171 1172 1173 protected MeasureValue[][][] retrieveTotals(List vals, List bucketMaps) 1174 { 1175 MeasureValue[][][] totals = new MeasureValue[rowBucketCount + 1][colBucketCount + 1][]; 1176 1177 for (int row = rowRetrTotalMax; row >= rowRetrTotalMin; --row) 1178 { 1179 if (!rowRetrTotals[row]) 1180 { 1181 continue; 1182 } 1183 1184 BucketMap rowMap = (BucketMap) bucketMaps.get(row); 1185 for (int i = row; rowMap != null && i < rowBucketCount; ++i) 1186 { 1187 Entry totalEntry = rowMap.getTotalEntry(); 1188 rowMap = totalEntry == null ? null : (BucketMap) totalEntry.getValue(); 1189 } 1190 1191 for (int col = 0; col <= rowRetrColMax[row]; ++col) 1192 { 1193 BucketMap colMap = rowMap; 1194 1195 if (col < colBucketCount - 1) 1196 { 1197 if (row == rowBucketCount) 1198 { 1199 rowMap = (BucketMap) bucketMaps.get(rowBucketCount + col + 1); 1200 } 1201 else if (rowMap != null) 1202 { 1203 rowMap = (BucketMap) rowMap.get((Bucket) vals.get(rowBucketCount + col)); 1204 } 1205 } 1206 1207 if (!retrieveTotal[row][col]) 1208 { 1209 continue; 1210 } 1211 1212 for (int i = col + 1; colMap != null && i < colBucketCount; ++i) 1213 { 1214 colMap = (BucketMap) colMap.getTotalEntry().getValue(); 1215 } 1216 1217 if (colMap != null) 1218 { 1219 if (col == colBucketCount) 1220 { 1221 MeasureValue[] measureValues = (MeasureValue[]) colMap.get((Bucket) vals.get(rowBucketCount + colBucketCount - 1)); 1222 totals[row][col] = getUserMeasureValues(measureValues); 1223 } 1224 else 1225 { 1226 Map.Entry totalEntry = colMap.getTotalEntry(); 1227 if (totalEntry != null) 1228 { 1229 MeasureValue[] totalValues = (MeasureValue[]) totalEntry.getValue(); 1230 totals[row][col] = getUserMeasureValues(totalValues); 1231 } 1232 } 1233 } 1234 1235 if (totals[row][col] == null) 1236 { 1237 totals[row][col] = zeroUserMeasureValues; 1238 } 1239 } 1240 } 1241 1242 return totals; 1243 } 1244 1245 protected static class CollectedList extends LinkedList 1246 { 1247 int span; 1248 Bucket key; 1249 1250 CollectedList() 1251 { 1252 super(); 1253 1254 span = 0; 1255 } 1256 1257 public boolean add(Object o) 1258 { 1259 boolean added = super.add(o); 1260 1261 incrementSpan(o); 1262 1263 return added; 1264 } 1265 1266 public void addFirst(Object o) 1267 { 1268 super.addFirst(o); 1269 1270 incrementSpan(o); 1271 } 1272 1273 public void addLast(Object o) 1274 { 1275 super.add(o); 1276 1277 incrementSpan(o); 1278 } 1279 1280 private void incrementSpan(Object o) 1281 { 1282 if (o != null && o instanceof CollectedList) 1283 { 1284 span += ((CollectedList) o).span; 1285 } 1286 else 1287 { 1288 span += 1; 1289 } 1290 } 1291 1292 public String toString() 1293 { 1294 return key + "/" + span + ": " + super.toString(); 1295 } 1296 } 1297} 1298 | Popular Tags |