1 package autotest.tko; 2 3 import autotest.common.Utils; 4 import autotest.common.ui.ExtendedListBox; 5 import autotest.common.ui.NotifyManager; 6 import autotest.common.ui.TabView; 7 import autotest.tko.SeriesSelector.Series; 8 9 import com.google.gwt.event.dom.client.ChangeEvent; 10 import com.google.gwt.event.dom.client.ChangeHandler; 11 import com.google.gwt.event.dom.client.ClickEvent; 12 import com.google.gwt.event.dom.client.ClickHandler; 13 import com.google.gwt.json.client.JSONObject; 14 import com.google.gwt.json.client.JSONString; 15 import com.google.gwt.user.client.ui.HorizontalPanel; 16 import com.google.gwt.user.client.ui.Panel; 17 import com.google.gwt.user.client.ui.RadioButton; 18 import com.google.gwt.user.client.ui.TextBox; 19 import com.google.gwt.user.client.ui.VerticalPanel; 20 21 import java.util.HashMap; 22 import java.util.List; 23 import java.util.Map; 24 25 public class MetricsPlotFrontend extends DynamicGraphingFrontend implements ClickHandler { 26 27 public static final String NORMALIZE_SINGLE = "single"; 28 public static final String NORMALIZE_FIRST = "first"; 29 public static final String NORMALIZE_SERIES_PREFIX = "series__"; 30 public static final String NORMALIZE_X_PREFIX = "x__"; 31 32 protected FilterSelector globalFilter = new FilterSelector(DBColumnSelector.PERF_VIEW); 33 private ExtendedListBox plotSelector = new ExtendedListBox(); 34 private ExtendedListBox xAxis = new DBColumnSelector(DBColumnSelector.PERF_VIEW, true); 35 private RadioButton noNormalizeMultiple = 36 new RadioButton("normalize", "No normalization (multiple subplots)"); 37 private RadioButton noNormalizeSingle = 38 new RadioButton("normalize", "No normalization (single plot)"); 39 private RadioButton normalizeFirst = new RadioButton("normalize", "First data point"); 40 private RadioButton normalizeSeries = new RadioButton("normalize", "Specified series:"); 41 private ExtendedListBox normalizeSeriesSelect = new ExtendedListBox(); 42 private RadioButton normalizeX = new RadioButton("normalize", "Specified X-axis value:"); 43 private TextBox normalizeXSelect = new TextBox(); 44 private SeriesSelector seriesSelector = new SeriesSelector(new ChangeHandler() { 45 public void onChange(ChangeEvent event) { 46 refreshSeries(); 47 } 48 }); 49 50 public MetricsPlotFrontend(final TabView parent) { 51 super(parent, new MetricsPlot(), "metrics"); 52 53 noNormalizeSingle.setValue(true); 54 55 noNormalizeMultiple.addClickHandler(this); 56 noNormalizeSingle.addClickHandler(this); 57 normalizeFirst.addClickHandler(this); 58 normalizeSeries.addClickHandler(this); 59 normalizeX.addClickHandler(this); 60 61 normalizeSeriesSelect.setEnabled(false); 62 normalizeXSelect.setEnabled(false); 63 64 plotSelector.addItem("Line"); 65 plotSelector.addItem("Bar"); 66 plotSelector.addChangeHandler(new ChangeHandler() { 67 public void onChange(ChangeEvent event) { 68 checkNormalizeInput(); 69 } 70 }); 71 72 Panel normalizePanel = new VerticalPanel(); 73 normalizePanel.add(noNormalizeMultiple); 74 normalizePanel.add(noNormalizeSingle); 75 Panel seriesPanel = new HorizontalPanel(); 76 seriesPanel.add(normalizeSeries); 77 seriesPanel.add(normalizeSeriesSelect); 78 normalizePanel.add(seriesPanel); 79 normalizePanel.add(normalizeFirst); 80 Panel baselinePanel = new HorizontalPanel(); 81 baselinePanel.add(normalizeX); 82 baselinePanel.add(normalizeXSelect); 83 normalizePanel.add(baselinePanel); 84 85 addControl("Preconfigured:", preconfig); 86 addControl("Plot:", plotSelector); 87 addControl("X-axis values:", xAxis); 88 addControl("Global filters:", globalFilter); 89 addControl("Series:", seriesSelector); 90 addControl("Normalize to:", normalizePanel); 91 92 commonInitialization(); 93 } 94 95 @Override 96 public void onClick(ClickEvent event) { 97 if (event.getSource() != noNormalizeSingle && event.getSource() != noNormalizeMultiple 98 && event.getSource() != normalizeSeries && event.getSource() != normalizeX) { 99 super.onClick(event); 100 return; 101 } 102 103 normalizeSeriesSelect.setEnabled(false); 104 normalizeXSelect.setEnabled(false); 105 if (event.getSource() == normalizeSeries) { 106 normalizeSeriesSelect.setEnabled(true); 107 refreshSeries(); 108 } else if (event.getSource() == normalizeX) { 109 normalizeXSelect.setEnabled(true); 110 } 111 112 checkInvertible(); 113 } 114 115 private void addNormalizeParameter(String plotType, Map<String, String> parameters) { 116 String normalizationType = null; 117 if (plotType.equals("Line") && noNormalizeSingle.getValue()) { 118 normalizationType = NORMALIZE_SINGLE; 119 } else if (normalizeFirst.getValue()) { 120 normalizationType = NORMALIZE_FIRST; 121 } else if (normalizeSeries.getValue()) { 122 String series = normalizeSeriesSelect.getSelectedValue(); 123 normalizationType = NORMALIZE_SERIES_PREFIX + series; 124 } else if (normalizeX.getValue()) { 125 String baseline = normalizeXSelect.getText(); 126 normalizationType = NORMALIZE_X_PREFIX + baseline; 127 } 128 129 if (normalizationType != null) { 130 parameters.put("normalize", normalizationType); 131 } 132 } 133 134 @Override 135 public void addToHistory(Map<String, String> args) { 136 String plot = plotSelector.getValue(plotSelector.getSelectedIndex()); 137 args.put("plot", plot); 138 args.put("xAxis", xAxis.getSelectedValue()); 139 globalFilter.addToHistory(args, "globalFilter"); 140 seriesSelector.addToHistory(args); 141 addNormalizeParameter(plot, args); 142 } 143 144 @Override 145 public void handleHistoryArguments(Map<String, String> args) { 146 setVisible(false); 147 plot.setVisible(false); 148 embeddingLink.setVisible(false); 149 globalFilter.reset(); 150 seriesSelector.reset(); 151 for (int i = 0; i < plotSelector.getItemCount(); i++) { 152 if (plotSelector.getValue(i).equals(args.get("plot"))) { 153 plotSelector.setSelectedIndex(i); 154 break; 155 } 156 } 157 158 xAxis.selectByValue(args.get("xAxis")); 159 globalFilter.handleHistoryArguments(args, "globalFilter"); 160 seriesSelector.handleHistoryArguments(args); 161 162 refreshSeries(); 163 noNormalizeMultiple.setValue(true); 164 normalizeSeriesSelect.setEnabled(false); 165 normalizeXSelect.setEnabled(false); 166 String normalizeString = args.get("normalize"); 167 if (normalizeString != null) { 168 if (normalizeString.equals(NORMALIZE_SINGLE)) { 169 noNormalizeSingle.setValue(true); 170 } else if (normalizeString.equals(NORMALIZE_FIRST)) { 171 normalizeFirst.setValue(true); 172 } else if (normalizeString.startsWith(NORMALIZE_SERIES_PREFIX)) { 173 normalizeSeries.setValue(true); 174 String series = normalizeString.substring(NORMALIZE_SERIES_PREFIX.length()); 175 for (int i = 0; i < normalizeSeriesSelect.getItemCount(); i++) { 176 if (normalizeSeriesSelect.getValue(i).equals(series)) { 177 normalizeSeriesSelect.setSelectedIndex(i); 178 break; 179 } 180 } 181 normalizeSeriesSelect.setEnabled(true); 182 } else if (normalizeString.startsWith(NORMALIZE_X_PREFIX)) { 183 normalizeX.setValue(true); 184 normalizeXSelect.setText(normalizeString.substring(NORMALIZE_X_PREFIX.length())); 185 normalizeXSelect.setEnabled(true); 186 } 187 } 188 checkNormalizeInput(); 189 checkInvertible(); 190 191 setVisible(true); 192 } 193 194 @Override 195 protected void addAdditionalEmbeddingParams(JSONObject params) { 196 params.put("graph_type", new JSONString("metrics")); 197 params.put("params", buildParams()); 198 } 199 200 private void refreshSeries() { 201 String selectedValue = normalizeSeriesSelect.getSelectedValue(); 202 normalizeSeriesSelect.clear(); 203 for (Series selector : seriesSelector.getAllSeries()) { 204 normalizeSeriesSelect.addItem(selector.getName()); 205 if (selector.getName().equals(selectedValue)) { 206 normalizeSeriesSelect.setSelectedIndex(normalizeSeriesSelect.getItemCount() - 1); 207 } 208 } 209 } 210 211 // Disable "No Normalization (multiple)" for bar charts 212 private void checkNormalizeInput() { 213 if (plotSelector.getValue(plotSelector.getSelectedIndex()).equals("Line")) { 214 noNormalizeMultiple.setEnabled(true); 215 } else { 216 noNormalizeMultiple.setEnabled(false); 217 if (noNormalizeMultiple.getValue()) { 218 noNormalizeSingle.setValue(true); 219 } 220 } 221 } 222 223 private JSONObject buildQueries() { 224 List<Series> seriesList = seriesSelector.getAllSeries(); 225 JSONObject queries = new JSONObject(); 226 StringBuilder sql = new StringBuilder(); 227 228 sql.append("SELECT "); 229 sql.append(xAxis.getSelectedValue()); 230 for (Series series : seriesList) { 231 addSeriesSelects(series, sql); 232 } 233 234 sql.append(" FROM tko_perf_view_2"); 235 236 String xFilterString = globalFilter.getFilterString(); 237 if (xFilterString.equals("")) { 238 NotifyManager.getInstance().showError("You must enter a global filter"); 239 return null; 240 } 241 242 sql.append(" WHERE "); 243 sql.append(xFilterString); 244 245 sql.append(" GROUP BY "); 246 sql.append(xAxis.getSelectedValue()); 247 queries.put("__main__", new JSONString(sql.toString())); 248 249 for (Series series : seriesList) { 250 String drilldownQuery = getSeriesDrilldownQuery(series, xFilterString); 251 queries.put("__" + series.getName() + "__", new JSONString(drilldownQuery)); 252 } 253 254 return queries; 255 } 256 257 private String getSeriesDrilldownQuery(Series series, String xFilterString) { 258 StringBuilder sql; 259 sql = new StringBuilder(); 260 ExtendedListBox valueSelector = series.getDBColumnSelector(); 261 262 sql.append("SELECT test_idx, "); 263 sql.append(valueSelector.getSelectedValue()); 264 sql.append(" FROM tko_perf_view_2 WHERE "); 265 266 String seriesFilter = series.getFilterString(); 267 if (!xFilterString.equals("") || !seriesFilter.equals("")) { 268 sql.append(xFilterString.replace("%", "%%")); 269 if (!xFilterString.equals("") && !seriesFilter.equals("")) { 270 sql.append(" AND "); 271 } 272 sql.append(seriesFilter.replace("%", "%%")); 273 sql.append(" AND "); 274 } 275 276 sql.append(xAxis.getSelectedValue()); 277 sql.append(" = %s ORDER BY "); 278 sql.append(valueSelector.getSelectedValue()); 279 return sql.toString(); 280 } 281 282 private void addSeriesSelects(Series series, StringBuilder sql) { 283 ExtendedListBox valueSelector = series.getDBColumnSelector(); 284 285 StringBuilder ifClause = new StringBuilder(); 286 String seriesFilter = series.getFilterString(); 287 if (!seriesFilter.equals("")) { 288 ifClause.append("IF("); 289 ifClause.append(seriesFilter); 290 ifClause.append(", "); 291 } 292 ifClause.append(valueSelector.getSelectedValue()); 293 if (!seriesFilter.equals("")) { 294 ifClause.append(", NULL)"); 295 } 296 297 sql.append(", "); 298 sql.append(series.getAggregation()); 299 sql.append(ifClause.toString()); 300 sql.append(") '"); 301 sql.append(series.getName()); 302 sql.append("'"); 303 if (series.wantErrorBars()) { 304 sql.append(", STDDEV("); 305 sql.append(ifClause.toString()); 306 sql.append(") 'errors-"); 307 sql.append(series.getName()); 308 sql.append("'"); 309 } 310 } 311 312 // Disable the "Invert y-axis" checkboxes if inversion doesn't make sense 313 private void checkInvertible() { 314 boolean invertible = noNormalizeMultiple.getValue() || normalizeFirst.getValue() 315 || normalizeX.getValue(); 316 seriesSelector.setInvertible(invertible); 317 } 318 319 @Override 320 protected JSONObject buildParams() { 321 JSONObject queries = buildQueries(); 322 if (queries == null) { 323 return null; 324 } 325 326 Map<String, String> params = new HashMap<String, String>(); 327 String plot = plotSelector.getSelectedValue(); 328 params.put("plot", plot); 329 addNormalizeParameter(plot, params); 330 331 JSONObject jsonParams = Utils.mapToJsonObject(params); 332 jsonParams.put("invert", Utils.stringsToJSON(seriesSelector.getInverted())); 333 jsonParams.put("queries", queries); 334 return jsonParams; 335 } 336 337 @Override 338 public String getFrontendId() { 339 return "metrics_plot"; 340 } 341 } 342