Home | History | Annotate | Download | only in tko
      1 package autotest.tko;
      2 
      3 import autotest.common.StatusSummary;
      4 import autotest.common.spreadsheet.Spreadsheet;
      5 import autotest.common.spreadsheet.Spreadsheet.CellInfo;
      6 import autotest.common.spreadsheet.Spreadsheet.Header;
      7 import autotest.common.spreadsheet.Spreadsheet.HeaderImpl;
      8 import autotest.common.table.DataSource.DataCallback;
      9 import autotest.common.table.DataSource.Query;
     10 import autotest.common.ui.NotifyManager;
     11 
     12 import com.google.gwt.core.client.Duration;
     13 import com.google.gwt.json.client.JSONArray;
     14 import com.google.gwt.json.client.JSONObject;
     15 import com.google.gwt.user.client.Command;
     16 import com.google.gwt.user.client.DeferredCommand;
     17 import com.google.gwt.user.client.IncrementalCommand;
     18 
     19 import java.util.ArrayList;
     20 import java.util.List;
     21 
     22 public class SpreadsheetDataProcessor implements DataCallback {
     23     private static final NotifyManager notifyManager = NotifyManager.getInstance();
     24     private static final int MAX_CELL_COUNT = 500000;
     25     private static final int ROWS_PROCESSED_PER_ITERATION = 1000;
     26 
     27     private Spreadsheet spreadsheet;
     28     private TestGroupDataSource dataSource;
     29     private int numTotalTests;
     30     private CellInfo lastCellInfo;
     31 
     32     private Header rowFields, columnFields;
     33     private Command onFinished;
     34     private Duration timer;
     35     private Query currentQuery;
     36 
     37     public static class TooManyCellsError extends Exception {
     38         public int cellCount;
     39 
     40         public TooManyCellsError(int cellCount) {
     41             super();
     42             this.cellCount = cellCount;
     43         }
     44     }
     45 
     46     private class ProcessDataCommand implements IncrementalCommand {
     47         private int state = 0;
     48         private List<JSONObject> counts;
     49         private int currentRow = 0;
     50 
     51         public ProcessDataCommand(List<JSONObject> counts) {
     52             this.counts = counts;
     53         }
     54 
     55         public void processSomeRows() {
     56             for (int i = 0; i < ROWS_PROCESSED_PER_ITERATION; i++, currentRow++) {
     57                 if (currentRow == counts.size()) {
     58                     state++;
     59                     return;
     60                 }
     61                 processRow(counts.get(currentRow).isObject());
     62             }
     63         }
     64 
     65         public boolean execute() {
     66             switch (state) {
     67                 case 0:
     68                     notifyManager.setLoading(true);
     69                     numTotalTests = 0;
     70                     try {
     71                         processHeaders();
     72                     } catch (TooManyCellsError exc) {
     73                         notifyManager.showError("Resulting spreadsheet contains " + exc.cellCount +
     74                                                 " cells, " + "exceeding maximum " + MAX_CELL_COUNT);
     75                         finalizeCommand();
     76                         return false;
     77                     }
     78                     break;
     79                 case 1:
     80                     spreadsheet.prepareForData();
     81                     break;
     82                 case 2:
     83                     processSomeRows();
     84                     return true;
     85                 case 3:
     86                     // we must make the spreadsheet visible before rendering, or size computations
     87                     // won't work correctly
     88                     spreadsheet.setVisible(true);
     89                     break;
     90                 case 4:
     91                     spreadsheet.render(this);
     92                     state++;
     93                     return false; // render will re-add us to the command queue
     94                 case 5:
     95                     logTimer("Rendering");
     96                     finalizeCommand();
     97                     return false;
     98             }
     99 
    100             state++;
    101             return true;
    102         }
    103 
    104         private void finalizeCommand() {
    105             notifyManager.setLoading(false);
    106             onFinished.execute();
    107         }
    108     }
    109 
    110     public SpreadsheetDataProcessor(Spreadsheet spreadsheet) {
    111         this.spreadsheet = spreadsheet;
    112     }
    113 
    114     public void processHeaders() throws TooManyCellsError {
    115         spreadsheet.setHeaderFields(rowFields, columnFields);
    116         List<List<String>> rowHeaderValues = dataSource.getHeaderGroupValues(0);
    117         List<List<String>> columnHeaderValues = dataSource.getHeaderGroupValues(1);
    118         int totalCells = rowHeaderValues.size() * columnHeaderValues.size();
    119         if (totalCells > MAX_CELL_COUNT) {
    120             throw new TooManyCellsError(totalCells);
    121         }
    122         for (List<String> header : rowHeaderValues) {
    123             spreadsheet.addRowHeader(header);
    124         }
    125         for (List<String> header : columnHeaderValues) {
    126             spreadsheet.addColumnHeader(header);
    127         }
    128     }
    129 
    130     private void processRow(JSONObject group) {
    131         JSONArray headerIndices = group.get("header_indices").isArray();
    132         int row = (int) headerIndices.get(0).isNumber().doubleValue();
    133         int column = (int) headerIndices.get(1).isNumber().doubleValue();
    134         CellInfo cellInfo = spreadsheet.getCellInfo(row, column);
    135         StatusSummary statusSummary = StatusSummary.getStatusSummary(
    136             group,
    137             TestGroupDataSource.PASS_COUNT_FIELD,
    138             TestGroupDataSource.COMPLETE_COUNT_FIELD,
    139             TestGroupDataSource.INCOMPLETE_COUNT_FIELD,
    140             TestGroupDataSource.GROUP_COUNT_FIELD);
    141         numTotalTests += statusSummary.getTotal();
    142         cellInfo.contents = statusSummary.formatContents();
    143         cellInfo.cssClass = statusSummary.getCssClass();
    144         cellInfo.testCount = statusSummary.getTotal();
    145         cellInfo.testIndex = (int) group.get("test_idx").isNumber().doubleValue();
    146         lastCellInfo = cellInfo;
    147     }
    148 
    149     public void refresh(JSONObject condition, Command onFinished) {
    150         timer = new Duration();
    151         this.onFinished = onFinished;
    152         dataSource.query(condition, this);
    153     }
    154 
    155     public void onQueryReady(Query query) {
    156         currentQuery = query;
    157         query.getPage(null, null, null, this);
    158     }
    159 
    160     public void handlePage(List<JSONObject> data) {
    161         logTimer("Server response");
    162         if (data.size() == 0) {
    163             notifyManager.showMessage("No results for query");
    164             onFinished.execute();
    165             return;
    166         }
    167 
    168         DeferredCommand.addCommand(new ProcessDataCommand(data));
    169     }
    170 
    171     public void handleTotalResultCount(int totalCount) {}
    172 
    173     private void logTimer(String message) {
    174         notifyManager.log(message + ": " + timer.elapsedMillis() + " ms");
    175         timer = new Duration();
    176     }
    177 
    178     public int getNumTotalTests() {
    179         return numTotalTests;
    180     }
    181 
    182     /**
    183      * This is useful when there turns out to be only a single test return.
    184      * @return the last CellInfo created.  Should only really be called when there was only a single
    185      *         one.
    186      */
    187     public CellInfo getLastCellInfo() {
    188         assert numTotalTests == 1;
    189         return lastCellInfo;
    190     }
    191 
    192     public void onError(JSONObject errorObject) {
    193         onFinished.execute();
    194     }
    195 
    196     public void setHeaders(List<HeaderField> rowFields, List<HeaderField> columnFields,
    197                            JSONObject queryParameters) {
    198         this.rowFields = getHeaderSqlNames(rowFields);
    199         this.columnFields = getHeaderSqlNames(columnFields);
    200 
    201         List<List<String>> headerGroups = new ArrayList<List<String>>();
    202         headerGroups.add(this.rowFields);
    203         headerGroups.add(this.columnFields);
    204         dataSource.setHeaderGroups(headerGroups);
    205         dataSource.setQueryParameters(queryParameters);
    206     }
    207 
    208     private Header getHeaderSqlNames(List<HeaderField> fields) {
    209         Header header = new HeaderImpl();
    210         for (HeaderField field : fields) {
    211             header.add(field.getSqlName());
    212         }
    213         return header;
    214     }
    215 
    216     public void setDataSource(TestGroupDataSource dataSource) {
    217         this.dataSource = dataSource;
    218     }
    219 
    220     public TestGroupDataSource getDataSource() {
    221         return dataSource;
    222     }
    223 
    224     public Query getCurrentQuery() {
    225         return currentQuery;
    226     }
    227 }
    228