| /** |
| ******************************************************************************** |
| * Copyright (c) 2020 Eclipse APP4MC contributors. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.atdb.metrics; |
| |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.stream.IntStream; |
| |
| import org.eclipse.nebula.widgets.nattable.data.AutomaticSpanningDataProvider; |
| import org.eclipse.nebula.widgets.nattable.data.IDataProvider; |
| import org.eclipse.nebula.widgets.nattable.data.IRowDataProvider; |
| import org.eclipse.nebula.widgets.nattable.data.ISpanningDataProvider; |
| import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider; |
| import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider; |
| import org.eclipse.nebula.widgets.nattable.group.performance.RowGroupHeaderLayer; |
| import org.eclipse.nebula.widgets.nattable.layer.cell.DataCell; |
| |
| import com.google.common.collect.BiMap; |
| import com.google.common.collect.HashBasedTable; |
| import com.google.common.collect.HashBiMap; |
| import com.google.common.collect.Table; |
| |
| public final class DBResultRowDataProvider implements IRowDataProvider<List<String>>, ISpanningDataProvider { |
| |
| static DBResultRowDataProvider of(final ResultSet rs, final List<Integer> groupByColumnIndices) throws SQLException { |
| return new DBResultRowDataProvider(rs, groupByColumnIndices); |
| } |
| |
| private final int columnCount; |
| private final BiMap<Integer, List<String>> rowIndex2DataValue; |
| private final IDataProvider columnsHeaderDataProvider; |
| private final IDataProvider rowHeaderDataProvider; |
| private final ISpanningDataProvider rowSpanningDataProvider; |
| private final List<Integer> groupByColumnIndices; |
| |
| private DBResultRowDataProvider(final ResultSet rs, final List<Integer> groupByColumnIndices) throws SQLException { |
| this.rowIndex2DataValue = HashBiMap.create(); |
| final ResultSetMetaData rsmd = rs.getMetaData(); |
| final int colCount = rsmd.getColumnCount(); |
| final List<String> columneHeaderNames = new ArrayList<>(); |
| for(int i = 1; i <= colCount; i++) { |
| columneHeaderNames.add(rsmd.getColumnName(i)); |
| } |
| while (rs.next()) { |
| final List<String> resultRow = new ArrayList<>(); |
| for(int i = 1; i <= colCount; i++) { |
| resultRow.add(rs.getString(i)); |
| } |
| this.rowIndex2DataValue.put(rs.getRow() - 1, resultRow); |
| } |
| this.columnsHeaderDataProvider = new DefaultColumnHeaderDataProvider(columneHeaderNames.toArray(new String[colCount])); |
| this.rowSpanningDataProvider = new AutomaticSpanningDataProvider(this, false, true); |
| this.rowHeaderDataProvider = new DefaultRowHeaderDataProvider(this.rowSpanningDataProvider); |
| this.columnCount = colCount; |
| this.groupByColumnIndices = Collections.unmodifiableList(groupByColumnIndices); |
| } |
| |
| @Override |
| public String getDataValue(final int columnIndex, final int rowIndex) { |
| return this.rowIndex2DataValue.get(rowIndex).get(columnIndex); |
| } |
| |
| @Override |
| public void setDataValue(final int columnIndex, final int rowIndex, final Object newValue) { |
| throw new UnsupportedOperationException(Messages.DBViewer_immutableResultError); |
| } |
| |
| @Override |
| public int getColumnCount() { |
| return this.columnCount; |
| } |
| |
| @Override |
| public int getRowCount() { |
| return this.rowIndex2DataValue.size(); |
| } |
| |
| @Override |
| public List<String> getRowObject(final int rowIndex) { |
| return this.rowIndex2DataValue.get(rowIndex); |
| } |
| |
| @Override |
| public int indexOfRowObject(final List<String> rowObject) { |
| return this.rowIndex2DataValue.inverse().get(rowObject); |
| } |
| |
| public IDataProvider getColumnHeaderDataProvider() { |
| return this.columnsHeaderDataProvider; |
| } |
| |
| public IDataProvider getRowHeaderDataProvider() { |
| return this.rowHeaderDataProvider; |
| } |
| |
| public void initializeGroups(final RowGroupHeaderLayer rowGroupHeaderLayer) { |
| if (this.groupByColumnIndices.isEmpty()) { |
| // no groups to initialize |
| return; |
| } |
| IntStream.range(rowGroupHeaderLayer.getLevelCount(), this.groupByColumnIndices.size()).forEach(i -> rowGroupHeaderLayer.addGroupingLevel()); |
| Table<Integer, String, Integer> levelGroupTuple2StartIndex = HashBasedTable.create(); |
| Map<Integer, String> level2currentGroup = new LinkedHashMap<>(); |
| for(final Entry<Integer,List<String>> entry:this.rowIndex2DataValue.entrySet()) { |
| final int absIndex = entry.getKey(); |
| final List<String> row = entry.getValue(); |
| for(int level = 0; level < this.groupByColumnIndices.size(); level++) { |
| final int columnIndex = this.groupByColumnIndices.get(level); |
| final String groupCellValue = row.get(columnIndex); |
| if (!levelGroupTuple2StartIndex.contains(level, groupCellValue)) { |
| if (level2currentGroup.containsKey(level)) { |
| // current group ends here |
| final String currentGroupName = level2currentGroup.get(level); |
| final int startIndex = levelGroupTuple2StartIndex.get(level, currentGroupName); |
| rowGroupHeaderLayer.addGroup(level, currentGroupName, startIndex, absIndex - startIndex); |
| levelGroupTuple2StartIndex.remove(level, currentGroupName); |
| } |
| // new group starts here |
| level2currentGroup.put(level, groupCellValue); |
| levelGroupTuple2StartIndex.put(level, groupCellValue, absIndex); |
| } |
| } |
| } |
| for(int level = 0; level < this.groupByColumnIndices.size(); level++) { |
| if (level2currentGroup.containsKey(level)) { |
| // finish groups |
| final String currentGroupName = level2currentGroup.get(level); |
| final int startIndex = levelGroupTuple2StartIndex.get(level, currentGroupName); |
| rowGroupHeaderLayer.addGroup(level, currentGroupName, startIndex, this.rowIndex2DataValue.size() - startIndex); |
| levelGroupTuple2StartIndex.remove(level, currentGroupName); |
| } |
| } |
| } |
| |
| @Override |
| public DataCell getCellByPosition(int columnPosition, int rowPosition) { |
| return this.rowSpanningDataProvider.getCellByPosition(columnPosition, rowPosition); |
| } |
| |
| } |