You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@chukwa.apache.org by ey...@apache.org on 2015/04/27 02:37:46 UTC

[4/4] chukwa git commit: CHUKWA-745. Improved chart configuration management. (Eric Yang)

CHUKWA-745. Improved chart configuration management.  (Eric Yang)


Project: http://git-wip-us.apache.org/repos/asf/chukwa/repo
Commit: http://git-wip-us.apache.org/repos/asf/chukwa/commit/a6e0cbad
Tree: http://git-wip-us.apache.org/repos/asf/chukwa/tree/a6e0cbad
Diff: http://git-wip-us.apache.org/repos/asf/chukwa/diff/a6e0cbad

Branch: refs/heads/master
Commit: a6e0cbad7cd52cc04a5363c04bc0fbd5b78f66be
Parents: 16927ce
Author: Eric Yang <ey...@apache.org>
Authored: Sun Apr 26 14:52:58 2015 -0700
Committer: Eric Yang <ey...@apache.org>
Committed: Sun Apr 26 17:25:26 2015 -0700

----------------------------------------------------------------------
 CHANGES.txt                                     |   2 +
 bin/chukwa                                      |   1 +
 conf/hbase.schema                               |   3 +-
 pom.xml                                         |  11 +
 .../writer/hbase/HBaseWriter.java               |  15 +-
 .../chukwa/datastore/ChukwaHBaseStore.java      | 174 +++++++-
 .../extraction/hbase/AbstractProcessor.java     |   2 -
 .../apache/hadoop/chukwa/hicc/BarOptions.java   |  30 ++
 .../org/apache/hadoop/chukwa/hicc/Chart.java    | 446 ++++---------------
 .../hadoop/chukwa/hicc/HiccWebServer.java       |  19 +
 .../apache/hadoop/chukwa/hicc/LineOptions.java  |  25 ++
 .../apache/hadoop/chukwa/hicc/PointOptions.java |  27 ++
 .../org/apache/hadoop/chukwa/hicc/Series.java   | 121 +++++
 .../hadoop/chukwa/hicc/SeriesOptions.java       |  33 ++
 .../apache/hadoop/chukwa/hicc/bean/Series.java  |   4 +
 .../chukwa/hicc/rest/ChartController.java       | 187 ++++++++
 .../chukwa/hicc/rest/MetricsController.java     |   7 +-
 .../chukwa/hicc/rest/VelocityResolver.java      |  86 ++++
 .../apache/hadoop/chukwa/util/HBaseUtil.java    |  17 +
 src/main/web/hicc/WEB-INF/vm/chart.vm           | 106 +++++
 .../web/hicc/WEB-INF/vm/unit-bytes-binary.vm    |  27 ++
 .../web/hicc/WEB-INF/vm/unit-bytes-decimal.vm   |  27 ++
 src/main/web/hicc/WEB-INF/vm/unit-generic.vm    |  20 +
 src/main/web/hicc/WEB-INF/vm/unit-ops.vm        |  20 +
 src/main/web/hicc/WEB-INF/vm/unit-percent.vm    |  20 +
 src/main/web/hicc/css/default.css               |  11 +-
 src/main/web/hicc/css/iframe.css                |  91 +++-
 src/main/web/hicc/js/flot.extend.js             | 170 +++----
 src/main/web/hicc/jsp/graph_explorer.jsp        | 204 ++++-----
 .../apache/hadoop/chukwa/hicc/TestChart.java    |  84 ++--
 30 files changed, 1321 insertions(+), 669 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index dd3f642..5e3e93c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -10,6 +10,8 @@ Trunk (unreleased changes)
 
   IMPROVEMENTS
 
+    CHUKWA-745. Improved chart configuration management.  (Eric Yang)
+
     CHUKWA-744. Implemented new parsers for extract and transform data to HBase format.  (Eric Yang)
 
     CHUKWA-667. Optimize HBase metrics schema.  (Eric Yang)

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/bin/chukwa
----------------------------------------------------------------------
diff --git a/bin/chukwa b/bin/chukwa
index 1a3a341..db77200 100755
--- a/bin/chukwa
+++ b/bin/chukwa
@@ -153,6 +153,7 @@ fi
 pid="$CHUKWA_PID_DIR/chukwa-$CHUKWA_IDENT_STRING-$COMMAND.pid"
 
 if [ "$1" = "start" ]; then
+  shift
   if [ -f $pid ]; then
     TARGET_PID=`cat $pid`
     if kill -0 `cat $pid` > /dev/null 2>&1; then

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/conf/hbase.schema
----------------------------------------------------------------------
diff --git a/conf/hbase.schema b/conf/hbase.schema
index 5e32f90..54e5b01 100644
--- a/conf/hbase.schema
+++ b/conf/hbase.schema
@@ -1,5 +1,6 @@
 create "chukwa_meta",
-{NAME=>"k"}
+{NAME=>"k"},
+{NAME=>"c"}
 create "chukwa", 
 {NAME=>"t"},
 {NAME=>"a"}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6beaef8..1c8d26c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -109,6 +109,16 @@
 	    <version>1.8.1</version>
           </dependency>
           <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+            <version>1.7</version>
+          </dependency>
+          <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-tools</artifactId>
+            <version>2.0</version>
+          </dependency>
+          <dependency>
             <groupId>edu.berkeley.confspell</groupId>
             <artifactId>confspellcheck</artifactId>
             <version>1.0</version>
@@ -481,6 +491,7 @@
                         <exclude>**/JobLog.java</exclude>
                         <exclude>**/TestJobLogEntry.java</exclude>
                         <exclude>**/TestDemuxManager.java</exclude>
+                        <exclude>**/TestFSMBuilder.java</exclude>
                       </testExcludes>
                     </configuration>
                   </execution>

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java b/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java
index 34c82e1..e5a8083 100644
--- a/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java
+++ b/src/main/java/org/apache/hadoop/chukwa/datacollection/writer/hbase/HBaseWriter.java
@@ -37,10 +37,14 @@ import org.apache.hadoop.chukwa.extraction.hbase.UnknownRecordTypeException;
 import org.apache.hadoop.chukwa.util.ExceptionUtil;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.ConnectionFactory;
 import org.apache.hadoop.hbase.client.HConnection;
 import org.apache.hadoop.hbase.client.HConnectionManager;
 import org.apache.hadoop.hbase.client.HTableInterface;
 import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Table;
 import org.apache.log4j.Logger;
 
 public class HBaseWriter extends PipelineableWriter {
@@ -54,7 +58,7 @@ public class HBaseWriter extends PipelineableWriter {
   private Reporter reporter;
   private ChukwaConfiguration conf;
   String defaultProcessor;
-  private HConnection connection;
+  private static Connection connection;
   
   private class StatReportingTask extends TimerTask {
     private long lastTs = System.currentTimeMillis();
@@ -105,7 +109,9 @@ public class HBaseWriter extends PipelineableWriter {
     } catch (NoSuchAlgorithmException e) {
       throw new IOException("Can not register hashing algorithm.");
     }
-    connection = HConnectionManager.createConnection(hconf);
+    if (connection == null) {
+      connection = ConnectionFactory.createConnection(hconf);
+    }
   }
 
   public void close() {
@@ -121,8 +127,8 @@ public class HBaseWriter extends PipelineableWriter {
   public CommitStatus add(List<Chunk> chunks) throws WriterException {
     CommitStatus rv = ChukwaWriter.COMMIT_OK;
     try {
-      HTableInterface hbase = connection.getTable(CHUKWA_TABLE);              
-      HTableInterface meta = connection.getTable(CHUKWA_META_TABLE);              
+      Table hbase = connection.getTable(TableName.valueOf(CHUKWA_TABLE));
+      Table meta = connection.getTable(TableName.valueOf(CHUKWA_META_TABLE));
       for(Chunk chunk : chunks) {
         synchronized (this) {
           try {
@@ -140,6 +146,7 @@ public class HBaseWriter extends PipelineableWriter {
         }
       }
       hbase.close();
+      meta.close();
     } catch (Exception e) {
       log.error(ExceptionUtil.getStackTrace(e));
       throw new WriterException("Failed to store data to HBase.");

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java b/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java
index d9c32d6..7494aa8 100644
--- a/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java
+++ b/src/main/java/org/apache/hadoop/chukwa/datastore/ChukwaHBaseStore.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -29,11 +30,13 @@ import java.util.Map.Entry;
 import java.util.NavigableMap;
 import java.util.Set;
 import java.util.TimeZone;
+import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.hadoop.chukwa.hicc.Chart;
 import org.apache.hadoop.chukwa.hicc.bean.HeatMapPoint;
 import org.apache.hadoop.chukwa.hicc.bean.Heatmap;
 import org.apache.hadoop.chukwa.hicc.bean.Series;
@@ -48,6 +51,7 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.client.Connection;
 import org.apache.hadoop.hbase.client.ConnectionFactory;
 import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.client.ResultScanner;
 import org.apache.hadoop.hbase.client.Scan;
@@ -56,16 +60,37 @@ import org.apache.log4j.Logger;
 import org.json.simple.JSONObject;
 import org.json.simple.JSONValue;
 
+import com.google.gson.Gson;
+
 public class ChukwaHBaseStore {
   private static Configuration hconf = HBaseConfiguration.create();
   static Logger LOG = Logger.getLogger(ChukwaHBaseStore.class);
   static byte[] COLUMN_FAMILY = "t".getBytes();
   static byte[] ANNOTATION_FAMILY = "a".getBytes();
   static byte[] KEY_NAMES = "k".getBytes();
+  static byte[] CHART_TYPE = "chart_meta".getBytes();
+  static byte[] CHART_FAMILY = "c".getBytes();
   private static final String CHUKWA = "chukwa";
   private static final String CHUKWA_META = "chukwa_meta";
   private static long MILLISECONDS_IN_DAY = 86400000L;
+  private static Connection connection = null;
 
+  public static void getHBaseConnection() throws IOException {
+    if (connection == null || connection.isClosed()) {
+      connection = ConnectionFactory.createConnection(hconf);
+    }
+  }
+  
+  public static void closeHBase() {
+    try {
+      if(connection != null) {
+        connection.close();
+      }
+    } catch(IOException e) {
+      LOG.warn("Unable to release HBase connection.");
+    }
+  }
+  
   /**
    * Scan chukwa table for a particular metric group and metric name based on
    * time ranges.
@@ -93,7 +118,7 @@ public class ChukwaHBaseStore {
    * @param endTime
    * @return
    */
-  public static Series getSeries(String metric, String source, long startTime,
+  public static synchronized Series getSeries(String metric, String source, long startTime,
       long endTime) {
     String seriesName = new StringBuilder(metric).append(":").append(source).toString();
     Series series = new Series(seriesName);
@@ -104,7 +129,7 @@ public class ChukwaHBaseStore {
         startTime = endTime;
         endTime = temp;
       }
-      Connection connection = ConnectionFactory.createConnection(hconf);
+      getHBaseConnection();
       Table table = connection.getTable(TableName.valueOf(CHUKWA));
       Scan scan = new Scan();
       Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
@@ -144,6 +169,7 @@ public class ChukwaHBaseStore {
       }
       table.close();
     } catch (Exception e) {
+      closeHBase();
       LOG.error(ExceptionUtil.getStackTrace(e));
     }
     return series;
@@ -152,7 +178,7 @@ public class ChukwaHBaseStore {
   public static Set<String> getMetricNames(String metricGroup) {
     Set<String> familyNames = new CopyOnWriteArraySet<String>();
     try {
-      Connection connection = ConnectionFactory.createConnection(hconf);
+      getHBaseConnection();
       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
       Get get = new Get(metricGroup.getBytes());
       Result result = table.get(get);
@@ -163,8 +189,8 @@ public class ChukwaHBaseStore {
         }
       }
       table.close();
-      connection.close();
     } catch (Exception e) {
+      closeHBase();
       LOG.error(ExceptionUtil.getStackTrace(e));
     }
     return familyNames;
@@ -174,7 +200,7 @@ public class ChukwaHBaseStore {
   public static Set<String> getMetricGroups() {
     Set<String> metricGroups = new CopyOnWriteArraySet<String>();
     try {
-      Connection connection = ConnectionFactory.createConnection(hconf);
+      getHBaseConnection();
       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
       Scan scan = new Scan();
       scan.addFamily(KEY_NAMES);
@@ -185,8 +211,8 @@ public class ChukwaHBaseStore {
         metricGroups.add(new String(result.getRow(), "UTF-8"));
       }
       table.close();
-      connection.close();
     } catch (Exception e) {
+      closeHBase();
       LOG.error(ExceptionUtil.getStackTrace(e));
     }
     return metricGroups;
@@ -195,7 +221,7 @@ public class ChukwaHBaseStore {
   public static Set<String> getSourceNames(String dataType) {
     Set<String> pk = new HashSet<String>();
     try {
-      Connection connection = ConnectionFactory.createConnection(hconf);
+      getHBaseConnection();
       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
       Scan scan = new Scan();
       scan.addFamily(KEY_NAMES);
@@ -211,8 +237,8 @@ public class ChukwaHBaseStore {
         }
       }
       table.close();
-      connection.close();
     } catch (Exception e) {
+      closeHBase();
       LOG.error(ExceptionUtil.getStackTrace(e));
     }
     return pk;
@@ -227,7 +253,7 @@ public class ChukwaHBaseStore {
     List<Get> series = new ArrayList<Get>();
     String fullName = new StringBuilder(metricGroup).append(".").append(metric).toString();
     try {
-      Connection connection = ConnectionFactory.createConnection(hconf);
+      getHBaseConnection();
       Table table = connection.getTable(TableName.valueOf(CHUKWA));
       Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
       c.setTimeInMillis(startTime);
@@ -288,6 +314,7 @@ public class ChukwaHBaseStore {
       heatmap.putRadius(radius);
       heatmap.putSeries(index);
     } catch (IOException e) {
+      closeHBase();
       LOG.error(ExceptionUtil.getStackTrace(e));
     }
     return heatmap;
@@ -304,7 +331,7 @@ public class ChukwaHBaseStore {
   public static Set<String> getClusterNames(long startTime, long endTime) {
     Set<String> clusters = new HashSet<String>();
     try {
-      Connection connection = ConnectionFactory.createConnection(hconf);
+      getHBaseConnection();
       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
       Scan scan = new Scan();
       scan.addFamily(KEY_NAMES);
@@ -320,11 +347,136 @@ public class ChukwaHBaseStore {
         }
       }
       table.close();
-      connection.close();
     } catch (Exception e) {
+      closeHBase();
       LOG.error(ExceptionUtil.getStackTrace(e));
     }
     return clusters;
   }
 
+  public static Chart getChart(String id) {
+    Chart chart = null;
+    try {
+      getHBaseConnection();
+      Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
+      Get get = new Get(CHART_TYPE);
+      Result r = table.get(get);
+      byte[] value = r.getValue(CHART_FAMILY, id.getBytes());
+      Gson gson = new Gson();
+      if(value!=null) {
+        chart = gson.fromJson(new String(value), Chart.class);
+      }
+      table.close();
+    } catch (Exception e) {
+      closeHBase();
+      LOG.error(ExceptionUtil.getStackTrace(e));
+    }
+    return chart;
+  }
+
+  public static void putChart(String id, Chart chart) {
+    try {
+      getHBaseConnection();
+      Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
+      Put put = new Put(CHART_TYPE);
+      Gson gson = new Gson();
+      String buffer = gson.toJson(chart);
+      put.add(CHART_FAMILY, id.getBytes(), buffer.getBytes());
+      table.put(put);
+      table.close();
+    } catch (Exception e) {
+      closeHBase();
+      LOG.error(ExceptionUtil.getStackTrace(e));
+    }
+    
+  }
+
+  public static String createChart(Chart chart) throws IOException {
+    getHBaseConnection();
+    String id = chart.getId();
+    if(id!=null) {
+      // Check if there is existing chart with same id.
+      Chart test = getChart(id);
+      if(test!=null) {
+        // If id already exists, randomly generate an id.
+        id = String.valueOf(UUID.randomUUID());
+      }
+    } else {
+      // If id is not provided, randomly generate an id.
+      id = String.valueOf(UUID.randomUUID());
+    }
+    chart.setId(id);
+    Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
+    Put put = new Put(CHART_TYPE);
+    Gson gson = new Gson();
+    String buffer = gson.toJson(chart);
+    put.add(CHART_FAMILY, id.getBytes(), buffer.getBytes());
+    table.put(put);
+    table.close();
+    return id;
+  }
+
+  public static synchronized ArrayList<org.apache.hadoop.chukwa.hicc.Series> getChartSeries(ArrayList<org.apache.hadoop.chukwa.hicc.Series> series, long startTime, long endTime) {
+    ArrayList<org.apache.hadoop.chukwa.hicc.Series> list = new ArrayList<org.apache.hadoop.chukwa.hicc.Series>();
+    try {
+      // Swap start and end if the values are inverted.
+      if (startTime > endTime) {
+        long temp = endTime;
+        startTime = endTime;
+        endTime = temp;
+      }
+      getHBaseConnection();
+      Table table = connection.getTable(TableName.valueOf(CHUKWA));
+      Scan scan = new Scan();
+      Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+      c.setTimeInMillis(startTime);
+      int startDay = c.get(Calendar.DAY_OF_YEAR);
+      c.setTimeInMillis(endTime);
+      int endDay = c.get(Calendar.DAY_OF_YEAR);
+      for (org.apache.hadoop.chukwa.hicc.Series s : series) {
+        org.apache.hadoop.chukwa.hicc.Series clone = (org.apache.hadoop.chukwa.hicc.Series) s.clone();
+        long currentDay = startTime;
+        String[] parts = s.getUrl().toString().split("/");
+        String metric = parts[5];
+        String source = parts[6];
+        ArrayList<ArrayList<Number>> data = new ArrayList<ArrayList<Number>>();
+        for (int i = startDay; i <= endDay; i++) {
+          byte[] rowKey = HBaseUtil.buildKey(currentDay, metric, source);
+          scan.addFamily(COLUMN_FAMILY);
+          scan.setStartRow(rowKey);
+          scan.setStopRow(rowKey);
+          scan.setTimeRange(startTime, endTime);
+          scan.setBatch(10000);
+
+          ResultScanner results = table.getScanner(scan);
+          Iterator<Result> it = results.iterator();
+          // TODO: Apply discrete wavelet transformation to limit the output
+          // size to 1000 data points for graphing optimization. (i.e jwave)
+          while (it.hasNext()) {
+            Result result = it.next();
+            for (KeyValue kv : result.raw()) {
+              byte[] key = kv.getQualifier();
+              long timestamp = ByteBuffer.wrap(key).getLong();
+              double value = Double.parseDouble(new String(kv.getValue(),
+                  "UTF-8"));
+              ArrayList<Number> points = new ArrayList<Number>();
+              points.add(timestamp);
+              points.add(value);
+              data.add(points);
+            }
+          }
+          results.close();
+          currentDay = currentDay + (i * MILLISECONDS_IN_DAY);
+        }
+        clone.setData(data);
+        list.add(clone);
+      }
+      table.close();
+    } catch (Exception e) {
+      closeHBase();
+      LOG.error(ExceptionUtil.getStackTrace(e));
+    }
+    return list;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java b/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java
index b39c789..eb79cd7 100644
--- a/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java
+++ b/src/main/java/org/apache/hadoop/chukwa/extraction/hbase/AbstractProcessor.java
@@ -22,8 +22,6 @@ import java.nio.ByteBuffer;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.TimeZone;
 
 import org.apache.hadoop.chukwa.Chunk;
 import org.apache.hadoop.chukwa.datacollection.writer.hbase.Reporter;

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java
new file mode 100644
index 0000000..9ab686d
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/BarOptions.java
@@ -0,0 +1,30 @@
+/*
+ * 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.hicc;
+
+public class BarOptions extends SeriesOptions {
+  public boolean zero;
+  public boolean stepByStep = true;
+  public int barWidth = 4;
+  public String align;
+  public boolean horizontal;
+  
+  public BarOptions() {
+    fill = true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java b/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java
index 76ba919..ab6dc4e 100644
--- a/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/Chart.java
@@ -19,27 +19,13 @@
 package org.apache.hadoop.chukwa.hicc;
 
 
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.TreeMap;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map.Entry;
-import java.text.SimpleDateFormat;
-import javax.servlet.http.HttpServletRequest;
-import javax.swing.text.html.HTMLDocument.Iterator;
 
-import org.apache.hadoop.chukwa.util.XssFilter;
-import org.json.JSONArray;
-
-@SuppressWarnings("unused")
 public class Chart {
   private String id;
   private String title;
-  private String graphType;
-  private ArrayList<TreeMap<String, TreeMap<String, Double>>> dataset;
-  private ArrayList<String> chartType;
-  private ArrayList<String> restData;
+  private List<Series> series;
   private boolean xLabelOn;
   private boolean yLabelOn;
   private boolean yRightLabelOn;
@@ -47,45 +33,27 @@ public class Chart {
   private int height;
   private List<String> xLabelRange;
   private HashMap<String, Long> xLabelRangeHash;
-  private HttpServletRequest request = null;
-  private boolean legend;
+  private boolean legend = true;
   private String xLabel = "";
   private String yLabel = "";
   private String yRightLabel = "";
-  private int datasetCounter = 0;
   private double max = 0;
   private double min = 0;
-  private int seriesCounter = 0;
-  private List<String> rightList;
-  private boolean userDefinedMax = false;
-  private boolean userDefinedMin = false;
-  private boolean displayPercentage = false;
-  private String[] seriesOrder = null;
-  private XssFilter xf = null;
-  
-  public Chart(HttpServletRequest request) {
-    xf = new XssFilter(request);
-    if (request != null && xf.getParameter("boxId") != null) {
-      this.id = xf.getParameter("boxId");
-    } else {
-      this.id = "0";
-    }
+  private boolean userDefinedMax = true;
+  private boolean userDefinedMin = true;
+  private String yUnitType = "";
+
+  public Chart(String id) {
+    this.id = id;
     this.title = "Untitled Chart";
-    this.graphType = "image";
     this.xLabelOn = true;
     this.yLabelOn = true;
-    this.width = 400;
-    this.height = 200;
-    this.request = request;
+    this.width = 100;
+    this.height = 100;
     this.legend = true;
     this.max = 0;
-    this.datasetCounter = 0;
-    this.seriesCounter = 0;
-    this.rightList = new ArrayList<String>();
     this.userDefinedMax = false;
     this.userDefinedMin = false;
-    this.displayPercentage = false;
-    this.seriesOrder = null;
   }
 
   public void setYMax(double max) {
@@ -93,13 +61,25 @@ public class Chart {
     this.userDefinedMax = true;
   }
 
+  public double getYMax() {
+    return this.max;
+  }
+
+  public boolean getUserDefinedMax() {
+    return this.userDefinedMax;
+  }
+
   public void setYMin(double min) {
     this.min = min;
     this.userDefinedMin = true;
   }
 
-  public void setDisplayPercentage(boolean percentage) {
-    this.displayPercentage = percentage;
+  public double getYMin() {
+    return this.min;
+  }
+
+  public boolean getUserDefinedMin() {
+    return this.userDefinedMin;
   }
 
   public void setSize(int width, int height) {
@@ -107,71 +87,86 @@ public class Chart {
     this.height = height;
   }
 
-  public void setGraphType(String graphType) {
-    if (graphType != null) {
-      this.graphType = graphType;
-    }
+  public int getWidth() {
+    return this.width;
+  }
+
+  public int getHeight() {
+    return this.height;
   }
 
   public void setTitle(String title) {
     this.title = title;
   }
 
+  public String getTitle() {
+    return this.title;
+  }
+
   public void setId(String id) {
     this.id = id;
   }
 
-  public void setDataSet(String chartType,
-    TreeMap<String, TreeMap<String, Double>> data) {
-    if (this.dataset == null) {
-      this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>();
-      this.chartType = new ArrayList<String>();
-    }
-    this.dataset.add(data);
-    this.chartType.add(chartType);
+  public String getId() {
+    return this.id;
   }
 
-  public void setDataSet(String chartType, String series, String data) {
-    if (this.dataset == null) {
-      this.restData = new ArrayList<String>();
-      this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>();
-      this.chartType = new ArrayList<String>();
-    }
-    this.chartType.add(chartType);
-    this.restData.add(data);
-    TreeMap<String, TreeMap<String, Double>> tree = new TreeMap<String, TreeMap<String, Double>>();
-    tree.put(series, new TreeMap<String, Double>()); 
-    this.dataset.add(tree);
+  public void SetSeries(List<Series> series) {
+    this.series = series;
   }
-
-  public void setSeriesOrder(String[] metrics) {
-    this.seriesOrder = (String[]) metrics.clone();
+  
+  public List<Series> getSeries() {
+    return this.series;
   }
-
-  public void setXAxisLabels(boolean toggle) {
+  
+  public void setXAxisLabelsOn(boolean toggle) {
     xLabelOn = toggle;
   }
 
+  public boolean isXAxisLabelsOn() {
+    return xLabelOn;
+  }
+
   public void setYAxisLabels(boolean toggle) {
     yLabelOn = toggle;
   }
 
+  public boolean isYAxisLabelsOn() {
+    return yLabelOn;
+  }
+
   public void setYAxisRightLabels(boolean toggle) {
     yRightLabelOn = toggle;
   }
 
+  public boolean isYAxisRightLabelsOn() {
+    return yRightLabelOn;
+  }
+
   public void setXAxisLabel(String label) {
     xLabel = label;
   }
 
+  public String getXAxisLabel() {
+    return xLabel;
+  }
+
   public void setYAxisLabel(String label) {
     yLabel = label;
   }
 
+  public String getYAxisLabel() {
+    return yLabel;
+  }
+
   public void setYAxisRightLabel(String label) {
     yRightLabel = label;
   }
 
+  public String getYAxisRightLabel() {
+    return yRightLabel;
+  }
+
   public void setXLabelsRange(List<String> range) {
     xLabelRange = range;
     xLabelRangeHash = new HashMap<String, Long>();
@@ -182,302 +177,23 @@ public class Chart {
     }
   }
 
+  public List<String> getXLabelsRange() {
+    return xLabelRange;
+  }
+  
   public void setLegend(boolean toggle) {
     legend = toggle;
   }
 
-  public String plot() {
-    StringBuilder output = new StringBuilder();
-    if (dataset == null && restData == null) {
-      output.append("No Data available.");
-      return output.toString();
-    }
-    String dateFormat = "%H:%M";
-    if (xLabel.intern() == "Time".intern()) {
-//      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-//      try {
-//        long xMin = 0;
-//        long xMax = 0;
-//        if(xLabelRange!=null && xLabelRange.size()>0) {
-//          xMin = Long.parseLong(xLabelRange.get(0));
-//          xMax = Long.parseLong(xLabelRange.get(xLabelRange.size() - 1));
-//        }
-//        if (xMax - xMin > 31536000000L) {
-//          dateFormat = "%y";
-//        } else if (xMax - xMin > 2592000000L) {
-//          dateFormat = "%y-%m";
-//        } else if (xMax - xMin > 604800000L) {
-//          dateFormat = "%m-%d";
-//        } else if (xMax - xMin > 86400000L) {
-//          dateFormat = "%m-%d %H:%M";
-//        }
-//      } catch (NumberFormatException e) {
-//        dateFormat = "%y-%m-%d %H:%M";
-//      }
-    }
-    StringBuilder xAxisOptions = new StringBuilder();
-    if (xLabel.intern() == "Time".intern()) {
-//      if(this.restData==null) {
-//        xAxisOptions.append("timeformat: \"");
-//        xAxisOptions.append(dateFormat);
-//        xAxisOptions.append("\",");
-//      }
-      xAxisOptions.append("mode: \"time\"");
-    } else {
-      xAxisOptions
-          .append("tickFormatter: function (val, axis) { if(val!=0) { return xLabels[Math.round(val)]; } else { return \" \"; }; }, ticks: 5");
-    }
-    if (request != null && xf.getParameter("format") == null) {
-      output
-          .append("<html><link href=\"/hicc/css/default.css\" rel=\"stylesheet\" type=\"text/css\">\n");
-      output
-          .append("<html><link href=\"/hicc/css/iframe.css\" rel=\"stylesheet\" type=\"text/css\">\n");
-      output
-          .append("<html><link href=\"/hicc/css/flexigrid/flexigrid.css\" rel=\"stylesheet\" type=\"text/css\">\n");
-      output
-          .append("<body><script type=\"text/javascript\" src=\"/hicc/js/jquery-1.2.6.min.js\"></script>\n");
-      output
-          .append("<script type=\"text/javascript\" src=\"/hicc/js/jquery.flot.pack.js\"></script>\n");
-      output
-          .append("<script type=\"text/javascript\" src=\"/hicc/js/flexigrid.pack.js\"></script>\n");
-      output
-          .append("<script type=\"text/javascript\" src=\"/hicc/js/excanvas.pack.js\"></script>\n");
-      output
-          .append("<script type=\"text/javascript\" src=\"/hicc/js/base64.js\"></script>\n");
-      output
-          .append("<script type=\"text/javascript\" src=\"/hicc/js/canvas2image.js\"></script>\n");
-      output.append("<div id=\"placeholderTitle\"><center>" + title
-          + "</center></div>\n");
-      output.append("<div id=\"placeholder\" style=\"width:" + this.width
-          + "px;height:" + this.height + "px;\"></div>\n");
-      output.append("<center><div id=\"placeholderLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n");
-      output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n");
-      output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n");
-      output.append("<input type=\"hidden\" id=\"boxId\" value=\"iframe"
-          + this.id + "\">\n");
-      output
-          .append("<script type=\"text/javascript\" src=\"/hicc/js/flot.extend.js\">\n");
-      output.append("</script>\n");
-      output.append("<script type=\"text/javascript\">\n");
-      output.append("var chartTitle=\"<center>" + title + "</center>\";\n");
-      output.append("var height=" + this.height + ";\n");
-      output.append("var xLabels=new Array();\n");
-      output.append("var cw = document.body.clientWidth-70;\n");
-      output.append("var ch = document.body.clientHeight-50;\n");
-      output
-          .append("document.getElementById('placeholder').style.width=cw+'px';\n");
-      output
-          .append("document.getElementById('placeholder').style.height=ch+'px';\n");
-    }
-    output.append("_options={\n");
-    output.append("        points: { show: false },\n");
-    output.append("        xaxis: { " + xAxisOptions + " },\n");
-    output.append("	  selection: { mode: \"xy\" },\n");
-    output.append("	  grid: {\n");
-    output.append("	           clickable: true,\n");
-    output.append("	           hoverable: true,\n");
-    output.append("	           tickColor: \"#C0C0C0\",\n");
-    output.append("            borderWidth: 0,\n");
-    output.append("	           backgroundColor:\"#F9F9F9\"\n");
-    output.append("	  },\n");
-    output.append("	  legend: { show: " + this.legend
-        + ", noColumns: 3, container: $(\"#placeholderLegend\") },\n");
-    output.append("        yaxis: { ");
-    boolean stack = false;
-    for (String type : this.chartType) {
-      if (type.startsWith("stack")) {
-        stack = true;
-      }
-    }
-    if (stack) {
-      output.append("mode: \"stack\", ");
-    }
-    if (displayPercentage) {
-      output
-          .append("tickFormatter: function(val, axis) { return val.toFixed(axis.tickDecimals) + \" %\"; }");
-    } else {
-      output.append("tickFormatter: function(val, axis) { ");
-      output
-          .append("if (val >= 1000000000000000) return (val / 1000000000000000).toFixed(2) + \"x10<sup>15</sup>\";");
-      output
-          .append("else if (val >= 100000000000000) return (val / 100000000000000).toFixed(2) + \"x10<sup>14</sup>\";");
-      output
-          .append("else if (val >= 10000000000000) return (val / 10000000000000).toFixed(2) + \"x10<sup>13</sup>\";");
-      output
-          .append("else if (val >= 1000000000000) return (val / 1000000000000).toFixed(2) + \"x10<sup>12</sup>\";");
-      output
-          .append("else if (val >= 100000000000) return (val / 100000000000).toFixed(2) + \"x10<sup>11</sup>\";");
-      output
-          .append("else if (val >= 10000000000) return (val / 10000000000).toFixed(2) + \"x10<sup>10</sup>\";");
-      output
-          .append("else if (val >= 1000000000) return (val / 1000000000).toFixed(2) + \"x10<sup>9</sup>\";");
-      output
-          .append("else if (val >= 100000000) return (val / 100000000).toFixed(2) + \"x10<sup>8</sup>\";");
-      output
-          .append("else if (val >= 10000000) return (val / 10000000).toFixed(2) + \"x10<sup>7</sup>\";");
-      output
-          .append("else if (val >= 1000000) return (val / 1000000).toFixed(2) + \"x10<sup>6</sup>\";");
-      output
-          .append("else if (val >= 100000) return (val / 100000).toFixed(2) + \"x10<sup>5</sup>\";");
-      output
-          .append("else if (val >= 10000) return (val / 10000).toFixed(2) + \"x10<sup>4</sup>\";");
-      output
-          .append("else if (val >= 2000) return (val / 1000).toFixed(2) + \"x10<sup>3</sup>\";");
-      output.append("else return val.toFixed(2) + \"\"; }");
-    }
-    if (userDefinedMin) {
-      output.append(", min:");
-      output.append(this.min);
-    }
-    if (userDefinedMax) {
-      output.append(", max:");
-      output.append(this.max);
-    }
-    output.append("}\n");
-    output.append("	};\n");
-    if (!xLabel.equals("Time")) {
-      output.append("xLabels = [\"");
-      for (int i = 0; i < xLabelRange.size(); i++) {
-        if (i > 0) {
-          output.append("\",\"");
-        }
-        output.append(xLabelRange.get(i));
-      }
-      output.append("\"];\n");
-    }
-    output.append("_series=[\n");
-    ColorPicker cp = new ColorPicker();
-    int i = 0;
-    if(this.dataset!=null) {
-      for (TreeMap<String, TreeMap<String, Double>> dataMap : this.dataset) {
-        String[] keyNames;
-        if (this.seriesOrder != null) {
-          keyNames = this.seriesOrder;
-        } else {
-          keyNames = dataMap.keySet().toArray(
-              new String[dataMap.size()]);
-        }
-        int counter = 0;
-        if (i != 0 && !this.userDefinedMax) {
-            this.max = 0;
-        }
-        for (String seriesName : keyNames) {
-          int counter2 = 0;
-          if ((counter != 0) || (i != 0)) {
-            output.append(",");
-          }
-          String param = "fill: false, lineWidth: 1";
-          String type = "lines";
-          if (this.chartType.get(i).intern() == "stack-area".intern()
-              || this.chartType.get(i).intern() == "area".intern()) {
-            param = "fill: true, lineWidth: 0";
-          }
-          if (this.chartType.get(i).intern() == "bar".intern()) {
-            type = "bars";
-            param = "stepByStep: true, lineWidth: 0";
-          }
-          if (this.chartType.get(i).intern() == "point".intern()) {
-            type = "points";
-            param = "fill: false";
-          }
-          output.append("  {");
-          output.append(type);
-          output.append(": { show: true, ");
-          output.append(param);
-          output.append(" }, color: \"");
-          output.append(cp.getNext());
-          output.append("\", label: \"");
-          output.append(seriesName);
-          output.append("\", ");
-          String showYAxis = "false";
-          String shortRow = "false";
-          if (counter == 0 || i > 0) {
-            showYAxis = "true";
-            shortRow = "false";
-          }
-          output.append(" row: { show: ");
-          output.append(showYAxis);
-          output.append(",shortRow:");
-          output.append(shortRow);
-          output.append(", showYAxis:");
-          output.append(showYAxis);
-          output.append("}, data:[");
-          TreeMap<String, Double> data = dataMap.get(seriesName);
-          if(data!=null) {
-            java.util.Iterator<Entry<String, Double>> iter = data.entrySet().iterator();
-            while (iter.hasNext()) {
-              Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iter.next();
-              int rangeLabel = 0;
-              if (counter2 != 0) {
-                output.append(",");
-              }
-              if (xLabel.equals("Time")) {
-                if (Double.isNaN(entry.getValue())) {
-                  output.append("[");
-                  output.append(entry.getKey());
-                  output.append(",NULL]");
-                } else {
-                  output.append("[");
-                  output.append(entry.getKey());
-                  output.append(",");
-                  output.append(entry.getValue());
-                  output.append("]");
-                }
-              } else {
-                long value = xLabelRangeHash.get(entry.getKey());
-                if (Double.isNaN(entry.getValue())) {
-                  output.append("[");
-                  output.append(value);
-                  output.append(",NULL]");
-                } else {
-                  output.append("[");
-                  output.append(value);
-                  output.append(",");
-                  output.append(entry.getValue());
-                  output.append("]");
-                }
-                rangeLabel++;
-              }
-              counter2++;
-            }
-          }
-          output.append("], min:0");
-          if (this.userDefinedMax) {
-            output.append(", max:");
-            output.append(this.max);
-          }
-          output.append("}");
-          counter++;
-        }
-        i++;
-      }
-      }
-    output.append(" ];\n");
-    if(this.restData!=null) {
-      JSONArray arr = new JSONArray();
-      for(String url : restData) {
-        arr.put(url);
-      }
-      output.append("var _rest = ");
-      output.append(arr.toString());
-      output.append(";");
-    }
-    if (request != null && xf.getParameter("format") == null) {
-      output.append("$(document).ready(function() { \n");
-      if(this.restData!=null) {
-        output.append("   loadData();\n");
-      } else {
-        output.append("   wholePeriod();\n");
-      }
-      output.append("   $(window).resize(function() { wholePeriod(); });\n");
-      output.append("});\n");
-      output.append("</script>\n");
-      output.append("<input type=\"button\" value=\"Export\" onclick=\"javascript:saveReport();\">\n");
-      output.append("</body></html>\n");
-    } else {
-      output.append("chartTitle=\"<center>" + this.title + "</center>\";");
-      output.append("height=" + this.height + ";");
-    }
-    return output.toString();
+  public boolean getLegend() {
+    return legend;
+  }
+
+  public void setYUnitType(String yUnitType) {
+    this.yUnitType = yUnitType;
+  }
+  
+  public String getYUnitType() {
+    return this.yUnitType;
   }
 }

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java b/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java
index 09e829d..ea53941 100644
--- a/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/HiccWebServer.java
@@ -22,6 +22,7 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
@@ -31,6 +32,7 @@ import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
 import org.apache.hadoop.chukwa.conf.ChukwaConfiguration;
+import org.apache.hadoop.chukwa.datastore.ChukwaHBaseStore;
 import org.apache.hadoop.chukwa.util.ExceptionUtil;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FSDataOutputStream;
@@ -106,6 +108,7 @@ public class HiccWebServer {
           }
         }
       }
+      jar.close();
       return result;
     } 
       
@@ -187,6 +190,22 @@ public class HiccWebServer {
         fs.mkdirs(viewsPath);
         List<String> views = getResourceListing("views");
         populateDir(views, viewsPath);
+
+        // Populate example chart widgets
+        Chart chart = new Chart("1");
+        chart.setYUnitType("");
+        chart.setTitle("Load Average");
+        ArrayList<Series> series = new ArrayList<Series>();
+
+        Series s = new Series();
+        s.setLabel("SystemMetrics.LoadAverage.1/Erics-MacBook-Pro.local");
+        s.setUrl(new URI("/hicc/v1/metrics/series/SystemMetrics.LoadAverage.1/Erics-MacBook-Pro.local"));
+        LineOptions l = new LineOptions();
+        s.setLineOptions(l);
+        series.add(s);
+
+        chart.SetSeries(series);
+        ChukwaHBaseStore.createChart(chart);
         log.info("HICC Datastore initialization completed.");
       }
     } catch (IOException ex) {

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java
new file mode 100644
index 0000000..f0e1279
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/LineOptions.java
@@ -0,0 +1,25 @@
+/*
+ * 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.hicc;
+
+public class LineOptions extends SeriesOptions {
+  public boolean zero;
+  public boolean steps;
+  
+
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java
new file mode 100644
index 0000000..dedea86
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/PointOptions.java
@@ -0,0 +1,27 @@
+/*
+ * 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.hicc;
+
+public class PointOptions extends SeriesOptions {
+  public int radius;
+  public String symbol = "circle";
+  
+  public PointOptions() {
+    radius = 5;
+  }
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java b/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java
new file mode 100644
index 0000000..4906059
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/Series.java
@@ -0,0 +1,121 @@
+/*
+ * 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.hicc;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Series implements Cloneable {
+
+  @XmlElement
+  public URI url;
+  @XmlElement
+  public String color;
+  @XmlElement
+  public String label;
+  @XmlElement
+  public LineOptions lines;
+  @XmlElement
+  public BarOptions bars;
+  @XmlElement
+  public PointOptions points;
+  @XmlElement
+  public int xaxis;
+  @XmlElement
+  public int yaxis;
+  @XmlElement
+  public boolean clickable;
+  @XmlElement
+  public boolean hoverable;
+  @XmlElement
+  public int shadowSize;
+  @XmlElement
+  public int highlightColor;
+  public ArrayList<ArrayList<Number>> data = null;
+  
+  public Series() {
+    
+  }
+
+  public void setUrl(URI url) {
+    this.url = url;
+  }
+  
+  public URI getUrl() {
+    return url;
+  }
+  
+  public void setLineOptions(LineOptions lines) {
+    this.lines = lines;
+    
+  }
+  
+  public LineOptions getLineOptions() {
+    return lines;
+  }
+  
+  public void setBarOptions(BarOptions bars) {
+    this.bars = bars;
+  }
+  
+  public BarOptions getBarOptions() {
+    return bars;
+  }
+  
+  public void setPointOptions(PointOptions points) {
+    this.points = points;
+  }
+  
+  public PointOptions getPointOptions() {
+    return points;
+  }
+  
+  public void setColor(String color) {
+    this.color = color;
+  }
+  
+  public String getColor() {
+    return color;
+  }
+
+  public void setData(ArrayList<ArrayList<Number>> data) {
+    this.data = data;
+  }
+  
+  public ArrayList<ArrayList<Number>> getData() {
+    return data;
+  }
+
+  public void setLabel(String label) {
+    this.label = label;
+  }
+  
+  public String getLabel() {
+    return label;
+  }
+
+  @Override
+  public Object clone()throws CloneNotSupportedException{  
+    return super.clone();  
+  }
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java b/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java
new file mode 100644
index 0000000..74527d9
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/SeriesOptions.java
@@ -0,0 +1,33 @@
+/*
+ * 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.hicc;
+
+public class SeriesOptions {
+  public boolean show = true;
+  public boolean fill = false;
+  public int lineWidth;
+  public String fillColor;
+  
+  public boolean getFill() {
+    return fill;
+  }
+  
+  public void setFill(boolean fill) {
+    this.fill = fill;
+  }
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java b/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java
index 90d3963..c946086 100644
--- a/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/bean/Series.java
@@ -64,4 +64,8 @@ public class Series {
   public Object toJSONObject() {
     return series;
   }
+
+  public String getData() {
+    return (String) series.get("data");
+  }
 }

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java
new file mode 100644
index 0000000..93b8ab9
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/ChartController.java
@@ -0,0 +1,187 @@
+/*
+ * 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.hicc.rest;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.lang.reflect.Type;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.hadoop.chukwa.datastore.ChukwaHBaseStore;
+import org.apache.hadoop.chukwa.hicc.Chart;
+import org.apache.hadoop.chukwa.hicc.Series;
+import org.apache.hadoop.chukwa.hicc.TimeHandler;
+import org.apache.log4j.Logger;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.mortbay.log.Log;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.sun.jersey.api.Responses;
+
+@Path("/chart")
+public class ChartController {
+  static Logger LOG = Logger.getLogger(ChartController.class);
+  SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+
+  @Context
+  VelocityEngine velocity;
+  
+  /**
+   * Render chart using flot.js
+   * 
+   * @param id Reference ID of Chart stored in HBase chukwa_meta table.
+   * @return html chart widget
+   */
+  @GET
+  @Path("draw/{id}")
+  @Produces(MediaType.TEXT_HTML)
+  public String draw(@PathParam("id") String id) {
+    VelocityContext context = new VelocityContext();
+    StringWriter sw = null;
+    try {
+      Chart chart = ChukwaHBaseStore.getChart(id);
+      List<Series> series = chart.getSeries();
+      Gson gson = new Gson();
+      String seriesMetaData = gson.toJson(series);
+
+      context.put("chart", chart);
+      context.put("seriesMetaData", seriesMetaData);
+      Template template = velocity.getTemplate("chart.vm");
+      sw = new StringWriter();
+      template.merge(context, sw);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return e.getMessage();
+    }
+    return sw.toString();
+  }
+
+  /**
+   * Describe chart meta data
+   */
+  @GET
+  @Path("describe/{id}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public String describe(@PathParam("id") String id) {
+    Chart chart = ChukwaHBaseStore.getChart(id);
+    Gson gson = new Gson();
+    String buffer = gson.toJson(chart);
+    return buffer;
+  }
+
+  /**
+   * Create a new chart meta data
+   * 
+   * @param chart
+   * @return
+   */
+  @POST
+  @Path("save")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response create(String buffer) {
+    try {
+      Gson gson = new Gson();
+      Chart chart = gson.fromJson(buffer, Chart.class);
+      String id = ChukwaHBaseStore.createChart(chart);
+      return Response.ok(id).build();
+    } catch (IOException e) {
+      return Responses.notAcceptable().build();
+    }
+    
+  }
+
+  /**
+   * Save chart meta data
+   * 
+   * @param chart
+   * @return
+   */
+  @PUT
+  @Path("save/{id}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response save(@PathParam("id") String id, String buffer) {
+    Gson gson = new Gson();
+    Chart chart = gson.fromJson(buffer, Chart.class);
+    ChukwaHBaseStore.putChart(id, chart);
+    return Response.ok().build();
+    
+  }
+
+  /**
+   * Preview a chart
+   */
+  @PUT
+  @Path("preview")
+  public String preview(String buffer) {
+    VelocityContext context = new VelocityContext();
+    StringWriter sw = null;
+    try {
+      Gson gson = new Gson();
+      Chart chart = gson.fromJson(buffer, Chart.class);
+      List<Series> series = chart.getSeries();
+      String seriesMetaData = gson.toJson(series);
+
+      context.put("chart", chart);
+      context.put("seriesMetaData", seriesMetaData);
+      Template template = velocity.getTemplate("chart.vm");
+      sw = new StringWriter();
+      template.merge(context, sw);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return e.getMessage();
+    }
+    return sw.toString();
+  }
+
+  @PUT
+  @Path("preview/series")
+  @Produces("application/json")
+  public String previewSeries(@Context HttpServletRequest request, String buffer) {
+    Type listType = new TypeToken<ArrayList<Series>>() {
+    }.getType();
+    long startTime = 0;
+    long endTime = 0;
+    TimeHandler time = new TimeHandler(request);
+    startTime = time.getStartTime();
+    endTime = time.getEndTime();
+    Gson gson = new Gson();
+    ArrayList<Series> series = gson.fromJson(buffer, listType);
+    series = ChukwaHBaseStore.getChartSeries(series, startTime, endTime);
+    String result = gson.toJson(series);
+    return result;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java
index 61f8247..9730b43 100644
--- a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/MetricsController.java
@@ -37,6 +37,8 @@ import org.apache.hadoop.chukwa.hicc.TimeHandler;
 import org.apache.hadoop.chukwa.hicc.bean.Series;
 import org.json.simple.JSONArray;
 
+import com.google.gson.Gson;
+
 @Path("/metrics")
 public class MetricsController {
 
@@ -128,7 +130,7 @@ public class MetricsController {
   @GET
   @Path("schema/{metricGroup}")
   @Produces("application/json")
-  public String getFamilies(@PathParam("metricGroup") String metricGroup) {
+  public String getMetrics(@PathParam("metricGroup") String metricGroup) {
     Set<String> metricNames = ChukwaHBaseStore.getMetricNames(metricGroup);
     JSONArray metrics = new JSONArray();
     for(String metric : metricNames) {
@@ -136,7 +138,7 @@ public class MetricsController {
     }
     return metrics.toString();
   }
-    
+
   @GET
   @Path("source/{metricGroup}")
   @Produces("application/json")
@@ -148,4 +150,5 @@ public class MetricsController {
     }
     return rows.toString();
   }
+
 }

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java
new file mode 100644
index 0000000..ea07797
--- /dev/null
+++ b/src/main/java/org/apache/hadoop/chukwa/hicc/rest/VelocityResolver.java
@@ -0,0 +1,86 @@
+/*
+ * 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.hicc.rest;
+
+import java.lang.reflect.Type;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.log4j.Logger;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+
+import com.sun.jersey.core.spi.component.ComponentContext;
+import com.sun.jersey.core.spi.component.ComponentScope;
+import com.sun.jersey.spi.inject.Injectable;
+import com.sun.jersey.spi.inject.InjectableProvider;
+
+@Provider
+public class VelocityResolver implements InjectableProvider<Context, Type> {
+  @Context
+  private ServletContext servletContext;
+
+  private VelocityEngine ve;
+  private static Logger LOG = Logger.getLogger(VelocityResolver.class);
+  public static String LOGGER_NAME = VelocityResolver.class.getName();
+  
+  /**
+   * Jersey configuration for setting up Velocity configuration.
+   */
+  @Override
+  public Injectable<VelocityEngine> getInjectable(ComponentContext arg0,
+      Context arg1, Type c) {
+    if (c.equals(VelocityEngine.class)) {
+      return new Injectable<VelocityEngine>() {
+        public VelocityEngine getValue() {
+          if (ve == null) {
+            LOG.info("Ready to start velocity");
+            ve = new VelocityEngine();
+            ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+                    "org.apache.velocity.runtime.log.Log4JLogChute");
+            ve.setProperty("runtime.log.logsystem.log4j.logger",
+                LOGGER_NAME);
+            ve.setProperty(RuntimeConstants.RESOURCE_LOADER,
+                "webapp");
+            ve.setProperty("webapp.resource.loader.class",
+                    "org.apache.velocity.tools.view.WebappResourceLoader");
+            ve.setProperty("webapp.resource.loader.path",
+                "/WEB-INF/vm/");
+            ve.setApplicationAttribute(
+                "javax.servlet.ServletContext", servletContext);
+            try {
+              ve.init();
+              LOG.info("Velocity is loaded");
+            } catch (Exception e) {
+              LOG.error("Error when initializing Velocity", e);
+            }
+          }
+          return ve;
+        }
+      };
+    }
+    return null;
+  }
+
+  public ComponentScope getScope() {
+    return ComponentScope.Singleton;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java b/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java
index d463dd1..b0ae38e 100644
--- a/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java
+++ b/src/main/java/org/apache/hadoop/chukwa/util/HBaseUtil.java
@@ -1,3 +1,20 @@
+/*
+ * 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.util;
 
 import java.security.MessageDigest;

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/chart.vm
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/WEB-INF/vm/chart.vm b/src/main/web/hicc/WEB-INF/vm/chart.vm
new file mode 100644
index 0000000..90cb1d7
--- /dev/null
+++ b/src/main/web/hicc/WEB-INF/vm/chart.vm
@@ -0,0 +1,106 @@
+#*
+  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.
+ *#
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <link href="/hicc/css/default.css" rel="stylesheet" type="text/css">
+    <link href="/hicc/css/iframe.css" rel="stylesheet" type="text/css">
+    <link href="/hicc/css/flexigrid/flexigrid.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="placeholderTitle"><center>$chart.getTitle()</center></div>
+    <div id="placeholder"></div>
+    <div class="legendHolder">
+      <div class="left"></div>
+      <div class="center" id="placeholderLegend"></div>
+      <div class="right"></div>
+    </div>
+    <div class="legendHolder">
+      <div class="center" id="statisLegend"></div>
+    </div>
+    <script type="text/javascript" src="/hicc/js/jquery-1.2.6.min.js"></script>
+    <script type="text/javascript" src="/hicc/js/jquery.flot.pack.js"></script>
+    <script type="text/javascript" src="/hicc/js/flexigrid.pack.js"></script>
+    <script type="text/javascript" src="/hicc/js/excanvas.pack.js"></script>
+    <script type="text/javascript" src="/hicc/js/base64.js"></script>
+    <script type="text/javascript" src="/hicc/js/canvas2image.js"></script>
+    <script type="text/javascript" src="/hicc/js/flot.extend.js"></script>
+
+    <script type="text/javascript">
+
+var chartTitle="<center>$chart.getTitle()</center>";
+var xLabels=new Array();
+
+var _options={
+    points: { 
+      show: false
+    },
+    xaxis: { 
+      mode: "time"
+    },
+	  selection: { 
+	    mode: "xy",
+	    color: "#999999"
+	  },
+	  grid: {
+	    clickable: true,
+	    hoverable: true,
+	    tickColor: "#C0C0C0",
+      borderWidth: 0,
+	    backgroundColor:"#F9F9F9"
+	  },
+	  legend: { show: true, noColumns: 3, container: $("#placeholderLegend") },
+    yaxis: {
+      #if ( $chart.getYMin()!=0 )
+        min: $chart.getYMin(),
+      #end
+      #if ( $chart.getYMax()!=0 )
+        max: $chart.getYMax(),
+      #end
+      tickFormatter: function(val, axis) {
+        #if ( $chart.getYUnitType().equals('bytes') )
+          #parse("unit-bytes-binary.vm")
+        #elseif ( $chart.getYUnitType().equals('bytes-decimal') )
+          #parse("unit-bytes-decimal.vm")
+        #elseif ( $chart.getYUnitType().equals('ops') )
+          #parse("unit-ops.vm")
+        #elseif ( $chart.getYUnitType().equals('percent') )
+          #parse("unit-percent.vm")
+        #else
+          #parse("unit-generic.vm")
+        #end
+      }
+    }
+};
+
+var _series=$seriesMetaData;
+var _seriesTemplate=$seriesMetaData;
+
+$(document).ready(function() { 
+  reload();
+  $(window).resize(function() { 
+    wholePeriod();
+  });
+});
+
+
+</script>
+<input type="hidden" id="boxId" value="iframe">
+<!-- <input type="button" value="Export" onclick="javascript:saveReport();">  -->
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm b/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm
new file mode 100644
index 0000000..96c6cf7
--- /dev/null
+++ b/src/main/web/hicc/WEB-INF/vm/unit-bytes-binary.vm
@@ -0,0 +1,27 @@
+#*
+  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.
+ *#
+var bytes = val;
+var thresh = 1024;
+if(bytes < thresh) return bytes + 'B';
+  var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
+  var u = -1;
+  do {
+    bytes /= thresh;
+    ++u;
+  } while(bytes >= thresh);
+return bytes.toFixed(1)+units[u];
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm b/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm
new file mode 100644
index 0000000..ed91660
--- /dev/null
+++ b/src/main/web/hicc/WEB-INF/vm/unit-bytes-decimal.vm
@@ -0,0 +1,27 @@
+#*
+  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.
+ *#
+var bytes = val;
+var thresh = 1000;
+if(bytes < thresh) return bytes + 'B';
+  var units = ['kB','MB','GB','TB','PB','EB','ZB','YB'];
+  var u = -1;
+  do {
+    bytes /= thresh;
+    ++u;
+  } while(bytes >= thresh);
+return bytes.toFixed(1)+units[u];
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-generic.vm
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/WEB-INF/vm/unit-generic.vm b/src/main/web/hicc/WEB-INF/vm/unit-generic.vm
new file mode 100644
index 0000000..2c56c1f
--- /dev/null
+++ b/src/main/web/hicc/WEB-INF/vm/unit-generic.vm
@@ -0,0 +1,20 @@
+#*
+  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.
+ *#
+var parts = val.toString().split(".");
+parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+return parts.join(".");

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-ops.vm
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/WEB-INF/vm/unit-ops.vm b/src/main/web/hicc/WEB-INF/vm/unit-ops.vm
new file mode 100644
index 0000000..e863b6a
--- /dev/null
+++ b/src/main/web/hicc/WEB-INF/vm/unit-ops.vm
@@ -0,0 +1,20 @@
+#*
+  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.
+ *#
+var parts = val.toString().split(".");
+parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+return parts.join(".") + "ops";

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/WEB-INF/vm/unit-percent.vm
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/WEB-INF/vm/unit-percent.vm b/src/main/web/hicc/WEB-INF/vm/unit-percent.vm
new file mode 100644
index 0000000..d37807a
--- /dev/null
+++ b/src/main/web/hicc/WEB-INF/vm/unit-percent.vm
@@ -0,0 +1,20 @@
+#*
+  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.
+ *#
+var parts = val.toString().split(".");
+parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+return parts.join(".") + "%";

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/css/default.css
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/css/default.css b/src/main/web/hicc/css/default.css
index eef956e..3a2741b 100644
--- a/src/main/web/hicc/css/default.css
+++ b/src/main/web/hicc/css/default.css
@@ -67,8 +67,7 @@ body {font-family:Oswald,Arial;background-color:#ffffff;}
 .glossy_icon img {
         position:relative; /*this is the key*/
         z-index:24;
-        filter:progid:DXImageTransform.Microsoft.Alpha(opacity=65);
-        opacity:.65; -moz-opacity: 0.65;
+        opacity:.65;
         text-decoration:none;
         border:none;
 }
@@ -78,14 +77,14 @@ body {font-family:Oswald,Arial;background-color:#ffffff;}
         border:none;
         text-decoration:none;
         filter:progid:DXImageTransform.Microsoft.Alpha(opacity=100);
-        opacity:1.00; -moz-opacity: 1.00;
+        opacity:1.00;
 }
 
 .glossy_icon:hover img {
         z-index:25;
         border:none;
         filter:progid:DXImageTransform.Microsoft.Alpha(opacity=100);
-        opacity:1.00; -moz-opacity: 1.00;
+        opacity:1.00;
 }
 
 .glossy_icon span{display: none}
@@ -107,7 +106,7 @@ body {font-family:Oswald,Arial;background-color:#ffffff;}
 .glossy_icon:disabled {
         border:none;
         filter:progid:DXImageTransform.Microsoft.Alpha(opacity=25);
-        opacity:.25; -moz-opacity: 0.25;
+        opacity:.25;
 }
 
 .group_box {
@@ -443,7 +442,6 @@ table.simple th {
 	border-color: #E1D8E5;
 	background-color: #E1D8E5;
         font: bold 11px Arial; color:#000000;
-	-moz-border-radius: ;
 }
 table.simple td {
 	text-decoration: none;
@@ -451,7 +449,6 @@ table.simple td {
 	padding: 2px;
 	border-style: inset;
 	border-color: #E1D8E5;
-	-moz-border-radius: ;
 }
 
 thead.fixedHead {

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/css/iframe.css
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/css/iframe.css b/src/main/web/hicc/css/iframe.css
index 4f7555f..493e0b1 100644
--- a/src/main/web/hicc/css/iframe.css
+++ b/src/main/web/hicc/css/iframe.css
@@ -16,31 +16,31 @@
  * limitations under the License.
  */
 #statisLegend table {
-	border-collapse: collapse;
+  border-collapse: collapse;
+  padding: 5px;
 }
 
 #statisLegend th strong {
-	color: #fff;
+  color: #fff;
 }
 
 #statisLegend th {
-        padding-left: 5px;
-        padding-right: 5px;
-	background: #93BC0C;
-	color: #fff;
-	text-align: center;
-	border-left: 1px solid #B6D59A;
-	border-bottom: solid 2px #fff;
+  padding-left: 5px;
+  padding-right: 5px;
+  background: #999999;
+  color: #fff;
+  text-align: center;
+  border-bottom: solid 2px #fff;
 }
 
 #statisLegend tr {
 }
 
 #statisLegend td {
-        padding-left: 5px;
-        padding-right: 5px;
-	border-left: 1px solid #fff;
-	border-bottom: 1px solid #fff;
+  padding-left: 5px;
+  padding-right: 5px;
+  border-left: 1px solid #fff;
+  border-bottom: 1px solid #fff;
 }
 
 #statisLegend td.first,th.first {
@@ -57,8 +57,73 @@
 
 #statisLegend {
     font-size: 0.85em;
+    margin: auto;
+    align: center;
+    overflow-x: hidden;
+    overflow-y: hidden;
 }
 
 .small_font {
     font-size: 0.85em;
 }
+
+#placeholder {
+    align: center;
+    width: 100%;
+    height: 70%;
+    min-height: 100px;
+    max-height: 480px;
+}
+
+#placeholder canvas {
+    width: 100%;
+    height: 100%;
+    margin: 0 auto;
+    min-height: 100px;
+    max-height: 450px;
+}
+
+.legendHolder {
+    text-align:center;
+    min-width: 400px;
+    min-height: 20px;
+}
+
+div.center {
+    display: inline-block;
+    margin:auto;
+    min-width: 200px;
+    min-height: 20px;
+}
+
+div.left {
+    display: inline-block;
+    margin:auto auto auto 0;
+    width: 20px;
+    height: 20px;
+}
+
+div.right {
+    display: inline-block;
+    margin:auto 0 auto auto;
+    width: 20px;
+    height: 20px;
+}
+
+#placeholderLegend {
+    margin: auto;
+    align: center;
+    overflow-x: hidden;
+    overflow-y: hidden;
+}
+
+.statisTable table th td {
+    table-layout:fixed;
+    overflow:hidden;
+    white-space: nowrap;
+}
+
+html, body {
+    height: 100%;
+    overflow: hidden;
+}

http://git-wip-us.apache.org/repos/asf/chukwa/blob/a6e0cbad/src/main/web/hicc/js/flot.extend.js
----------------------------------------------------------------------
diff --git a/src/main/web/hicc/js/flot.extend.js b/src/main/web/hicc/js/flot.extend.js
index 5af6793..d7a2056 100644
--- a/src/main/web/hicc/js/flot.extend.js
+++ b/src/main/web/hicc/js/flot.extend.js
@@ -15,7 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-var zoom=false;
+var pause=false;
+var timer;
 var bound=null;
 var _chartSeriesSize=0;
 
@@ -97,7 +98,6 @@ function calculateStatis() {
   }
   dataTable+='</table>';
   $('#statisLegend').html(dataTable);
-  setIframeHeight(document.getElementById('boxId').value);
 }
 
 /*
@@ -112,23 +112,31 @@ function showTooltip(x, y, contents) {
   }
   $('<div id="tooltip">' + contents + '</div>').css( {
     position: 'absolute',
-	display: 'none',
-	top: y + 5,
-	left: x + 5,
-	border: '2px solid #aaa',
-	padding: '2px',
-	'background-color': '#fff',
-        }).appendTo("body").fadeIn(200);
+    display: 'none',
+    top: y + 5,
+    left: x + 5,
+    'border-radius': '5px',
+    border: '2px solid #aaa',
+    padding: '2px',
+    'background-color': '#fff',
+  }).appendTo("body").fadeIn(200);
 }
 
 /*
  * calculate the height of the area and set the correct height for the chart, legend and the statis legend as well.
  */
 function wholePeriod() {
-  var cw = document.body.clientWidth-30;
-  var ch = height-$("#placeholderTitle").height()-10;
-  document.getElementById('placeholder').style.width=cw+'px';
-  document.getElementById('placeholder').style.height=ch+'px';
+  var ch = document.body.clientHeight;
+  if (ch < 200 ) {
+    $('#placeholderLegend').hide();
+    $('#statisLegend').hide();
+  } else if (ch < 320) {
+    $('#placeholderLegend').show();
+    $('#statisLegend').hide();
+  } else {
+    $('#placeholderLegend').show();
+    $('#statisLegend').show();
+  }
   $.plot($("#placeholder"), _series, _options);
   // update statis
   calculateStatis();
@@ -163,29 +171,29 @@ $("#placeholder").bind("plotclick", function (event, pos, item) {
     };
     if (item) {
       if (previousPoint != item.datapoint) {
-	previousPoint = item.datapoint;
-               
-	$("#tooltip").remove();
-	if(xLabels.length==0) {
-	  var x = item.datapoint[0],
-	    y = item.stackValue.toFixed(2);
-	  var dnow=new Date();
-	  dnow.setTime(x);
-	  var dita=leftPad(dnow.getUTCFullYear())+"/"+leftPad(dnow.getUTCMonth()+1)+"/"+dnow.getUTCDate()+" "+leftPad(dnow.getUTCHours())+":"+leftPad(dnow.getUTCMinutes())+":"+leftPad(dnow.getUTCSeconds());
- 
-	  showTooltip(item.pageX, item.pageY,
-		      item.series.label + ": " + y + "<br>Time: " + dita);
-	} else {
-	  var x = item.datapoint[0],
-	    y = item.stackValue.toFixed(2);
-	  xLabel = xLabels[x];
-	  showTooltip(item.pageX, item.pageY,
-		      item.series.label + ": " + y + "<br>" + xLabel);
-	}
+        previousPoint = item.datapoint;
+        pause = true;
+        $("#tooltip").remove();
+        if(xLabels.length==0) {
+          var x = item.datapoint[0],
+            y = item.stackValue.toFixed(2);
+          var dnow=new Date();
+          dnow.setTime(x);
+          var dita=leftPad(dnow.getUTCFullYear())+"/"+leftPad(dnow.getUTCMonth()+1)+"/"+dnow.getUTCDate()+" "+leftPad(dnow.getUTCHours())+":"+leftPad(dnow.getUTCMinutes())+":"+leftPad(dnow.getUTCSeconds());
+          showTooltip(item.pageX, item.pageY,
+            item.series.label + ": " + y + "<br>Time: " + dita);
+        } else {
+          var x = item.datapoint[0],
+          y = item.stackValue.toFixed(2);
+          xLabel = xLabels[x];
+          showTooltip(item.pageX, item.pageY,
+            item.series.label + ": " + y + "<br>" + xLabel);
+        }
       }
     } else {
       $("#tooltip").remove();
-      previousPoint = null;            
+      previousPoint = null;
+      pause = false;
     }
   });
 
@@ -193,9 +201,13 @@ $("#placeholder").bind("plotclick", function (event, pos, item) {
  * bind the function for resizing the area inside the chart.
  */
 $("#placeholder").bind("selected", function (event, area) {
-    zoom = true;
+    if(area.x1 == area.x2 && area.y1 == area.y2) {
+      pause = false;
+    } else {
+      pause = true;
+    }
     extra_options = {};
-    extra_options.xaxis={ min: area.x1, max: area.x2 };	       
+    extra_options.xaxis={ min: area.x1, max: area.x2 };
     extra_options.yaxis={ min: area.y1, max: area.y2 };
     bound = {};
     bound.xmin=area.x1;
@@ -204,15 +216,14 @@ $("#placeholder").bind("selected", function (event, area) {
     bound.ymax=area.y2;
     calculateStatis();
     plot = $.plot(
-		  $("#placeholder"),
-		  _series,
-		  $.extend(
-			   true, 
-			   {}, 
-			   _options, extra_options
-			   )
-		  );
-    setIframeHeight(document.getElementById('boxId').value);
+      $("#placeholder"),
+      _series,
+      $.extend(
+         true, 
+         {}, 
+         _options, extra_options
+         )
+      );
   });
 
 /*
@@ -230,71 +241,30 @@ function getDocHeight(doc) {
 }
 
 /*
- * auto resize the iframe height to match content.
- */
-function setIframeHeight(ifrm) {
-  try {
-    objToResize = parent.document.getElementById(window.name);
-    objToResize.height = document.body.scrollHeight;
-  } catch(err) {
-    window.status = err.message;
-  }
-}
-
-/*
- * refresh the chart widget.
+ * Reload data
  */
-function refresh(url, parameters) {
-  bound=null;
-  if(zoom) {
-    wholePeriod();
-    zoom=false;
-  } else {
-    if(parameters.indexOf("render=stack")>0) {
-      return false;
-    }
-    if(parameters.indexOf("_force_refresh")>0) {
-      return false;
-    }
-    var dataURL = url+"?"+parameters;
-    $.get(dataURL,{format: 'json'}, function(data){
-      try {
-        eval(data);
-        wholePeriod();
-        document.getElementById('placeholderTitle').innerHTML=chartTitle;
-      } catch(err) {
-        return false;
-      }
-    });a
-    if(_rest!=null) {
-      loadData(url, parameters);
-    }
+function reload() {
+  if (!pause) {
+    loadData();
   }
-  return true;
+  timer = setTimeout(reload, 3000);
 }
 
 /*
  * Initialize data from REST API.
  */
 function loadData() {
-  _chartSeriesSize=0;
-  for(var i=0;i<_series.length;i++) {
-    $.getJSON(_rest[i], function(json) {
-      if(json.constructor.toString().indexOf("Array") != -1) {
-        for(var index=0;index<json.length;index++) {
-          _series[_chartSeriesSize].label=json[index].name;
-          _series[_chartSeriesSize].data=json[index].data;
-          _chartSeriesSize++;
-        }
-      } else {
-        var name=json.name;
-        _series[_chartSeriesSize].label=name;
-        _series[_chartSeriesSize].data=json.data;
-        _chartSeriesSize++;
-      }
+  $.ajax({
+    url: '/hicc/v1/chart/preview/series',
+    type: 'PUT',
+    contentType: 'application/json',
+    data: JSON.stringify(_seriesTemplate),
+    dataType: "json",
+    success: function(result) {
+      _series = result;
       wholePeriod();
-    }); 
-  }
+    }
+  });
 }
 
 /*