Package org.apache.hadoop.chukwa.analysis.salsa.visualization

Source Code of org.apache.hadoop.chukwa.analysis.salsa.visualization.Swimlanes$MapReduceSwimlanes

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.chukwa.analysis.salsa.visualization;

import prefuse.data.io.sql.*;
import prefuse.data.Table;
import prefuse.data.expression.parser.*;
import prefuse.data.expression.*;
import prefuse.data.column.*;
import prefuse.data.query.*;
import prefuse.data.*;
import prefuse.action.*;
import prefuse.action.layout.*;
import prefuse.action.assignment.*;
import prefuse.visual.expression.*;
import prefuse.visual.*;
import prefuse.render.*;
import prefuse.util.collections.*;
import prefuse.util.*;
import prefuse.*;

import org.apache.hadoop.chukwa.hicc.OfflineTimeHandler;
import org.apache.hadoop.chukwa.hicc.TimeHandler;
import org.apache.hadoop.chukwa.util.DatabaseWriter;
import org.apache.hadoop.chukwa.database.Macro;
import org.apache.hadoop.chukwa.util.XssFilter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.http.*;
import javax.swing.BorderFactory;

import java.sql.*;
import java.util.*;
import java.text.NumberFormat;
import java.text.DateFormat;

import java.awt.Font;
import java.awt.geom.Rectangle2D;

/**
* Static image generation for Swimlanes visualization for scalable
* rendering on front-end client (web-browser)
* Handles database data retrieval, transforming data to form for
* visualization elements, and initializing and calling visualization
* elements
*/
public class Swimlanes {

  private static Log log = LogFactory.getLog(Swimlanes.class);

  int SIZE_X=1600, SIZE_Y=1600;
  final int [] BORDER = {50,50,50,50};
  final int LEGEND_X_OFFSET = 50;
  final int LEGEND_Y_OFFSET = 25;
  final int LEGEND_TEXT_OFFSET = 20;
  final int LEGEND_FONT_SIZE = 18;
  final int AXIS_NAME_FONT_SIZE = 24;

  protected boolean offline_use = true;
  protected HttpServletRequest request;
 
  protected String abc;

  /**
   * Modifier for generic Swimlanes plots to plot shuffle, sort, and reducer
   * states of same reduce on same line
   */
  protected class MapReduceSwimlanes {
    protected Table plot_tab;
    protected HashMap<String, ArrayList<Tuple> > reducepart_hash;
    protected boolean collate_reduces = false;
   
    public MapReduceSwimlanes() {
      this.plot_tab = new Table();
      this.plot_tab.addColumn("ycoord",float.class);
      this.plot_tab.addColumn("state_name",String.class);
      this.plot_tab.addColumn("hostname",String.class);
      this.plot_tab.addColumn("friendly_id",String.class);
      this.plot_tab.addColumn(START_FIELD_NAME,double.class);
      this.plot_tab.addColumn(END_FIELD_NAME,double.class);
      this.plot_tab.addColumn(PolygonRenderer.POLYGON,float[].class);
      this.reducepart_hash = new HashMap<String, ArrayList<Tuple> >();
    }
   
    public void populateTable_OneLinePerState(Table orig_tab) {
      IntIterator rownumiter;
      int newrownum, origrownum;
      rownumiter = orig_tab.rows(); // iterate over everything
      while (rownumiter.hasNext()) {
        origrownum = ((Integer)rownumiter.next()).intValue();
        newrownum = this.plot_tab.addRow();
        this.plot_tab.set(newrownum, "state_name", orig_tab.getString(origrownum, "state_name"));
        this.plot_tab.set(newrownum, "ycoord", orig_tab.getInt(origrownum, "seqno"));
        this.plot_tab.set(newrownum,"hostname",orig_tab.getString(origrownum,"hostname"));
        this.plot_tab.set(newrownum,"friendly_id",orig_tab.getString(origrownum,"friendly_id"));
        this.plot_tab.set(newrownum,START_FIELD_NAME, orig_tab.getDouble(origrownum,START_FIELD_NAME));
        this.plot_tab.set(newrownum,END_FIELD_NAME, orig_tab.getDouble(origrownum,END_FIELD_NAME));
      }     
    }
   
    public void populateTable_CollateReduces(Table orig_tab) {
      IntIterator rownumiter;
      int newrownum, origrownum;
     
      this.collate_reduces = true;
     
      // add maps normally
      rownumiter = orig_tab.rows(
        (Predicate) ExpressionParser.parse("[state_name] == 'map' " +
          "OR [state_name] == 'shuffle_local' " +
          "OR [state_name] == 'shuffle_remote'")
      );
     
      while (rownumiter.hasNext()) {
        origrownum = ((Integer)rownumiter.next()).intValue();
        newrownum = this.plot_tab.addRow();
        this.plot_tab.set(newrownum, "state_name", orig_tab.getString(origrownum, "state_name"));
        this.plot_tab.set(newrownum, "ycoord", orig_tab.getInt(origrownum, "seqno"));
        this.plot_tab.set(newrownum,"hostname",orig_tab.getString(origrownum,"hostname"));
        this.plot_tab.set(newrownum,"friendly_id",orig_tab.getString(origrownum,"friendly_id"));
        this.plot_tab.set(newrownum,START_FIELD_NAME, orig_tab.getDouble(origrownum,START_FIELD_NAME));
        this.plot_tab.set(newrownum,END_FIELD_NAME, orig_tab.getDouble(origrownum,END_FIELD_NAME));
      }

      // special breakdown for reduces
      IntIterator rownumiter3 = orig_tab.rows(
        (Predicate) ExpressionParser.parse("[state_name] == 'reduce_reducer' " +
          "OR [state_name] == 'reduce_shufflewait' " +
          "OR [state_name] == 'reduce_sort' " +
          "OR [state_name] == 'reduce'")
      );
     
      ArrayList<Tuple> tuple_array;
      while (rownumiter3.hasNext()) {
        origrownum = ((Integer)rownumiter3.next()).intValue();
        if (orig_tab.getString(origrownum,"state_name").equals("reduce")) {
          continue; // do NOT add reduces
        }
        String curr_reduce = orig_tab.getString(origrownum, "friendly_id");
        newrownum = this.plot_tab.addRow();
       
        this.plot_tab.set(newrownum, "state_name", orig_tab.getString(origrownum, "state_name"));
        this.plot_tab.set(newrownum, "ycoord", orig_tab.getInt(origrownum, "seqno"));
        this.plot_tab.set(newrownum,"hostname",orig_tab.getString(origrownum,"hostname"));
        this.plot_tab.set(newrownum,"friendly_id",orig_tab.getString(origrownum,"friendly_id"));       
        this.plot_tab.set(newrownum,START_FIELD_NAME, orig_tab.getDouble(origrownum,START_FIELD_NAME));
        this.plot_tab.set(newrownum,END_FIELD_NAME, orig_tab.getDouble(origrownum,END_FIELD_NAME));
       
        tuple_array = this.reducepart_hash.get(curr_reduce);
        if (tuple_array == null) {
          tuple_array = new ArrayList<Tuple>();
          tuple_array.add(this.plot_tab.getTuple(newrownum));
          this.reducepart_hash.put(curr_reduce, tuple_array);
        } else {
          tuple_array.add(this.plot_tab.getTuple(newrownum));
        }
      } 
    }
   
    public void populateTable_MapsReducesOnly(Table orig_tab) {
      IntIterator rownumiter;
      int newrownum, origrownum;
      rownumiter = orig_tab.rows(
        (Predicate) ExpressionParser.parse("[state_name] == 'map' OR [state_name] == 'reduce'")
      );
      while (rownumiter.hasNext()) {
        origrownum = ((Integer)rownumiter.next()).intValue();
        newrownum = this.plot_tab.addRow();
        this.plot_tab.set(newrownum, "state_name", orig_tab.getString(origrownum, "state_name"));
        this.plot_tab.set(newrownum, "ycoord", orig_tab.getInt(origrownum, "seqno"));
        this.plot_tab.set(newrownum,"hostname",orig_tab.getString(origrownum,"hostname"));
        this.plot_tab.set(newrownum,"friendly_id",orig_tab.getString(origrownum,"friendly_id"));       
        this.plot_tab.set(newrownum,START_FIELD_NAME, orig_tab.getDouble(origrownum,START_FIELD_NAME));
        this.plot_tab.set(newrownum,START_FIELD_NAME, orig_tab.getDouble(origrownum,END_FIELD_NAME));
      }
    }
   
    /**
     * Reassigns Y coord values to group by state
     */
    public void groupByState() {
      int counter, rownum;
      int rowcount = this.plot_tab.getRowCount();
      HashSet<String> states = new HashSet<String>();
      String curr_state = null;
      Iterator<String> state_iter;
      IntIterator rownumiter;
     
      for (int i = 0; i < rowcount; i++) {
        states.add(this.plot_tab.getString(i,"state_name"));
      }
    
      state_iter = states.iterator();
      counter = 1;
      while (state_iter.hasNext()) {
        curr_state = state_iter.next();
       
        if (this.collate_reduces) {
          if (curr_state.equals("reduce_reducer") || curr_state.equals("reduce_sort")) {
            continue;
          }
        }
        rownumiter = this.plot_tab.rows(
          (Predicate) ExpressionParser.parse("[state_name] == '"+curr_state+"'")
        );
        if (this.collate_reduces && curr_state.equals("reduce_shufflewait")) {
          while (rownumiter.hasNext()) {
            rownum = ((Integer)rownumiter.next()).intValue();
            this.plot_tab.setFloat(rownum,"ycoord",(float)counter);
           
            ArrayList<Tuple> alt = this.reducepart_hash.get(this.plot_tab.getString(rownum,"friendly_id"));
            Object [] tarr = alt.toArray();
            for (int i = 0; i < tarr.length; i++) ((Tuple)tarr[i]).setFloat("ycoord",(float)counter);
            counter++;           
          }
        } else {
          while (rownumiter.hasNext()) {
            rownum = ((Integer)rownumiter.next()).intValue();
            this.plot_tab.setFloat(rownum,"ycoord",(float)counter);
            counter++;
          }         
        }
      }
    }
   
    public void groupByStartTime() {
      int counter, rownum;
      int rowcount = this.plot_tab.getRowCount();
      HashSet<String> states = new HashSet<String>();
      String curr_state = null;
      Iterator<String> state_iter;
      IntIterator rownumiter;
    
      rownumiter = this.plot_tab.rowsSortedBy(START_FIELD_NAME, true);
    
      counter = 1;
      while (rownumiter.hasNext()) {
        rownum = ((Integer)rownumiter.next()).intValue();
        curr_state = this.plot_tab.getString(rownum, "state_name");       

        if (this.collate_reduces && curr_state.equals("reduce_shufflewait")) {
          this.plot_tab.setFloat(rownum,"ycoord",(float)counter);
          ArrayList<Tuple> alt = this.reducepart_hash.get(this.plot_tab.getString(rownum,"friendly_id"));
          Object [] tarr = alt.toArray();
          for (int i = 0; i < tarr.length; i++) ((Tuple)tarr[i]).setFloat("ycoord",(float)counter);
          counter++;  
        } else if (!curr_state.equals("reduce_sort") && !curr_state.equals("reduce_reducer")) {
          this.plot_tab.setFloat(rownum,"ycoord",(float)counter);         
          counter++;
        }
      }
    }
   
    public void groupByEndTime() {
      int counter, rownum;
      int rowcount = this.plot_tab.getRowCount();
      HashSet<String> states = new HashSet<String>();
      String curr_state = null;
      Iterator<String> state_iter;
      IntIterator rownumiter;
    
      rownumiter = this.plot_tab.rowsSortedBy(END_FIELD_NAME, true);
      counter = 1;
      while (rownumiter.hasNext()) {
        rownum = ((Integer)rownumiter.next()).intValue();
        curr_state = this.plot_tab.getString(rownum, "state_name");       

        if (this.collate_reduces && curr_state.equals("reduce_reducer")) {
          this.plot_tab.setFloat(rownum,"ycoord",(float)counter);
          ArrayList<Tuple> alt = this.reducepart_hash.get(this.plot_tab.getString(rownum,"friendly_id"));
          Object [] tarr = alt.toArray();
          for (int i = 0; i < tarr.length; i++) ((Tuple)tarr[i]).setFloat("ycoord",(float)counter);
          counter++;
        } else if (!curr_state.equals("reduce_sort") && !curr_state.equals("reduce_shufflewait")) {
          this.plot_tab.setFloat(rownum,"ycoord",(float)counter);         
          counter++;
        }
      }
    }   
   
    public VisualTable addToVisualization(Visualization viz, String groupname) {
      return viz.addTable(groupname, this.plot_tab);
    }
  }

  /**
   * Provide constant mapping between state names and colours
   * so that even if particular states are missing, the colours are fixed
   * for each state
   */
  public static class SwimlanesStatePalette {
    protected final String [] states = {"map","reduce","reduce_shufflewait","reduce_sort","reduce_reducer","shuffle"};
    HashMap<String,Integer> colourmap;
    protected int [] palette;
    public SwimlanesStatePalette() {
      palette = ColorLib.getCategoryPalette(states.length);
      colourmap = new HashMap<String,Integer>();
      for (int i = 0; i < states.length; i++) {
        colourmap.put(states[i], new Integer(palette[i]));
      }
    }
    public int getColour(String state_name) {
      Integer val = colourmap.get(state_name);
      if (val == null) {
        return ColorLib.color(java.awt.Color.BLACK);
      } else {
        return val.intValue();
      }
    }
    public int getNumStates() {
      return this.states.length;
    }
    public String [] getStates() {
      return this.states;
    }
  }

  /**
   * Provides convenient rescaling of raw values to be plotted to
   * actual pixels for plotting on image
   */
  public static class CoordScaler {
    double x_pixel_size, y_pixel_size;
    double x_max_value, y_max_value, x_min_value, y_min_value;
    double x_start, y_start;
   
    public CoordScaler() {
      this.x_pixel_size = 0.0;
      this.y_pixel_size = 0.0;
      this.x_max_value = 1.0;
      this.y_max_value = 1.0;
      this.x_min_value = 0.0;
      this.y_min_value = 0.0;
      this.x_start = 0.0;
      this.y_start = 0.0;
    }
    public void set_pixel_start(double x, double y) {
      this.x_start = x;
      this.y_start = y;
    }
    public void set_pixel_size(double x, double y) {
      this.x_pixel_size = x;
      this.y_pixel_size = y;
    }
    public void set_value_ranges(double x_min, double y_min, double x_max, double y_max) {
      this.x_max_value = x_max;
      this.y_max_value = y_max;
      this.x_min_value = x_min;
      this.y_min_value = y_min;
    }
    public double get_x_coord(double x_value) {
      return x_start+(((x_value - x_min_value) / (x_max_value-x_min_value)) * x_pixel_size);
    }
    public double get_y_coord(double y_value) {
      // this does "inverting" to shift the (0,0) point from top-right to bottom-right
      return y_start+(y_pixel_size - ((((y_value - y_min_value) / (y_max_value-y_min_value)) * y_pixel_size)));
    }
  }

  /**
   * Prefuse action for plotting a line for each state
   */
  public static class SwimlanesStateAction extends GroupAction {
   
    protected CoordScaler cs;
   
    public SwimlanesStateAction() {
      super();
    }
   
    public SwimlanesStateAction(String group, CoordScaler cs) {
      super(group);
      this.cs = cs;
    }
   
    public void run (double frac) {
      VisualItem item = null;
      SwimlanesStatePalette pal = new SwimlanesStatePalette();
     
      Iterator curr_group_items = this.m_vis.items(this.m_group);
     
      int i = 0;
     
      while (curr_group_items.hasNext()) {
        item = (VisualItem) curr_group_items.next();
       
        double start_time = item.getDouble(START_FIELD_NAME);
        double finish_time = item.getDouble(END_FIELD_NAME);       
        item.setShape(Constants.POLY_TYPE_LINE);
        item.setX(0.0);
        item.setY(0.0);       
       
        float [] coords = new float[4];
        coords[0] = (float) cs.get_x_coord(start_time);
        coords[1] = (float) cs.get_y_coord((double)item.getInt("ycoord"));
        coords[2] = (float) cs.get_x_coord(finish_time);
        coords[3] = (float) cs.get_y_coord((double)item.getInt("ycoord"));

        item.set(VisualItem.POLYGON,coords);
        item.setStrokeColor(pal.getColour(item.getString("state_name")));
        i++;
      }
    }   
  } // SwimlanesStateAction

  // keys that need to be filled:
  // period (last1/2/3/6/12/24hr,last7d,last30d), time_type (range/last), start, end
  protected HashMap<String, String> param_map;
 
  protected String cluster;
  protected String timezone;
  protected String shuffle_option;
  protected final String table = new String("mapreduce_fsm");
  protected boolean plot_legend = true;
  protected String jobname = null;
 
  protected Display dis;
  protected Visualization viz;
 
  protected Rectangle2D dataBound = new Rectangle2D.Double();
  protected Rectangle2D xlabBound = new Rectangle2D.Double();
  protected Rectangle2D ylabBound = new Rectangle2D.Double();
  protected Rectangle2D labelBottomBound = new Rectangle2D.Double();
 
  static final String START_FIELD_NAME = "start_time_num";
  static final String END_FIELD_NAME = "finish_time_num";
 
  /* Different group names allow control of what Renderers to use */
  final String maingroup = "Job";
  final String othergroup = "Misc";
  final String labelgroup = "Label";
  final String legendgroup = "Legend";
  final String legendshapegroup = "LegendShape";
 
  public Swimlanes() {
    this.cluster = new String("");
    this.timezone = new String("");
    this.shuffle_option = new String("");
    param_map = new HashMap<String, String>();
  }
 
  /**
   * @brief Constructor for Swimlanes visualization object
   * @param timezone Timezone string from environment
   * @param cluster Cluster name from environment
   * @param event_type Whether to display shuffles or not
   * @param valmap HashMap of key/value pairs simulating parameters from a HttpRequest
   */
  public Swimlanes
    (String timezone, String cluster, String event_type,
     HashMap<String, String> valmap)
  {
    this.cluster = new String(cluster);
    if (timezone != null) {
      this.timezone = new String(timezone);
    } else {
      this.timezone = null;
    }
    this.shuffle_option = new String(event_type);
   
    /* This should "simulate" an HttpServletRequest
     * Need to have "start" and "end" in seconds since Epoch
     */
    this.param_map = valmap;
  }
 
  public Swimlanes
    (String timezone, String cluster, String event_type,
     HashMap<String, String> valmap, int width, int height)
  {
    this.cluster = new String(cluster);
    if (timezone != null) {
      this.timezone = new String(timezone);
    } else {
      this.timezone = null;
    }
    this.shuffle_option = new String(event_type);
   
    /* This should "simulate" an HttpServletRequest
     * Need to have "start" and "end" in seconds since Epoch
     */
    this.param_map = valmap;
   
    this.SIZE_X = width;
    this.SIZE_Y = height;
  }
 
  public Swimlanes
    (String timezone, String cluster, String event_type,
     HashMap<String, String> valmap, int width, int height,
     String legend_opt)
  {
    this.cluster = new String(cluster);
    if (timezone != null) {
      this.timezone = new String(timezone);
    } else {
      this.timezone = null;
    }
    this.shuffle_option = new String(event_type);
   
    /* This should "simulate" an HttpServletRequest
     * Need to have "start" and "end" in seconds since Epoch
     */
    this.param_map = valmap;
   
    this.SIZE_X = width;
    this.SIZE_Y = height;
   
    if (legend_opt.equals("nolegend")) {
      this.plot_legend = false;
    }
   
  }
 
  public Swimlanes(HttpServletRequest request) {
    XssFilter xf = new XssFilter(request);
    this.offline_use = false;
    this.request = request;
    HttpSession session = request.getSession();
    this.cluster = session.getAttribute("cluster").toString();
      String evt_type = xf.getParameter("event_type");
    if (evt_type != null) {
      this.shuffle_option = new String(evt_type);
    } else {
      this.shuffle_option = new String("noshuffle");
    }
    this.timezone = session.getAttribute("time_zone").toString();
  }
 
  /**
   * Set job ID to filter results on
   * Call before calling @see #run
   */
  public void setJobName(String s) {
    this.jobname = new String(s);
  }

  /**
   * Set dimensions of image to be generated
   * Call before calling @see #run
   */ 
  public void setDimensions(int width, int height) {
    this.SIZE_X=width;
    this.SIZE_Y=height;
  }
 
  /**
   * Specify whether to print legend of states
   * Advisable to not print legend for excessively small images since
   * legend has fixed point size
   * Call before calling @see #run
   */
  public void setLegend(boolean legendopt) {
    if (legendopt) {
      this.plot_legend = true;
    } else {
      this.plot_legend = false;
    }
  }
 
  /**
   * Generates image in specified format, and writes image as binary
   * output to supplied output stream
   */
  public boolean getImage(java.io.OutputStream output, String img_fmt, double scale) {
    dis = new Display(this.viz);
    dis.setSize(SIZE_X,SIZE_Y);
    dis.setHighQuality(true);
    dis.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,24));
    return dis.saveImage(output, img_fmt, scale);
  }
 
  /**
   * Adds a column to given table by converting timestamp to long with
   * seconds since epoch, and adding milliseconds from additional column
   * in original table
   *
   * @param origTable Table to add to
   * @param srcFieldName Name of column containing timestamp
   * @param srcMillisecondFieldName Name of column containing millisecond value of time
   * @param dstFieldName Name of new column to add
   *
   * @return Modified table with added column
   */
  protected Table addTimeCol
    (Table origTable, String srcFieldName,
     String srcMillisecondFieldName, String dstFieldName)
  {
    origTable.addColumn(dstFieldName, long.class);
   
    int total_rows = origTable.getRowCount();
    for (int curr_row_num = 0; curr_row_num < total_rows; curr_row_num++) {
      origTable.setLong(curr_row_num, dstFieldName,
        ((Timestamp)origTable.get(curr_row_num, srcFieldName)).getTime() +
        origTable.getLong(curr_row_num, srcMillisecondFieldName)
      );
    }
   
    return origTable;
  }
 
  /**
   * Adds a column with number of seconds of timestamp elapsed since lowest
   * start time; allows times to be plotted as a delta of the start time
   *
   * @param origTable Table to add column to
   * @param srcFieldName Name of column containing timestamp
   * @param srcMillisecondFieldName Name of column containing millisecond value of time
   * @param dstFieldName Name of new column to add
   *  
   * @return Modified table with added column
   */
  protected Table addTimeOffsetCol
    (Table origTable, String srcFieldName,
     String srcMillisecondFieldName, String dstFieldName,
     long timeOffset)
  {
    Table newtable = addTimeCol(origTable, srcFieldName,
      srcMillisecondFieldName, dstFieldName + "_fulltime");
     
    ColumnMetadata dstcol = newtable.getMetadata(dstFieldName + "_fulltime");
    long mintime = newtable.getLong(dstcol.getMinimumRow(), dstFieldName + "_fulltime");
   
    if (timeOffset == 0) {
      newtable.addColumn(dstFieldName, "ROUND((["+dstFieldName+"_fulltime] - " + mintime +"L) / 1000L)");
    } else {
      newtable.addColumn(dstFieldName, "ROUND((["+dstFieldName+"_fulltime] - " + timeOffset +"L) / 1000L)");     
    }
   
    return newtable;
  }
 
  protected void setupRenderer() {
    this.viz.setRendererFactory(new RendererFactory(){
      AbstractShapeRenderer sr = new ShapeRenderer();
      ShapeRenderer sr_big = new ShapeRenderer(20);
      Renderer arY = new AxisRenderer(Constants.LEFT, Constants.TOP);
      Renderer arX = new AxisRenderer(Constants.CENTER, Constants.BOTTOM);
      PolygonRenderer pr = new PolygonRenderer(Constants.POLY_TYPE_LINE);
      LabelRenderer lr = new LabelRenderer("label");
      LabelRenderer lr_legend = new LabelRenderer("label");
     
      public Renderer getRenderer(VisualItem item) {
        lr.setHorizontalAlignment(Constants.CENTER);
        lr.setVerticalAlignment(Constants.TOP);
        lr_legend.setHorizontalAlignment(Constants.LEFT);
        lr_legend.setVerticalAlignment(Constants.CENTER);
       
        if (item.isInGroup("ylab")) {
          return arY;
        } else if (item.isInGroup("xlab")) {
          return arX;
        } else if (item.isInGroup(maingroup)) {
          return pr;
        } else if (item.isInGroup(labelgroup)) {
          return lr;
        } else if (item.isInGroup(legendgroup)) {
          return lr_legend;
        } else if (item.isInGroup(legendshapegroup)) {
          return sr_big;
        } else {
          return sr;
        }
      }
    });
  }
 
  // setup columns: add additional time fields
  protected Table setupDataTable() {
    Table res_tab = this.getData();   
    if (res_tab == null) {
        return res_tab;
    }
   
    res_tab.addColumn("seqno","ROW()");
    res_tab = addTimeOffsetCol(res_tab, "start_time", "start_time_millis", START_FIELD_NAME, 0);   
    ColumnMetadata dstcol = res_tab.getMetadata(START_FIELD_NAME);
    long mintime = ((Timestamp)res_tab.get(dstcol.getMinimumRow(), "start_time")).getTime();
    res_tab = addTimeOffsetCol(res_tab, "finish_time", "finish_time_millis", END_FIELD_NAME, mintime);   
    res_tab.addColumn(PolygonRenderer.POLYGON,float[].class);
   
    log.debug("After adding seqno: #cols: " + res_tab.getColumnCount() + "; #rows: " + res_tab.getRowCount());
   
    return res_tab;
  }
 
  protected void addAxisNames() {
    Table textlabels_table = new Table();
    textlabels_table.addColumn("label",String.class);
    textlabels_table.addColumn("type",String.class);
    textlabels_table.addRow();
    textlabels_table.setString(0,"label",new String("Time/s"));
    textlabels_table.setString(0,"type",new String("xaxisname"));
   
    VisualTable textlabelsviz = this.viz.addTable(labelgroup, textlabels_table);
    textlabelsviz.setX(0,SIZE_X/2);
    textlabelsviz.setY(0,SIZE_Y - BORDER[2] + (BORDER[2]*0.1));
    textlabelsviz.setTextColor(0,ColorLib.color(java.awt.Color.GRAY));
    textlabelsviz.setFont(0,new Font(Font.SANS_SERIF,Font.PLAIN,AXIS_NAME_FONT_SIZE));
  }
 
  protected void addLegend() {
    SwimlanesStatePalette ssp = new SwimlanesStatePalette();
   
    Table shapes_table = new Table();
    shapes_table.addColumn(VisualItem.X,float.class);
    shapes_table.addColumn(VisualItem.Y,float.class);
   
    Table legend_labels_table = new Table();
    Table legend_squares_table = new Table();
    legend_labels_table.addColumn("label",String.class);
   
    // add labels
    int num_states = ssp.getNumStates();
    String [] state_names = ssp.getStates();
    legend_labels_table.addRows(num_states);
    shapes_table.addRows(num_states);
    for (int i = 0; i < num_states; i++) {
      legend_labels_table.setString(i,"label",state_names[i]);
    }
   
    // add legend shapes, manipulate visualitems to set colours
    VisualTable shapes_table_viz = viz.addTable(legendshapegroup, shapes_table);
    float start_x = BORDER[0] + LEGEND_X_OFFSET;
    float start_y = BORDER[1] + LEGEND_Y_OFFSET;
    float incr = (float) 30.0;
    for (int i = 0; i < num_states; i++) {
      shapes_table_viz.setFillColor(i, ssp.getColour(state_names[i]));
      shapes_table_viz.setFloat(i, VisualItem.X, start_x);
      shapes_table_viz.setFloat(i, VisualItem.Y, start_y + (i * incr));
    }
   
    // add legend labels, manipulate visualitems to set font
    VisualTable legend_labels_table_viz = this.viz.addTable(legendgroup, legend_labels_table);
    for (int i = 0; i < num_states; i++) {
      legend_labels_table_viz.setFloat(i, VisualItem.X, start_x + LEGEND_TEXT_OFFSET);
      legend_labels_table_viz.setFloat(i, VisualItem.Y, start_y + (i * incr));
      legend_labels_table_viz.setTextColor(i,ColorLib.color(java.awt.Color.BLACK));
      legend_labels_table_viz.setFont(i,new Font(Font.SANS_SERIF,Font.PLAIN,LEGEND_FONT_SIZE));
    }
   
  }
 
  public void run() {

    // setup bounds
    this.dataBound.setRect(BORDER[0],BORDER[1],SIZE_X-BORDER[2]-BORDER[0],SIZE_Y-BORDER[3]-BORDER[1]);
    this.xlabBound.setRect(BORDER[0],BORDER[1],SIZE_X-BORDER[2]-BORDER[0],SIZE_Y-BORDER[3]-BORDER[1]);
    this.ylabBound.setRect(BORDER[0],BORDER[1],SIZE_X-BORDER[2]-BORDER[0],SIZE_Y-BORDER[3]-BORDER[1]);
    this.labelBottomBound.setRect(BORDER[0],SIZE_X-BORDER[2],SIZE_Y-BORDER[0]-BORDER[1],BORDER[3]);
   
    // setup visualization
    this.viz = new Visualization();
    this.setupRenderer();
   
    // add table to visualization
    Table raw_data_tab = this.setupDataTable();
    MapReduceSwimlanes mrs = new MapReduceSwimlanes();
    mrs.populateTable_CollateReduces(raw_data_tab);
    mrs.groupByState();
    VisualTable maindatatable = mrs.addToVisualization(this.viz, maingroup);
       
    addAxisNames();
    if (plot_legend) {
      addLegend();
    }

    // plot swimlanes lines: setup axes, call custom action
    ActionList draw = new ActionList();
    {
      // setup axes
      AxisLayout xaxis = new AxisLayout(maingroup, START_FIELD_NAME, Constants.X_AXIS, VisiblePredicate.TRUE);
      AxisLayout yaxis = new AxisLayout(maingroup, "ycoord", Constants.Y_AXIS, VisiblePredicate.FALSE);   
      xaxis.setLayoutBounds(dataBound);
      yaxis.setLayoutBounds(dataBound);
   
      ColumnMetadata starttime_meta = maindatatable.getMetadata(START_FIELD_NAME);   
      ColumnMetadata finishtime_meta = maindatatable.getMetadata(END_FIELD_NAME);   
      ColumnMetadata ycoord_meta = maindatatable.getMetadata("ycoord");
      long x_min = (long) ((Double)maindatatable.get(starttime_meta.getMinimumRow(), START_FIELD_NAME)).doubleValue();
      long x_max = (long) ((Double)maindatatable.get(finishtime_meta.getMaximumRow(), END_FIELD_NAME)).doubleValue();
      xaxis.setRangeModel(new NumberRangeModel(x_min,x_max,x_min,x_max));
      float y_max = maindatatable.getFloat(ycoord_meta.getMaximumRow(),"ycoord");
      yaxis.setRangeModel(new NumberRangeModel(0,y_max,0,y_max));
     
      // call custom action to plot actual swimlanes lines
      CoordScaler cs = new CoordScaler();
      cs.set_pixel_size(SIZE_X-BORDER[0]-BORDER[2], SIZE_Y-BORDER[1]-BORDER[3]);
      cs.set_pixel_start(BORDER[0],BORDER[1]);
      cs.set_value_ranges(x_min,0,x_max,y_max);
      //SwimlanesStateAction swimlaneslines = new SwimlanesStateAction(maingroup, cs);
      SwimlanesStateAction swimlaneslines = new SwimlanesStateAction(maingroup, cs);
     
      // add everything to the plot
      draw.add(xaxis);
      draw.add(yaxis);
      draw.add(swimlaneslines);
     
      AxisLabelLayout xlabels = new AxisLabelLayout("xlab", xaxis, xlabBound);
      this.viz.putAction("xlabels",xlabels);
      AxisLabelLayout ylabels = new AxisLabelLayout("ylab", yaxis, ylabBound);
      this.viz.putAction("ylabels",ylabels);
    }
   
    // add axes names
    {
      SpecifiedLayout sl = new SpecifiedLayout(labelgroup, VisualItem.X, VisualItem.Y);
      ActionList labeldraw = new ActionList();
      labeldraw.add(sl);
      this.viz.putAction(labelgroup, labeldraw);
    }
   
    // add legend
    if (plot_legend) {
      ShapeAction legend_sa = new ShapeAction(legendshapegroup);
      SpecifiedLayout legendlabels_sl = new SpecifiedLayout(legendgroup, VisualItem.X, VisualItem.Y);
   
      ActionList legenddraw = new ActionList();
      legenddraw.add(legend_sa);
      this.viz.putAction(legendshapegroup, legenddraw);
      ActionList legendlabelsdraw = new ActionList();
      legendlabelsdraw.add(legendlabels_sl);
      this.viz.putAction(legendgroup,legendlabelsdraw);
    }
   
    // draw everything else
    this.viz.putAction("draw",draw);

    // finally draw
    this.viz.run("draw");
    this.viz.run("xlabels");
    this.viz.run("ylabels");

  }
 
  public Table getData() {
    // preliminary setup
    OfflineTimeHandler time_offline;
    TimeHandler time_online;
    long start, end;
   
    if (offline_use) {
      time_offline = new OfflineTimeHandler(param_map, this.timezone);
      start = time_offline.getStartTime();
      end = time_offline.getEndTime();
    } else {
      time_online = new TimeHandler(this.request, this.timezone);
      start = time_online.getStartTime();
      end = time_online.getEndTime();
    }
   
    DatabaseWriter dbw = new DatabaseWriter(this.cluster);
    String query;
   
    // setup query
    if (this.shuffle_option != null && this.shuffle_option.equals("shuffles")) {
      query = "select job_id,friendly_id,start_time,finish_time,start_time_millis,finish_time_millis,status,state_name,hostname from ["+this.table+"] where finish_time between '[start]' and '[end]'";
    } else {
      query = "select job_id,friendly_id,start_time,finish_time,start_time_millis,finish_time_millis,status,state_name,hostname from ["+this.table+"] where finish_time between '[start]' and '[end]' and not state_name like 'shuffle_local' and not state_name like 'shuffle_remote'";
    }
    if (this.jobname != null) {
      query = query + " and job_id like '"+ this.jobname +"'";
    }
    Macro mp = new Macro(start,end,query);
    query = mp.toString() + " order by start_time";
   
    Table rs_tab = null;   
    DatabaseDataSource dds;
    DefaultSQLDataHandler dh = new DefaultSQLDataHandler();

    log.debug("Query: " + query);
    // execute query
    try {
      dds = ConnectionFactory.getDatabaseConnection(dbw.getConnection());
      rs_tab = dds.getData(query);
    } catch (prefuse.data.io.DataIOException e) {
      System.err.println("prefuse data IO error: " + e);
      log.warn("prefuse data IO error: " + e);
      return null;
    } catch (SQLException e) {
      System.err.println("Error in SQL: " + e + " in statement: " + query);
      log.warn("Error in SQL: " + e + " in statement: " + query);
      return null;
    }
   
    HashMap<String, Integer> state_counts = new HashMap<String, Integer>();
    HashSet<String> states = new HashSet<String>();
    for (int i = 0; i < rs_tab.getRowCount(); i++) {
      String curr_state = rs_tab.getString(i, "state_name");
      states.add(curr_state);
      Integer cnt = state_counts.get(curr_state);
      if (cnt == null) {
        state_counts.put(curr_state, new Integer(1));
      } else {
        state_counts.remove(curr_state);
        state_counts.put(curr_state, new Integer(cnt.intValue()+1));
      }
    }
   
    log.info("Search complete: #cols: " + rs_tab.getColumnCount() + "; #rows: " + rs_tab.getRowCount());
   
    return rs_tab;
  }
 
}
TOP

Related Classes of org.apache.hadoop.chukwa.analysis.salsa.visualization.Swimlanes$MapReduceSwimlanes

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.