blob: 4e90ad7d655022032291027e6de6344c40da9e0b [file] [log] [blame]
/**
********************************************************************************
* 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);
}
}