blob: fc0b9fdb2bd962e2f20a5f4dd7b42ab868287c53 [file] [log] [blame]
package autotest.tko;
import autotest.common.StatusSummary;
import autotest.common.spreadsheet.Spreadsheet;
import autotest.common.spreadsheet.Spreadsheet.CellInfo;
import autotest.common.spreadsheet.Spreadsheet.Header;
import autotest.common.spreadsheet.Spreadsheet.HeaderImpl;
import autotest.common.table.DataSource.DataCallback;
import autotest.common.table.DataSource.Query;
import autotest.common.ui.NotifyManager;
import com.google.gwt.core.client.Duration;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.IncrementalCommand;
import java.util.ArrayList;
import java.util.List;
public class SpreadsheetDataProcessor implements DataCallback {
private static final NotifyManager notifyManager = NotifyManager.getInstance();
private static final int MAX_CELL_COUNT = 500000;
private static final int ROWS_PROCESSED_PER_ITERATION = 1000;
private Spreadsheet spreadsheet;
private TestGroupDataSource dataSource;
private int numTotalTests;
private CellInfo lastCellInfo;
private Header rowFields, columnFields;
private Command onFinished;
private Duration timer;
private Query currentQuery;
public static class TooManyCellsError extends Exception {
public int cellCount;
public TooManyCellsError(int cellCount) {
super();
this.cellCount = cellCount;
}
}
private class ProcessDataCommand implements IncrementalCommand {
private int state = 0;
private List<JSONObject> counts;
private int currentRow = 0;
public ProcessDataCommand(List<JSONObject> counts) {
this.counts = counts;
}
public void processSomeRows() {
for (int i = 0; i < ROWS_PROCESSED_PER_ITERATION; i++, currentRow++) {
if (currentRow == counts.size()) {
state++;
return;
}
processRow(counts.get(currentRow).isObject());
}
}
public boolean execute() {
switch (state) {
case 0:
notifyManager.setLoading(true);
numTotalTests = 0;
try {
processHeaders();
} catch (TooManyCellsError exc) {
notifyManager.showError("Resulting spreadsheet contains " + exc.cellCount +
" cells, " + "exceeding maximum " + MAX_CELL_COUNT);
finalizeCommand();
return false;
}
break;
case 1:
spreadsheet.prepareForData();
break;
case 2:
processSomeRows();
return true;
case 3:
// we must make the spreadsheet visible before rendering, or size computations
// won't work correctly
spreadsheet.setVisible(true);
break;
case 4:
spreadsheet.render(this);
state++;
return false; // render will re-add us to the command queue
case 5:
logTimer("Rendering");
finalizeCommand();
return false;
}
state++;
return true;
}
private void finalizeCommand() {
notifyManager.setLoading(false);
onFinished.execute();
}
}
public SpreadsheetDataProcessor(Spreadsheet spreadsheet) {
this.spreadsheet = spreadsheet;
}
public void processHeaders() throws TooManyCellsError {
spreadsheet.setHeaderFields(rowFields, columnFields);
List<List<String>> rowHeaderValues = dataSource.getHeaderGroupValues(0);
List<List<String>> columnHeaderValues = dataSource.getHeaderGroupValues(1);
int totalCells = rowHeaderValues.size() * columnHeaderValues.size();
if (totalCells > MAX_CELL_COUNT) {
throw new TooManyCellsError(totalCells);
}
for (List<String> header : rowHeaderValues) {
spreadsheet.addRowHeader(header);
}
for (List<String> header : columnHeaderValues) {
spreadsheet.addColumnHeader(header);
}
}
private void processRow(JSONObject group) {
JSONArray headerIndices = group.get("header_indices").isArray();
int row = (int) headerIndices.get(0).isNumber().doubleValue();
int column = (int) headerIndices.get(1).isNumber().doubleValue();
CellInfo cellInfo = spreadsheet.getCellInfo(row, column);
StatusSummary statusSummary = StatusSummary.getStatusSummary(
group,
TestGroupDataSource.PASS_COUNT_FIELD,
TestGroupDataSource.COMPLETE_COUNT_FIELD,
TestGroupDataSource.INCOMPLETE_COUNT_FIELD,
TestGroupDataSource.GROUP_COUNT_FIELD);
numTotalTests += statusSummary.getTotal();
cellInfo.contents = statusSummary.formatContents();
cellInfo.cssClass = statusSummary.getCssClass();
cellInfo.testCount = statusSummary.getTotal();
cellInfo.testIndex = (int) group.get("test_idx").isNumber().doubleValue();
lastCellInfo = cellInfo;
}
public void refresh(JSONObject condition, Command onFinished) {
timer = new Duration();
this.onFinished = onFinished;
dataSource.query(condition, this);
}
public void onQueryReady(Query query) {
currentQuery = query;
query.getPage(null, null, null, this);
}
public void handlePage(List<JSONObject> data) {
logTimer("Server response");
if (data.size() == 0) {
notifyManager.showMessage("No results for query");
onFinished.execute();
return;
}
DeferredCommand.addCommand(new ProcessDataCommand(data));
}
public void handleTotalResultCount(int totalCount) {}
private void logTimer(String message) {
notifyManager.log(message + ": " + timer.elapsedMillis() + " ms");
timer = new Duration();
}
public int getNumTotalTests() {
return numTotalTests;
}
/**
* This is useful when there turns out to be only a single test return.
* @return the last CellInfo created. Should only really be called when there was only a single
* one.
*/
public CellInfo getLastCellInfo() {
assert numTotalTests == 1;
return lastCellInfo;
}
public void onError(JSONObject errorObject) {
onFinished.execute();
}
public void setHeaders(List<HeaderField> rowFields, List<HeaderField> columnFields,
JSONObject queryParameters) {
this.rowFields = getHeaderSqlNames(rowFields);
this.columnFields = getHeaderSqlNames(columnFields);
List<List<String>> headerGroups = new ArrayList<List<String>>();
headerGroups.add(this.rowFields);
headerGroups.add(this.columnFields);
dataSource.setHeaderGroups(headerGroups);
dataSource.setQueryParameters(queryParameters);
}
private Header getHeaderSqlNames(List<HeaderField> fields) {
Header header = new HeaderImpl();
for (HeaderField field : fields) {
header.add(field.getSqlName());
}
return header;
}
public void setDataSource(TestGroupDataSource dataSource) {
this.dataSource = dataSource;
}
public TestGroupDataSource getDataSource() {
return dataSource;
}
public Query getCurrentQuery() {
return currentQuery;
}
}