Package org.pentaho.aggdes.ui.form.controller

Source Code of org.pentaho.aggdes.ui.form.controller.AggListController

/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* Copyright 2008 Pentaho Corporation.  All rights reserved.
*/
package org.pentaho.aggdes.ui.form.controller;

import java.awt.Color;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.DefaultIntervalXYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.pentaho.aggdes.algorithm.Algorithm;
import org.pentaho.aggdes.algorithm.util.ArgumentUtils;
import org.pentaho.aggdes.model.Aggregate;
import org.pentaho.aggdes.model.Parameter;
import org.pentaho.aggdes.output.OutputService;
import org.pentaho.aggdes.output.OutputValidationException;
import org.pentaho.aggdes.ui.Workspace;
import org.pentaho.aggdes.ui.ext.AlgorithmUiExtension;
import org.pentaho.aggdes.ui.form.model.AggModel;
import org.pentaho.aggdes.ui.form.model.AggregateSummaryModel;
import org.pentaho.aggdes.ui.form.model.ConnectionModel;
import org.pentaho.aggdes.ui.model.AggList;
import org.pentaho.aggdes.ui.model.AggListEvent;
import org.pentaho.aggdes.ui.model.AggListListener;
import org.pentaho.aggdes.ui.model.UIAggregate;
import org.pentaho.aggdes.ui.model.impl.UIAggregateImpl;
import org.pentaho.aggdes.ui.util.AggregateNamingService;
import org.pentaho.aggdes.ui.util.Messages;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.binding.Binding;
import org.pentaho.ui.xul.binding.BindingConvertor;
import org.pentaho.ui.xul.binding.BindingFactory;
import org.pentaho.ui.xul.binding.DefaultBinding;
import org.pentaho.ui.xul.components.XulButton;
import org.pentaho.ui.xul.components.XulImage;
import org.pentaho.ui.xul.components.XulTreeCell;
import org.pentaho.ui.xul.containers.XulTree;
import org.pentaho.ui.xul.containers.XulTreeRow;
import org.pentaho.ui.xul.impl.AbstractXulEventHandler;
import org.pentaho.ui.xul.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;

//FIXME: Use XUL data binding to remove all references to XulComponents

/**
* AggListController manages the UI for the Aggregate Table and the Aggregate
* Summary Screen, including the Cost / Benefit chart.
*/
@Controller
public class AggListController extends AbstractXulEventHandler {
 
  private final DecimalFormat format = new DecimalFormat("#0");
 
  private static final Log logger = LogFactory.getLog(AggListController.class);

  @Deprecated
  private XulTree aggLevelTable;

  @Deprecated
  private XulTree aggTable;

  private OutputService outputService;

  private AggModel aggModel;

  private AggregateNamingService aggNamingService;
 
  private AggregateSummaryModel aggregateSummaryModel;
 
  private Algorithm algorithm;
 
  private AlgorithmUiExtension algorithmUiExtension;
 
  private AggList aggList;
 
  private Workspace workspace;
 
  private ConnectionModel connectionModel;

  private BindingFactory bindingFactory;

  @Autowired
  public void setBindingFactory(BindingFactory bindingFactory) {
    this.bindingFactory = bindingFactory;
  }

 
  public AggList getAggList() {
    return aggList;
  }

  public void setAggList(AggList aggList) {
 
    this.aggList = aggList;
  }

  public void setAggModel(AggModel aggModel) {
    this.aggModel = aggModel;
  }

  public void setWorkspace(Workspace workspace) {
    this.workspace = workspace;
  }
 
  public void setOutputService(OutputService outputService) {
    this.outputService = outputService;
  }

  public void setAggregateNamingService(AggregateNamingService aggNamingService) {
    this.aggNamingService = aggNamingService;
  }
 
  public void setAggregateSummaryModel(AggregateSummaryModel aggregateSummaryModel) {
    this.aggregateSummaryModel = aggregateSummaryModel;
  }
 
  public void setAlgorithm(Algorithm algorithm) {
    this.algorithm = algorithm;
  }
 
  public void setAlgorithmUiExtension(AlgorithmUiExtension algorithmUiExtension) {
    this.algorithmUiExtension = algorithmUiExtension;
  }
 
  public void changeInAggregates() {
   
    // set dirty bit for workspace
    workspace.setWorkspaceUpToDate(false);
   
    // set the dirty bit for the schema publishing functionality
   
   if(getConnectionModel().getSchema() != null){
      getConnectionModel().setSchemaUpToDate(false);
    }
   
    // configure summary model and chart values
   
    int totalAggregatesSelected = 0;
    double totalRows = 0;
    double totalSpace = 0;
    double totalLoadTime = 0;

    //Fire event
    AggListController.this.firePropertyChange("aggList", null, aggList);
   
    List<Aggregate> algoAggregates = new ArrayList<Aggregate>();
    for (UIAggregate aggregate : getAggList()) {
      if (aggregate.getEnabled()) {
        totalAggregatesSelected++;
        totalRows += aggregate.estimateRowCount();
        totalSpace += aggregate.estimateSpace();
        algoAggregates.add(algorithm.createAggregate(connectionModel.getSchema(), aggregate.getAttributes()));
      }
    }

    double[] xs = new double[algoAggregates.size()];
    double[] startx = new double[algoAggregates.size()];
    double[] endx = new double[algoAggregates.size()];
   
    double[] ys = new double[algoAggregates.size()];
    double[] starty = new double[algoAggregates.size()];
    double[] endy = new double[algoAggregates.size()];

    XYSeries series1 = new XYSeries("CostBenefit");
    XYSeriesCollection dataset = new XYSeriesCollection();
    dataset.addSeries(series1);
    DefaultIntervalXYDataset datasetxy = new DefaultIntervalXYDataset();
   
    if (connectionModel.getSchema() != null) {
   
      Map<Parameter, Object> algorithmParams = ArgumentUtils.validateParameters(algorithm, algorithmUiExtension.getAlgorithmParameters());
      List<Algorithm.CostBenefit> costBenefit = algorithm.computeAggregateCosts(connectionModel.getSchema(), algorithmParams, algoAggregates);

      double totalbenefit = 0;
      double x = 0;
      int count = 0;
      for (Algorithm.CostBenefit cb : costBenefit) {
        Aggregate agg = algoAggregates.get(count);
        double estimateSpace = agg.estimateSpace();
        double hx = estimateSpace / 2;
        totalLoadTime += cb.getLoadTime();
        totalbenefit += cb.getSavedQueryRowCount();
        series1.add(x + hx, totalbenefit);
       
        xs[count] = x + hx;
        startx[count] = x;
        x += estimateSpace;
        endx[count] = x;
 
        ys[count] = totalbenefit;
        starty[count] = 0;
        endy[count] = 0;
 
        count++;
      }
 
      // update summary table
     
      aggregateSummaryModel.setSelectedAggregateCount(format.format(totalAggregatesSelected));
      aggregateSummaryModel.setSelectedAggregateRows(format.format(totalRows));
      aggregateSummaryModel.setSelectedAggregateSpace(format.format(totalSpace) + " bytes");
      aggregateSummaryModel.setSelectedAggregateLoadTime(format.format(totalLoadTime));
    } else {
      aggregateSummaryModel.setSelectedAggregateCount("");
      aggregateSummaryModel.setSelectedAggregateRows("");
      aggregateSummaryModel.setSelectedAggregateSpace("");
      aggregateSummaryModel.setSelectedAggregateLoadTime("");
     
    }
    // render cost benefit chart
   
    double[][] data = new double[][] {xs, startx, endx, ys, starty, endy};
    datasetxy.addSeries("", data);
   
    JFreeChart chart = ChartFactory.createXYBarChart(
        "", // chart title
        "Cost", // x axis label
        false,
        "Benefit", // y axis label
        datasetxy, // data
        PlotOrientation.VERTICAL, // orientation
        false, // include legend
        false, // tooltips?
        false // URLs?
        );
   
    ((XYPlot)chart.getPlot()).getDomainAxis().setTickLabelsVisible(false);
    ((XYPlot)chart.getPlot()).getRangeAxis().setTickLabelsVisible(false);
    ((XYPlot)chart.getPlot()).setDataset(1, dataset);
    XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();

    chart.setBackgroundPaint(
        new Color(Integer.parseInt(Messages.getString("chart_background_color").toUpperCase(), 16)));

    renderer.setSeriesPaint(0,
        new Color(Integer.parseInt(Messages.getString("chart_line_color").toUpperCase(), 16)));
   
    ((XYPlot)chart.getPlot()).getRenderer(0).setSeriesPaint(0,
        new Color(Integer.parseInt(Messages.getString("chart_bar_color").toUpperCase(), 16)));
   
   
   
    ((XYPlot)chart.getPlot()).setRenderer(1, renderer);
    ((XYPlot)chart.getPlot()).setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
    XulImage image = (XulImage)document.getElementById("chart");
    image.setSrc(chart.createBufferedImage(309, 168));
  }
 
  public void onLoad() {
    bindingFactory.setDocument(document);
    bindingFactory.setBindingType(Binding.Type.BI_DIRECTIONAL);

    // bind summary model label details
    bindingFactory.createBinding(aggregateSummaryModel, "selectedAggregateCount", "num_aggs", "value");
    bindingFactory.createBinding(aggregateSummaryModel, "selectedAggregateRows", "num_rows", "value");
    bindingFactory.createBinding(aggregateSummaryModel, "selectedAggregateSpace", "disk_space", "value");
   
   
    //Bind check-all, un-check-all buttons to model
    BindingConvertor<AggList, Boolean> convertor = new BindingConvertor<AggList, Boolean>() {
      public Boolean sourceToTarget(AggList list) {
        return ! (list.getSize() > 0);
      }

      //not used
      public AggList targetToSource(Boolean value) {
        return null;
      }
    };

    bindingFactory.setBindingType(Binding.Type.ONE_WAY);
   
    bindingFactory.createBinding(this, "aggList", "agg_checkall", "disabled", convertor);
   
    bindingFactory.createBinding(this, "aggList", "agg_uncheckall", "disabled", convertor);
   

    convertor = new BindingConvertor<AggList, Boolean>() {
      public Boolean sourceToTarget(AggList list) {
        return (list.getSize() > 0);
      }

      //not used
      public AggList targetToSource(Boolean value) {
        return null;
      }
    };
   
    bindingFactory.createBinding(this, "aggList", connectionModel, "schemaLocked", convertor);
   
   
    // not displayed at this time, no unit of measure
    // bind(aggregateSummaryModel, "selectedAggregateLoadTime", "load_time", "value");

   
    aggLevelTable = (XulTree) document.getElementById("dimtable");
    aggTable = (XulTree) document.getElementById("definedAggTable");

    AggListListener aggListListener = new AggListListener() {

      public void listChanged(AggListEvent e) {
        final String ESTIMATE_UNKNOWN = "unknown";

        AggList list = (AggList) e.getSource();
        switch (e.getType()) {
        case AGGS_ADDED:
          try {
            for (int i = e.getIndex(); i < list.getSize(); i++) {
              UIAggregate newAgg = list.getAgg(i);
 
              XulTreeRow newRow = (XulTreeRow) document.createElement("treerow");
 
              XulTreeCell newCell = (XulTreeCell) document.createElement("treecell");
              newCell.setValue(newAgg.getEnabled());
              newRow.addCell(newCell);
 
              newCell = (XulTreeCell) document.createElement("treecell");
              newCell.setLabel(newAgg.isAlgoAgg() ? Messages.getString("agg_type_advisor") : Messages.getString("agg_type_custom"));
              newRow.addCell(newCell);
 
              newCell = (XulTreeCell) document.createElement("treecell");
              newCell.setLabel(newAgg.getName());
              newRow.addCell(newCell);
 
              newCell = (XulTreeCell) document.createElement("treecell");
              double rowCount = newAgg.estimateRowCount();
              if (rowCount == 0) {
                newCell.setLabel(ESTIMATE_UNKNOWN);
              } else {
                newCell.setLabel(format.format(rowCount));
              }
              newRow.addCell(newCell);
 
              newCell = (XulTreeCell) document.createElement("treecell");
              double space = newAgg.estimateSpace();
              if (space == 0) {
                newCell.setLabel(ESTIMATE_UNKNOWN);
              } else {
                newCell.setLabel(format.format(space));
              }
              newRow.addCell(newCell);
 
              aggTable.addTreeRow(newRow);
            }
            changeInAggregates();
           
          } catch (XulException xe) {
            logger.error("Error adding new row to Agg table", xe);
          }
          break;
       
          case AGG_ADDED:
            try {
              UIAggregate newAgg = list.getAgg(e.getIndex());

              XulTreeRow newRow = (XulTreeRow) document.createElement("treerow");

              XulTreeCell newCell = (XulTreeCell) document.createElement("treecell");
              newCell.setValue(newAgg.getEnabled());
              newRow.addCell(newCell);

              newCell = (XulTreeCell) document.createElement("treecell");
              newCell.setLabel(newAgg.isAlgoAgg() ? Messages.getString("agg_type_advisor") : Messages.getString("agg_type_custom"));
              newRow.addCell(newCell);

              newCell = (XulTreeCell) document.createElement("treecell");
              newCell.setLabel(newAgg.getName());
              newRow.addCell(newCell);

              newCell = (XulTreeCell) document.createElement("treecell");
              double rowCount = newAgg.estimateRowCount();
              if (rowCount == 0) {
                newCell.setLabel(ESTIMATE_UNKNOWN);
              } else {
                newCell.setLabel(format.format(rowCount));
              }
              newRow.addCell(newCell);

              newCell = (XulTreeCell) document.createElement("treecell");
              double space = newAgg.estimateSpace();
              if (space == 0) {
                newCell.setLabel(ESTIMATE_UNKNOWN);
              } else {
                newCell.setLabel(format.format(space));
              }
              newRow.addCell(newCell);

              aggTable.addTreeRow(newRow);

              changeInAggregates();
             
            } catch (XulException xe) {
              logger.error("Error adding new row to Agg table", xe);
            }
            break;
          case AGGS_CLEARED:
            aggTable.getRootChildren().removeAll();
            aggModel.setThinAgg(null);
            changeInAggregates();
            break;
          case AGG_REMOVED:
            aggTable.removeTreeRows(new int[] { e.getIndex() });
            aggTable.clearSelection();
            int[] tableSelection = aggTable.getSelectedRows();
            if (e.getIndex() < list.getSize()) {
              //we're single selection
              list.setSelectedIndex(e.getIndex());
            }
            //There's aready a selection listener on the table firing the same.
            UIAggregate tempAgg = list.getSelectedValue();
           
            aggModel.setThinAgg(list.getSelectedValue());
           
            changeInAggregates();
                       
            break;
          case SELECTION_CHANGED:
           
            if (aggTable.getSelectedRows().length > 0) {
              logger.info("Event index: " + e.getIndex() + " aggTable.selectedRow0: " + aggTable.getSelectedRows()[0]);
            }
            int[] rows = aggTable.getSelectedRows();
            if (aggTable.getSelectedRows().length > 0 && e.getIndex() == aggTable.getSelectedRows()[0]) {
              aggModel.setThinAgg(list.getSelectedValue());
            }
            //check to see if it's already selected, ignore if so
            int[] curSelection = aggTable.getSelectedRows();
//            if(curSelection.length > 0 && e.getIndex() == curSelection[0]){
//              logger.debug("already selected row");
//              break;
//            }
            logger.debug("selecting new row");
            aggTable.setSelectedRows(new int[] { e.getIndex() });
            aggModel.setThinAgg(list.getSelectedValue());
            break;
          case AGG_CHANGED:
            logger.debug("agg list controller responding to AGG_CHANGED event from aggList");
            int idx = e.getIndex();
            UIAggregate agg = list.getAgg(idx);
            aggTable.getRootChildren().getItem(idx).getRow().getCell(0).setValue(agg.getEnabled());
            aggTable.getRootChildren().getItem(idx).getRow().getCell(1).setLabel(
                agg.isAlgoAgg()
                ? Messages.getString("agg_type_advisor")
                : Messages.getString("agg_type_custom")
            );
            aggTable.getRootChildren().getItem(idx).getRow().getCell(2).setLabel(agg.getName());

            double rowCount = agg.estimateRowCount();
            if (rowCount == 0) {
              aggTable.getRootChildren().getItem(idx).getRow().getCell(3).setLabel(ESTIMATE_UNKNOWN);
            } else {
              aggTable.getRootChildren().getItem(idx).getRow().getCell(3).setLabel(format.format(rowCount));
            }

            double space = agg.estimateSpace();
            if (space == 0) {
              aggTable.getRootChildren().getItem(idx).getRow().getCell(4).setLabel(ESTIMATE_UNKNOWN);
            } else {
              aggTable.getRootChildren().getItem(idx).getRow().getCell(4).setLabel(format.format(space));
            }
           
            // wrap the update in an invokeLater to avoid null pointer exceptions occurring deep in Swing code,
            // even though this method will normally be called within the event thread.
            document.invokeLater(new Runnable() {
              public void run() {
                aggTable.update();
              }
            });
            changeInAggregates();
           
            break;
        }

      }

    };
    getAggList().addAggListListener(aggListListener);
   
    // what happens?
    changeInAggregates();
  }

  public void addAgg() {
    try {
      UIAggregate newAgg = new UIAggregateImpl();
      aggNamingService.nameAggregate(newAgg, getAggList(), connectionModel.getSchema());
     
      newAgg.setOutput(outputService.generateDefaultOutput(newAgg));
     
      getAggList().addAgg(newAgg);
      getAggList().setSelectedIndex(getAggList().getSize() - 1);
    } catch (OutputValidationException e) {
      System.err.println("Failed to create output, skipping UIAggregate");
      e.printStackTrace();
    }
  }

  public void showAgg(int idx) {
    aggLevelTable.clearSelection();
    Aggregate agg = getAggList().getAgg(idx);
    if (agg == null) {
      logger.info(String.format("List and Table out of sync, %s does not exist", idx));
    } else {
      getAggList().setSelectedIndex(idx);
    }
  }

  public void saveAggChange(int idx) {
    UIAggregate agg = getAggList().getAgg(idx);
    XulTree aggTable = (XulTree) document.getElementById("definedAggTable");
    XulTreeRow row = aggTable.getRootChildren().getItem(idx).getRow();
    agg.setEnabled((Boolean) row.getCell(0).getValue());

    // get row count estimate
    Aggregate algoAggregate = algorithm.createAggregate(connectionModel.getSchema(), agg.getAttributes());
    agg.setEstimateRowCount(algoAggregate.estimateRowCount());
    agg.setEstimateSpace(algoAggregate.estimateSpace());
    getAggList().aggChanged(agg);
    System.out.println("Saving agg, enabled? " + row.getCell(0).getValue());
   
  }

  public void displayNewOrExistingAgg() {
    if (getAggList().getSize() == 0) {
      addAgg();
    } else {
      if (getAggList().getSelectedIndex() == -1) {
        showAgg(0);
      } else {
        showAgg(getAggList().getSelectedIndex());
      }
    }
  }

  public void removeAgg() {
    if (aggTable == null) {
      return;
    }
    int[] selectedIndexes = aggTable.getSelectedRows();
    for (int pos : selectedIndexes) {
      //the user has chosen to delete this agg, so do not prompt to save any changes
      //just reset the form.
      aggModel.reset();
     
      getAggList().removeAgg(pos);
    }

  }
 
  public void moveAggUp(){
    getAggList().moveAggUp(getAggList().getSelectedValue());
  }

  public void moveAggDown(){
    getAggList().moveAggDown(getAggList().getSelectedValue());
  }

  public void checkAll(){
    getAggList().checkAll();
  }

  public void uncheckAll(){
    getAggList().uncheckAll();
  }

  public ConnectionModel getConnectionModel() {
 
    return connectionModel;
  }

  public void setConnectionModel(ConnectionModel connectionModel) {
 
    this.connectionModel = connectionModel;
  }
}
TOP

Related Classes of org.pentaho.aggdes.ui.form.controller.AggListController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.