1 16 17 package org.pentaho.core.connection; 18 19 import java.text.Format ; 20 import java.text.MessageFormat ; 21 import java.util.ArrayList ; 22 import java.util.Collection ; 23 import java.util.HashMap ; 24 import java.util.Iterator ; 25 import java.util.LinkedList ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.TreeMap ; 29 import org.apache.commons.collections.map.ListOrderedMap; 30 import org.pentaho.core.connection.memory.MemoryMetaData; 31 import org.pentaho.core.connection.memory.MemoryResultSet; 32 import org.pentaho.messages.Messages; 33 34 42 public class PentahoDataTransmuter extends DataUtilities { 43 protected final IPentahoResultSet sourceResultSet; 44 45 public PentahoDataTransmuter(IPentahoResultSet resultSet) { 46 super(); 47 sourceResultSet = resultSet; 48 } 49 50 53 public IPentahoResultSet getSourceResultSet() { 54 return sourceResultSet; 55 } 56 57 public static IPentahoResultSet transmute(IPentahoResultSet source, boolean pivot) { 58 return transmute(source, (Integer ) null, null, null, null, pivot); 59 } 60 61 public static IPentahoResultSet transmute(IPentahoResultSet source, Integer columnForRowHeaders, Integer rowForColumnHeaders, boolean pivot) { 62 return transmute(source, columnForRowHeaders, rowForColumnHeaders, null, null, pivot); 63 } 64 65 public IPentahoResultSet transmute(Integer columnForRowHeaders, Integer rowForColumnHeaders, boolean pivot) { 66 return transmute(sourceResultSet, columnForRowHeaders, rowForColumnHeaders, null, null, pivot); 67 } 68 69 public static IPentahoResultSet transmute(IPentahoResultSet source, String [] columnForRowHeaders, String [] rowForColumnHeaders, boolean pivot) { 70 return transmute(source, columnForRowHeaders, rowForColumnHeaders, null, null, pivot); 71 } 72 73 public IPentahoResultSet transmute(String [] columnForRowHeaders, String [] rowForColumnHeaders, boolean pivot) { 74 return transmute(sourceResultSet, columnForRowHeaders, rowForColumnHeaders, null, null, pivot); 75 } 76 77 public static IPentahoResultSet transmute(IPentahoResultSet source, Integer [] rowsToInclude, Integer [] columnsToInclude, boolean pivot) { 78 return transmute(source, null, null, rowsToInclude, columnsToInclude, pivot); 79 } 80 81 public IPentahoResultSet transmute(Integer [] rowsToInclude, Integer [] columnsToInclude, boolean pivot) { 82 return transmute(sourceResultSet, null, null, rowsToInclude, columnsToInclude, pivot); 83 } 84 85 public static IPentahoResultSet transmute(IPentahoResultSet source, String [][] rowsToInclude, String [][] columnsToInclude, boolean pivot) { 86 return transmute(source, null, null, rowsToInclude, columnsToInclude, pivot); 87 } 88 89 public IPentahoResultSet transmute(String [][] rowsToInclude, String [][] columnsToInclude, boolean pivot) { 90 return transmute(sourceResultSet, null, null, rowsToInclude, columnsToInclude, pivot); 91 } 92 93 public IPentahoResultSet transmute(String [] columnForRowHeaders, String [] rowForColumnHeaders, String [][] rowsToInclude, String [][] columnsToInclude, boolean pivot) { 94 return transmute(sourceResultSet, columnForRowHeaders, rowForColumnHeaders, rowsToInclude, columnsToInclude, pivot); 95 } 96 97 125 public static IPentahoResultSet transmute(IPentahoResultSet source, String [] columnForRowHeaders, String [] rowForColumnHeaders, String [][] rowsToInclude, String [][] columnsToInclude, boolean pivot) { 126 Integer cfrh = null; 127 if (columnForRowHeaders != null) { 128 String [][] searchStrings = new String [1][]; 129 searchStrings[0] = columnForRowHeaders; 130 Integer [] indexes = columnNamesToIndexes(source, searchStrings); 131 if (indexes.length > 0) { 132 cfrh = indexes[0]; 133 } 134 } 135 Integer rfch = null; 136 if (rowForColumnHeaders != null) { 137 String [][] searchStrings = new String [1][]; 138 searchStrings[0] = rowForColumnHeaders; 139 Integer [] indexes = rowNamesToIndexes(source, searchStrings); 140 if (indexes.length > 0) { 141 rfch = indexes[0]; 142 } 143 } 144 Integer [] rti = null; 145 if (rowsToInclude != null) { 146 rti = rowNamesToIndexes(source, rowsToInclude); 147 } 148 Integer [] cti = null; 149 if (columnsToInclude != null) { 150 cti = columnNamesToIndexes(source, columnsToInclude); 151 } 152 return transmute(source, cfrh, rfch, rti, cti, pivot); 153 } 154 155 public IPentahoResultSet transmute(Integer columnForRowHeaders, Integer rowForColumnHeaders, Integer [] rowsToInclude, Integer [] columnsToInclude, boolean pivot) { 156 return transmute(sourceResultSet, columnForRowHeaders, rowForColumnHeaders, rowsToInclude, columnsToInclude, pivot); 157 } 158 159 185 public static IPentahoResultSet transmute(IPentahoResultSet source, Integer columnForRowHeaders, Integer rowForColumnHeaders, Integer [] rowsToInclude, Integer [] columnsToInclude, boolean pivot) { 186 Object [][] rowHeaders = null; 187 Object [][] columnHeaders = null; 188 189 rowHeaders = constructRowHeaders(source, columnForRowHeaders); 191 columnHeaders = constructColumnHeaders(source, rowForColumnHeaders); 192 rowHeaders = DataUtilities.filterDataByRows(rowHeaders, rowsToInclude); 194 columnHeaders = DataUtilities.filterDataByColumns(columnHeaders, columnsToInclude); 195 source.beforeFirst(); List dataList = new ArrayList (); 198 Object [] rowData = source.next(); 199 while (rowData != null) { 200 dataList.add(rowData); 201 rowData = source.next(); 202 } 203 Object [][] data = null; 204 if (columnHeaders != null) { 205 data = new Object [dataList.size()][columnHeaders[0].length]; 206 for (int row = 0; row < data.length; row++) { 207 data[row] = (Object []) dataList.get(row); 208 } 209 } 210 data = DataUtilities.filterData(data, rowsToInclude, columnsToInclude); 212 IPentahoResultSet result = new MemoryResultSet(new MemoryMetaData(columnHeaders, rowHeaders)); if (data != null) { 218 for (int row = 0; row < data.length; row++) { 219 ((MemoryResultSet) result).addRow(data[row]); 220 } 221 } 222 if (pivot) { 224 result = pivot(result); 225 } 226 return result; 227 } 228 229 public IPentahoResultSet pivot() { 230 return pivot(sourceResultSet); 231 } 232 233 267 public static IPentahoResultSet pivot(IPentahoResultSet resultSet) { 268 MemoryResultSet result = new MemoryResultSet(swapAndPivotRowAndColumnHeaders(resultSet.getMetaData())); 269 270 Object [][] dataValues = new Object [resultSet.getRowCount()][resultSet.getColumnCount()]; 272 for (int row = 0; row < resultSet.getRowCount(); row++) { 273 Object [] dataRow = resultSet.next(); 274 for (int column = 0; column < resultSet.getColumnCount(); column++) { 275 dataValues[row][column] = dataRow[column]; 276 } 277 } 278 dataValues = DataUtilities.pivotDimensions(dataValues); 280 for (int row = 0; row < dataValues.length; row++) { 281 result.addRow(dataValues[row]); 282 } 283 return result; 284 } 285 286 public Integer [] rowNamesToIndexes(String [][] names) { 287 return rowNamesToIndexes(sourceResultSet, names); 288 } 289 290 300 public static Integer [] rowNamesToIndexes(IPentahoResultSet source, String [][] names) { 301 List result = new ArrayList (); 302 for (int row = 0; row < names.length; row++) { 303 int found = source.getMetaData().getRowIndex(names[row]); 304 if (found != -1) { 305 result.add(new Integer (found)); 306 } 307 } 308 Integer [] resultArray = new Integer [result.size()]; 309 for (int i = 0; i < resultArray.length; i++) { 310 resultArray[i] = (Integer ) result.get(i); 311 } 312 return resultArray; 313 } 314 315 public Integer [] columnNamesToIndexes(String [][] names) { 316 return columnNamesToIndexes(sourceResultSet, names); 317 } 318 319 329 public static Integer [] columnNamesToIndexes(IPentahoResultSet source, String [][] names) { 330 List result = new ArrayList (); 331 for (int row = 0; row < names.length; row++) { 332 int found = source.getMetaData().getColumnIndex(names[row]); 333 if (found != -1) { 334 result.add(new Integer (found)); 335 } 336 } 337 Integer [] resultArray = new Integer [result.size()]; 338 for (int i = 0; i < resultArray.length; i++) { 339 resultArray[i] = (Integer ) result.get(i); 340 } 341 return resultArray; 342 } 343 344 349 protected static Object [][] constructColumnHeaders(IPentahoResultSet source, Integer rowForColumnHeaders) { 350 Object [][] result = null; 351 if (rowForColumnHeaders == null) { if (source.getMetaData().getColumnHeaders() == null) { Object [] dataRow = source.getDataRow(0); if (dataRow != null) { 359 result = new Object [1][]; 360 result[0] = dataRow; 361 } 362 } else { result = source.getMetaData().getColumnHeaders(); 364 } 365 } else { Object [] dataRow = source.getDataRow(rowForColumnHeaders.intValue()); 367 if (dataRow != null) { 368 result = new Object [1][]; 369 result[0] = dataRow; 370 } 371 } 372 return result; 373 } 374 375 388 protected static Object [][] constructRowHeaders(IPentahoResultSet source, Integer columnForRowHeaders) { 389 Object [][] result = null; 390 if (columnForRowHeaders == null) { if (source.getMetaData().getRowHeaders() == null) { Object [] dataColumn = source.getDataColumn(0); result = new Object [dataColumn.length][1]; 398 for (int row = 0; row < result.length; row++) { 399 result[row][0] = dataColumn[row]; 400 } 401 } else { result = source.getMetaData().getRowHeaders(); 403 } 404 } else { Object [] dataColumn = source.getDataColumn(columnForRowHeaders.intValue()); result = new Object [dataColumn.length][1]; 410 for (int row = 0; row < result.length; row++) { 411 result[row][0] = dataColumn[row]; 412 } 413 } 414 return result; 415 } 416 417 423 protected static IPentahoMetaData swapAndPivotRowAndColumnHeaders(IPentahoMetaData metaData) { 424 Object [][] sourceColumnHeaders = metaData.getColumnHeaders(); 425 Object [][] sourceRowHeaders = metaData.getRowHeaders(); 426 boolean hasColumnHeaders = sourceColumnHeaders != null; 427 boolean hasRowHeaders = sourceRowHeaders != null; 428 429 Object [][] columnHeaders = null; 430 Object [][] rowHeaders = null; 431 432 if (hasColumnHeaders) { 433 rowHeaders = DataUtilities.pivotDimensions(sourceColumnHeaders); 434 } 435 436 if (hasRowHeaders) { 437 columnHeaders = DataUtilities.pivotDimensions(sourceRowHeaders); 438 } 439 440 MemoryMetaData result = new MemoryMetaData(columnHeaders, rowHeaders); 441 return result; 442 } 443 444 private static String [] getCollapsedRowHeaders(IPentahoResultSet resultSet, char seperator) { 445 Object [][] rowHeaders = resultSet.getMetaData().getRowHeaders(); 446 if (rowHeaders != null) { 447 StringBuffer [] resultBuffer = new StringBuffer [rowHeaders.length]; 448 for (int i = 0; i < resultBuffer.length; i++) { 449 resultBuffer[i] = new StringBuffer (); 450 } 451 for (int row = 0; row < rowHeaders.length; row++) { 452 for (int col = 0; col < rowHeaders[row].length; col++) { 453 if (col == 0) { resultBuffer[row].append(rowHeaders[row][col].toString()); 455 } else { resultBuffer[row].append(seperator + rowHeaders[row][col].toString()); 457 } 458 } 459 } 460 String [] result = new String [resultBuffer.length]; 461 for (int i = 0; i < resultBuffer.length; i++) { 462 result[i] = resultBuffer[i].toString(); 463 } 464 return result; 465 } 466 return null; 467 } 468 469 private static String [] getCollapsedColumnHeaders(IPentahoResultSet resultSet, char seperator) { 470 Object [][] columnHeaders = resultSet.getMetaData().getColumnHeaders(); 471 if (columnHeaders != null) { 472 StringBuffer [] resultBuffer = new StringBuffer [columnHeaders[0].length]; 473 for (int i = 0; i < resultBuffer.length; i++) { 474 resultBuffer[i] = new StringBuffer (); 475 } 476 for (int col = 0; col < columnHeaders[0].length; col++) { for (int row = 0; row < columnHeaders.length; row++) { if (row == 0) { resultBuffer[col].append(columnHeaders[row][col].toString()); 487 } else { resultBuffer[col].append(seperator + columnHeaders[row][col].toString()); 489 } 490 } 491 } 492 String [] result = new String [resultBuffer.length]; 493 for (int i = 0; i < resultBuffer.length; i++) { 494 result[i] = resultBuffer[i].toString(); 495 } 496 return result; 497 } 498 return null; 499 } 500 501 public String [] getCollapsedHeaders(int axis, char seperator) throws Exception { 502 return getCollapsedHeaders(axis, sourceResultSet, seperator); 503 } 504 505 520 public static String [] getCollapsedHeaders(int axis, IPentahoResultSet resultSet, char seperator) throws Exception { 521 if (axis != AXIS_COLUMN && axis != AXIS_ROW) { 522 throw new IllegalArgumentException (Messages.getString("PentahoDataTransmuter.ERROR_0001_INVALID_AXIS")); } 524 if (resultSet == null) { 525 throw new IllegalArgumentException (Messages.getString("PentahoDataTransmuter.ERROR_0002_NULL_DATASET")); } 527 528 switch (axis) { 529 case AXIS_COLUMN: 530 return getCollapsedColumnHeaders(resultSet, seperator); 531 532 case AXIS_ROW: 533 return getCollapsedRowHeaders(resultSet, seperator); 534 535 } 536 return null; 537 } 538 539 547 public static IPentahoResultSet flattenResultSet(IPentahoResultSet resultSet, int squashColumn) { 548 IPentahoResultSet flattenedResultSet = resultSet.memoryCopy(); 549 if (flattenedResultSet instanceof MemoryResultSet) { 550 MemoryResultSet memoryResultSet = (MemoryResultSet) flattenedResultSet; 551 Object colHeads[][] = memoryResultSet.getMetaData().getColumnHeaders(); 558 559 int rowCount = memoryResultSet.getRowCount(); 560 int colCount = memoryResultSet.getColumnCount(); 561 Object squashColumnValue = memoryResultSet.getValueAt(0, squashColumn); 562 Object squashedRow[] = new Object [colCount]; 563 List rowsList = new LinkedList (); 564 rowsList.add(squashedRow); 565 for (int row = 0; row < rowCount; row++) { 566 Object newSquashColumnValue = memoryResultSet.getValueAt(row, squashColumn); 567 if (newSquashColumnValue.equals(squashColumnValue)) { 568 } else { 570 squashedRow = new Object [colCount]; 572 rowsList.add(squashedRow); 573 } 574 squashColumnValue = newSquashColumnValue; 575 for (int col = 0; col < colCount; col++) { 576 Object potentialValue = memoryResultSet.getValueAt(row, col); 578 if (potentialValue != null && !potentialValue.toString().equals("")) { squashedRow[col] = potentialValue; 581 } 582 } 583 } 584 Object rows[][] = new Object [rowsList.size()][colCount]; 585 for (int i = 0; i < rowsList.size(); i++) { 586 rows[i] = (Object []) rowsList.get(i); 587 } 588 return MemoryResultSet.createFromArrays(colHeads, rows); 589 } 590 return flattenedResultSet; 591 } 592 593 public static String dump(IPentahoResultSet source) { 594 return dump(source, true); 595 } 596 597 public static String dump(IPentahoResultSet source, boolean useOrBar) { 598 StringBuffer sb = new StringBuffer (); 599 String orBar = ""; if (useOrBar) { 601 orBar = "|"; } 603 source.beforeFirst(); 604 Object [][] columnHeaders = source.getMetaData().getColumnHeaders(); 605 Object [][] rowHeaders = source.getMetaData().getRowHeaders(); 606 String formatString = ""; if (rowHeaders != null) { 608 for (int columns = 0; columns < rowHeaders[0].length; columns++) { 609 formatString = formatString + "\t\t"; } 611 } 612 if (columnHeaders != null) { 613 for (int row = columnHeaders.length - 1; row >= 0; row--) { 614 sb.append(formatString); 615 for (int column = 0; column < columnHeaders[row].length; column++) { 616 sb.append(columnHeaders[row][column] + orBar + "\t"); } 618 sb.append('\n'); 619 } 620 } 621 if (rowHeaders != null) { 622 for (int row = 0; row < rowHeaders.length; row++) { 623 for (int column = rowHeaders[row].length - 1; column >= 0; column--) { 624 sb.append(rowHeaders[row][column] + orBar + "\t"); } 626 Object [] dataRow = source.next(); 627 for (int column = 0; column < dataRow.length; column++) { 628 sb.append(dataRow[column] + orBar + "\t"); } 630 sb.append('\n'); 631 } 632 } else { 633 Object [] dataRow = source.next(); 634 while (dataRow != null) { 635 for (int column = 0; column < dataRow.length; column++) { 636 sb.append(dataRow[column] + orBar + "\t"); } 638 sb.append('\n'); 639 dataRow = source.next(); 640 } 641 } 642 sb.append('\n'); 643 644 source.beforeFirst(); 645 return sb.toString(); 646 } 647 648 public static IPentahoResultSet crossTab(IPentahoResultSet source, int columnToPivot, int measureColumn, Format pivotDataFormatter) { 649 return crossTab(source, columnToPivot, measureColumn, pivotDataFormatter, true); 650 } 651 652 653 703 public static IPentahoResultSet crossTab(IPentahoResultSet source, int columnToPivot, int measureColumn, Format pivotDataFormatter, boolean orderedMaps) { 704 return crossTab(source, columnToPivot, measureColumn, -1, pivotDataFormatter, null, orderedMaps); 705 } 706 707 775 public static IPentahoResultSet crossTab(IPentahoResultSet source, int columnToPivot, int measureColumn, int columnToSortColumnsBy, Format pivotDataFormatter, Format sortDataFormatter, boolean orderedMaps) { 776 777 780 if (source == null) { 782 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0002_NULL_DATASET")); } 784 int sourceColumnCount = source.getColumnCount(); 785 if (columnToPivot > sourceColumnCount) { 786 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0003_INVALID_PIVOT_COLUMN")); } 788 if (measureColumn > sourceColumnCount) { 789 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0004_INVALID_MEASURE_COLUMN")); } 791 if (columnToSortColumnsBy > sourceColumnCount) { 792 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0004_INVALID_SORT_COLUMN")); } 794 final String sortPrefixSeparator = "\t"; Map rowMap = null, newHeadersMap = null; 797 798 if (columnToSortColumnsBy >= 0) { 802 orderedMaps = true; 803 } 804 805 if (orderedMaps) { 806 rowMap = new TreeMap (); newHeadersMap = new TreeMap (); } else { 810 rowMap = ListOrderedMap.decorate(new HashMap ()); 813 newHeadersMap = ListOrderedMap.decorate(new HashMap ()); 814 } 815 List columnHeaders = new ArrayList (); IPentahoMetaData origMetaData = source.getMetaData(); 818 Object [][] origColHeaders = origMetaData.getColumnHeaders(); 819 for (int i = 0; i < origColHeaders[0].length; i++) { 820 if ((i != columnToPivot) && (i != measureColumn)) { 821 columnHeaders.add(origColHeaders[0][i].toString()); 822 } 823 } 824 Object colPivotData, colMeasureData, cellData, colToSortByRaw; 827 Object [] rowData = source.next(); 828 String columnPrefix = null; 829 Map currentMap = null; 830 while (rowData != null) { 831 colPivotData = rowData[columnToPivot]; if (colPivotData == null) { 833 throw new IllegalArgumentException (Messages.getString("PentahoDataTransmuter.ERROR_0006_CANNOT_PIVOT_NULL_DATA")); } 835 colMeasureData = rowData[measureColumn]; if (columnToSortColumnsBy >= 0) { 838 colToSortByRaw = rowData[columnToSortColumnsBy]; 839 if (colToSortByRaw == null) { 840 throw new IllegalArgumentException (Messages.getString("PentahoDataTransmuter.ERROR_0007_CANNOT_SORT_NULL_DATA")); } 842 if (sortDataFormatter != null) { 843 columnPrefix = sortDataFormatter.format(colToSortByRaw); 844 } else { 845 columnPrefix = colToSortByRaw.toString(); 846 } 847 } 848 currentMap = rowMap; for (int i = 0; i < rowData.length; i++) { 850 if ((i != columnToPivot) && (i != measureColumn) && (i != columnToSortColumnsBy)) { 851 cellData = currentMap.get(rowData[i]); 854 if (cellData == null) { 855 Map newColumnMap = null; 857 if (orderedMaps) { 858 newColumnMap = new TreeMap (); 859 } else { 860 newColumnMap = ListOrderedMap.decorate(new HashMap ()); 861 } 862 863 currentMap.put(rowData[i], newColumnMap); 864 currentMap = newColumnMap; 865 } else { 866 currentMap = (Map ) cellData; 868 } 869 } 870 } 871 String formattedPivotData = null; 874 if (pivotDataFormatter != null) { 875 if (pivotDataFormatter instanceof MessageFormat ) { 876 formattedPivotData = pivotDataFormatter.format(new Object [] { colPivotData }); 877 } else { 878 formattedPivotData = pivotDataFormatter.format(colPivotData); 879 } 880 } else { 881 formattedPivotData = colPivotData.toString(); 882 } 883 if (columnToSortColumnsBy >= 0) { 885 formattedPivotData = columnPrefix + sortPrefixSeparator + formattedPivotData; 886 } 887 Object header = newHeadersMap.get(formattedPivotData); 889 if (header == null) { 890 newHeadersMap.put(formattedPivotData, ""); } 893 currentMap.put(formattedPivotData, colMeasureData); 895 rowData = source.next(); 897 } 898 Iterator hIt = newHeadersMap.keySet().iterator(); 900 while (hIt.hasNext()) { 901 columnHeaders.add(hIt.next().toString()); 902 } 903 904 ArrayList rows = new ArrayList (); 906 Collection uniqueItems = rowMap.keySet(); 908 Iterator it = uniqueItems.iterator(); 911 List newCurRow = new ArrayList (); 912 while (it.hasNext()) { 913 recurseCreateRow(it.next(), rowMap, rows, newCurRow, newHeadersMap); 915 newCurRow.clear(); 916 } 917 918 if (columnToSortColumnsBy >= 0) { 922 String aHeader; 923 int tabIdx; 924 for (int i = 0; i < columnHeaders.size(); i++) { 925 aHeader = (String ) columnHeaders.get(i); 926 tabIdx = aHeader.indexOf(sortPrefixSeparator); 927 if (tabIdx >= 0) { 928 columnHeaders.set(i, aHeader.substring(tabIdx + 1)); 929 } 930 } 931 } 932 IPentahoResultSet result = MemoryResultSet.createFromLists(columnHeaders, rows); 934 return result; 937 } 938 939 private static List recurseCreateRow(Object lookup, Map mapToLookupIn, List rows, List curRow, Map newColumnsMap) { 940 if (curRow == null) { 942 curRow = new ArrayList (); 944 } 945 Object value = mapToLookupIn.get(lookup); 947 948 if (value == null) { 949 curRow.add(null); 952 return null; 953 } else { 954 if (value instanceof Map ) { 957 curRow.add(lookup); 960 Map newLkupMap = (Map ) value; Collection uniqueItems = newLkupMap.keySet(); Iterator it = uniqueItems.iterator(); 968 Object obj = it.next(); 972 if (newColumnsMap.get(obj.toString()) != null) { 973 it = newColumnsMap.keySet().iterator(); 974 } else { 975 it = uniqueItems.iterator(); 976 } 977 List beforeValues = new ArrayList (curRow); 980 beforeValues.remove(beforeValues.size() - 1); 981 List addedValues = null; 983 while (it.hasNext()) { 986 addedValues = recurseCreateRow(it.next(), newLkupMap, rows, curRow, newColumnsMap); 988 if (addedValues != null) { 989 curRow.clear(); 991 curRow.addAll(addedValues); 992 } 993 } 994 if (addedValues == null) { 998 if (curRow.size() > newColumnsMap.size()) { 999 rows.add(new ArrayList (curRow)); 1000 } 1001 return beforeValues; 1002 } else { 1003 curRow.clear(); 1005 curRow.addAll(beforeValues); 1006 return null; 1007 } 1008 } else { 1009 curRow.add(value); 1012 return null; 1013 } 1014 } 1015 } 1016 1017 private static boolean isEqual(Object a, Object b) { 1018 if ( (a==null) && (b == null)) { 1019 return true; 1020 } else if ( (a == null) || (b == null) ) { 1021 return false; 1022 } else { 1023 return a.equals(b); 1024 } 1025 } 1026 1027 private static boolean isNewRow(Object [] thisRow, Object [] lastRow) { 1028 for(int i=0; i<thisRow.length; i++) { 1029 if (!isEqual(thisRow[i], lastRow[i])) { 1030 return true; 1031 } 1032 } 1033 return false; 1034 } 1035 1036 private static String formatPivotData(Object colPivotData, Format pivotDataFormatter) { 1037 String formattedPivotData = null; 1038 if (pivotDataFormatter != null) { 1039 if (pivotDataFormatter instanceof MessageFormat ) { 1040 formattedPivotData = pivotDataFormatter.format(new Object [] { colPivotData }); 1041 } else { 1042 formattedPivotData = pivotDataFormatter.format(colPivotData); 1043 } 1044 } else { 1045 formattedPivotData = colPivotData.toString(); 1046 } 1047 return formattedPivotData; 1048 } 1049 1050 1147 1148 public static IPentahoResultSet crossTabOrdered(IPentahoResultSet source, int columnToPivot, int measureColumn, Format pivotDataFormatter) { 1149 return crossTabOrdered(source, columnToPivot, measureColumn, pivotDataFormatter, true); 1150 } 1151 1152 public static IPentahoResultSet crossTabOrdered(IPentahoResultSet source, int columnToPivot, int measureColumn, Format pivotDataFormatter, boolean orderedMaps) { 1153 return crossTabOrdered(source, columnToPivot, measureColumn, -1, pivotDataFormatter, null, orderedMaps, -1); 1154 } 1155 1156 public static IPentahoResultSet crossTabOrdered(IPentahoResultSet source, 1157 int columnToPivot, 1158 int measureColumn, 1159 int columnToSortColumnsBy, 1160 Format pivotDataFormatter, 1161 Format sortDataFormatter, 1162 boolean orderedMaps, 1163 int uniqueRowIdentifierColumn) { 1164 1165 1168 if (source == null) { 1170 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0002_NULL_DATASET")); } 1172 int sourceColumnCount = source.getColumnCount(); 1173 if (columnToPivot > sourceColumnCount) { 1174 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0003_INVALID_PIVOT_COLUMN")); } 1176 if (measureColumn > sourceColumnCount) { 1177 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0004_INVALID_MEASURE_COLUMN")); } 1179 if (columnToSortColumnsBy > sourceColumnCount) { 1180 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0004_INVALID_SORT_COLUMN")); } 1182 if (uniqueRowIdentifierColumn > sourceColumnCount) { 1183 throw new IllegalArgumentException (Messages.getErrorString("PentahoDataTransmuter.ERROR_0008_INVALID_UNIQUE_COLUMN")); } 1185 1186 final String sortPrefixSeparator = "\t"; Map newHeadersMap = null; 1189 1190 Map uniqueColumnIdentifierMap = null; 1191 1192 if (uniqueRowIdentifierColumn >=0) { 1193 uniqueColumnIdentifierMap = new HashMap (); 1194 } 1195 1196 int uniqueRowIdentifierColumnPostShift = -1; 1197 1198 if (columnToSortColumnsBy >= 0) { 1202 orderedMaps = true; 1203 } 1204 1205 if (orderedMaps) { 1206 newHeadersMap = new TreeMap (); } else { 1209 newHeadersMap = ListOrderedMap.decorate(new HashMap ()); 1212 } 1213 List columnHeaders = new ArrayList (); IPentahoMetaData origMetaData = source.getMetaData(); 1216 Object [][] origColHeaders = origMetaData.getColumnHeaders(); 1217 1218 for (int i = 0; i < origColHeaders[0].length; i++) { 1219 if ((i != columnToPivot) && (i != measureColumn) && ((i != columnToSortColumnsBy)) ) { 1220 columnHeaders.add(origColHeaders[0][i].toString()); 1221 if (i == uniqueRowIdentifierColumn) { 1222 uniqueRowIdentifierColumnPostShift = columnHeaders.size()-1; 1223 } 1224 } 1225 } 1226 int baseColumnsCount = columnHeaders.size(); 1227 Object colPivotData, colMeasureData, colToSortByRaw; 1230 Object [] rowData = source.next(); 1231 String columnPrefix = null; 1232 1233 1234 1240 Map newColumnHeadersRaw = new HashMap (); 1241 Integer placeHolder = new Integer (0); 1242 while (rowData != null) { 1243 colPivotData = rowData[columnToPivot]; if (colPivotData == null) { 1245 throw new IllegalArgumentException (Messages.getString("PentahoDataTransmuter.ERROR_0006_CANNOT_PIVOT_NULL_DATA")); } 1247 1248 if (columnToSortColumnsBy >= 0) { 1250 colToSortByRaw = rowData[columnToSortColumnsBy]; 1251 if (colToSortByRaw == null) { 1252 throw new IllegalArgumentException (Messages.getString("PentahoDataTransmuter.ERROR_0007_CANNOT_SORT_NULL_DATA")); } 1254 if (sortDataFormatter != null) { 1255 columnPrefix = sortDataFormatter.format(colToSortByRaw); 1256 } else { 1257 columnPrefix = colToSortByRaw.toString(); 1258 } 1259 } 1260 1261 if (!newColumnHeadersRaw.containsKey(colPivotData)) { 1262 newColumnHeadersRaw.put(colPivotData, placeHolder); 1263 String formattedPivotData = formatPivotData(colPivotData, pivotDataFormatter); 1265 if (columnToSortColumnsBy >= 0) { 1266 formattedPivotData = columnPrefix + sortPrefixSeparator + formattedPivotData; 1267 } 1268 newHeadersMap.put(formattedPivotData, colPivotData ); 1269 } 1270 1271 rowData = source.next(); 1272 } 1273 source.beforeFirst(); 1274 1275 1278 Iterator it = newHeadersMap.entrySet().iterator(); 1279 int columnIndex = columnHeaders.size(); while (it.hasNext()) { 1281 Map.Entry me = (Map.Entry )it.next(); 1282 newColumnHeadersRaw.put(me.getValue(), new Integer (columnIndex)); 1283 columnHeaders.add(formatPivotData(me.getValue(), pivotDataFormatter)); 1284 columnIndex++; 1285 } 1286 1287 1290 int columnCount = columnHeaders.size(); 1291 int rowPos; 1292 MemoryResultSet mrs = new MemoryResultSet(); 1293 MemoryMetaData md = new MemoryMetaData(columnHeaders); 1294 mrs.setMetaData(md); 1295 Object [] thisRow = new Object [baseColumnsCount]; 1296 1297 Object [] currentRow = new Object [columnCount]; 1298 rowData = source.next(); 1299 boolean isFirstRow = true; 1300 while (rowData != null) { 1301 colMeasureData = rowData[measureColumn]; rowPos = 0; 1303 for (int i = 0; i < rowData.length; i++) { 1304 if ((i != columnToPivot) && (i != measureColumn) && (i != columnToSortColumnsBy)) { 1305 thisRow[rowPos] = rowData[i]; 1307 rowPos++; 1308 } 1309 } 1310 1313 boolean newRow = true; 1314 1315 Object uniqueRowIdentifierValue = null; 1316 Integer previousRowNumber = null; 1317 1318 if (uniqueRowIdentifierColumn>=0) { 1320 uniqueRowIdentifierValue = rowData[uniqueRowIdentifierColumn]!=null?rowData[uniqueRowIdentifierColumn]:"_NULL_VALUE_"; previousRowNumber = (Integer )uniqueColumnIdentifierMap.get(uniqueRowIdentifierValue); 1322 if (previousRowNumber != null) { 1323 addIfNeeded(currentRow, mrs, uniqueColumnIdentifierMap, uniqueRowIdentifierColumnPostShift); 1324 currentRow = mrs.getDataRow(previousRowNumber.intValue()); 1325 newRow = false; 1326 } 1327 } 1328 1329 newRow = (newRow && !isFirstRow && isNewRow(thisRow, currentRow)); 1330 if (newRow) { 1331 addIfNeeded(currentRow, mrs, uniqueColumnIdentifierMap, uniqueRowIdentifierColumnPostShift); 1332 currentRow = new Object [columnCount]; 1334 System.arraycopy(thisRow, 0, currentRow, 0, thisRow.length); 1336 } else if (isFirstRow) { 1337 System.arraycopy(thisRow, 0, currentRow, 0, thisRow.length); 1338 } 1339 isFirstRow = false; 1340 colPivotData = rowData[columnToPivot]; Integer targetColumn = (Integer )newColumnHeadersRaw.get(colPivotData); 1342 currentRow[targetColumn.intValue()] = colMeasureData; 1343 1344 rowData = source.next(); 1346 } 1347 addIfNeeded(currentRow, mrs, uniqueColumnIdentifierMap, uniqueRowIdentifierColumnPostShift); 1348 return mrs; 1351 } 1352 1353 private static void addIfNeeded(Object [] currentRow, MemoryResultSet mrs, Map uniqueColumnIdentifierMap, int uniqueRowIdentifierColumnPostShift) { 1354 if (uniqueRowIdentifierColumnPostShift >=0) { 1355 Object tmpValue = currentRow[uniqueRowIdentifierColumnPostShift]!=null?currentRow[uniqueRowIdentifierColumnPostShift]:"_NULL_VALUE_"; if (!uniqueColumnIdentifierMap.containsKey(tmpValue)) { 1357 int addedRow = mrs.addRow(currentRow); 1358 uniqueColumnIdentifierMap.put(tmpValue, new Integer (addedRow)); 1359 } 1360 } else { 1361 mrs.addRow(currentRow); 1362 } 1363 } 1364 1365} 1366 | Popular Tags |