geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From vfor...@apache.org
Subject [14/15] incubator-geode git commit: GEODE-628: Rename container folder to "geode-jvsd". - The jvsd code now sits in the geode-jvsd directory. - Files "pom.xml", "README.txt" and "runjvsd.sh" updated.
Date Wed, 13 Jan 2016 17:14:39 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/AbstractSeries.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/AbstractSeries.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/AbstractSeries.java
new file mode 100644
index 0000000..27bbeb0
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/AbstractSeries.java
@@ -0,0 +1,289 @@
+/*
+ * 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.geode.jvsd.javafx.scene.chart;
+
+import java.util.stream.Collectors;
+
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.beans.property.ReadOnlyObjectWrapper;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.property.StringProperty;
+import javafx.beans.property.StringPropertyBase;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.ObservableList;
+import javafx.scene.Node;
+import javafx.scene.chart.Axis;
+
+import com.pivotal.javafx.scene.chart.Data;
+import com.pivotal.javafx.scene.chart.LegendItem;
+import com.pivotal.javafx.scene.chart.MultiAxisChart;
+import com.pivotal.javafx.scene.chart.Series;
+
+//import com.pivotal.com.sun.javafx.charts.LegendItem;
+
+/**
+ * A named series of data items
+ */
+public abstract class AbstractSeries<X extends Number,Y extends Number> implements Series<X, Y> {
+
+    // -------------- PRIVATE PROPERTIES ----------------------------------------
+
+    /** the style class for default color for this series */
+    protected String defaultColorStyleClass;
+
+    // TODO make property
+    @Override
+    public String getDefaultColorStyleClass() {
+      return defaultColorStyleClass;
+    }
+    
+    @Override
+    public void setDefaultColorStyleClass(String defaultColorStyleClass) {
+      this.defaultColorStyleClass = defaultColorStyleClass;
+    }
+
+//    // TODO remove
+//    protected Data<X,Y> begin = null; // start pointer of a data linked list.
+//    
+//    // TODO remove
+//    @Override
+//    public Data<X, Y> getBegin() {
+//      return begin;
+//    }
+//
+//    // TODO remove
+//    @Override
+//    public void setBegin(Data<X, Y> begin) {
+//      this.begin = begin;
+//    }
+
+    /*
+     * Next pointer for the next series. We maintain a linkedlist of the
+     * serieses  so even after the series is deleted from the list,
+     * we have a reference to it - needed by BarChart e.g.
+     */
+    // TODO remove
+    protected Series<X,Y> next = null;
+
+    // TODO remove
+    @Override
+    public Series<X, Y> getNext() {
+      return next;
+    }
+
+    // TODO remove
+    @Override
+    public void setNext(Series<X, Y> next) {
+      this.next = next;
+    }
+
+
+    // -------------- PUBLIC PROPERTIES ----------------------------------------
+
+    /** Reference to the chart this series belongs to */
+    private final ReadOnlyObjectWrapper<MultiAxisChart<X, Y>> chart = new ReadOnlyObjectWrapper<MultiAxisChart<X, Y>>(this, "chart");
+
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#getChart()
+     */
+    @Override
+    public final MultiAxisChart<X,Y> getChart() { return chart.get(); }
+    @Override
+    public void setChart(MultiAxisChart<X,Y> value) { chart.set(value); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#chartProperty()
+     */
+    @Override
+    public final ReadOnlyObjectProperty<MultiAxisChart<X,Y>> chartProperty() { return chart.getReadOnlyProperty(); }
+
+    /** Reference to the Y Axis this chart belongs to */
+    private final ReadOnlyObjectWrapper<Axis<Y>> yAxis = new ReadOnlyObjectWrapper<Axis<Y>>(null, "yAxis") {
+      protected void invalidated() {
+        final Axis<Y> axis = get();
+        axis.autoRangingProperty().addListener(new ChangeListener<Boolean>() {
+          @Override
+          public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
+            if (newValue) {
+              // TODO keep lists in series changed listener?
+              axis.invalidateRange(getData().stream().map((Data<X,Y> d) -> d.getYValue()).collect(Collectors.toList()));
+            }
+          }
+        });
+      };
+    };
+    
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#getYAxis()
+     */
+    @Override
+    public final Axis<Y> getYAxis() { return yAxis.get(); }
+    // TODO change axis event
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#setYAxis(javafx.scene.chart.Axis)
+     */
+    @Override
+    public void setYAxis(Axis<Y> value) { yAxis.set(value); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#yAxisProperty()
+     */
+    @Override
+    public final ReadOnlyObjectProperty<Axis<Y>> yAxisProperty() { return yAxis.getReadOnlyProperty(); }
+
+    /** Reference to the legend for this series */
+    private final ReadOnlyObjectWrapper<LegendItem> legendItem = new ReadOnlyObjectWrapper<>(null, "legendItem");
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#getLegendItem()
+     */
+    @Override
+    public final LegendItem getLegendItem() { return legendItem.get(); }
+    
+    @Override
+    public  void setLegendItem(LegendItem value) { legendItem.set(value); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#legendItemProperty()
+     */
+    @Override
+    public final ReadOnlyObjectProperty<LegendItem> legendItemProperty() { return legendItem.getReadOnlyProperty(); }
+
+    
+    /** The user displayable name for this series */
+    private final StringProperty name = new StringPropertyBase() {
+        @Override protected void invalidated() {
+            get(); // make non-lazy
+            // TODO: We don't have visibility to execute the method, check if there's another way to call updateLegend() and requestChartLayout() from outside of MultiAxisChart. 
+//             if(getChart() != null) getChart().seriesNameChanged();
+            if(getChart() != null) getChart().requestLayout();
+        }
+
+        @Override
+        public Object getBean() {
+            return AbstractSeries.this;
+        }
+
+        @Override
+        public String getName() {
+            return "name";
+        }
+    };
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#getName()
+     */
+    @Override
+    public final String getName() { return name.get(); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#setName(java.lang.String)
+     */
+    @Override
+    public final void setName(String value) { name.set(value); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#nameProperty()
+     */
+    @Override
+    public final StringProperty nameProperty() { return name; }
+
+    /**
+     * The node to display for this series. This is created by the chart if it uses nodes to represent the whole
+     * series. For example line chart uses this for the line but scatter chart does not use it. This node will be
+     * set as soon as the series is added to the chart. You can then get it to add mouse listeners etc.
+     */
+    private ObjectProperty<Node> node = new SimpleObjectProperty<Node>(this, "node");
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#getNode()
+     */
+    @Override
+    public final Node getNode() { return node.get(); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#setNode(javafx.scene.Node)
+     */
+    @Override
+    public final void setNode(Node value) { node.set(value); }
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#nodeProperty()
+     */
+    @Override
+    public final ObjectProperty<Node> nodeProperty() { return node; }
+
+
+    // -------------- CONSTRUCTORS ----------------------------------------------
+
+    /**
+     * Construct a empty series
+     */
+    public AbstractSeries() {
+    }
+
+    /**
+     * Constructs a named Series and populates it with the given {@link ObservableList} data.
+     *
+     * @param name a name for the series
+     * @param data ObservableList of MultiAxisChart.Data
+     */
+    public AbstractSeries(String name, ObservableList<Data<X,Y>> data) {
+        setName(name);
+    }
+
+    // -------------- PUBLIC METHODS ----------------------------------------------
+
+    /* (non-Javadoc)
+     * @see com.pivotal.javafx.scene.chart.Series#toString()
+     */ 
+    @Override public String toString() {
+        return "Series["+getName()+"]";
+    }
+
+    // -------------- PRIVATE/PROTECTED METHODS -----------------------------------
+
+    /*
+     * The following methods are for manipulating the pointers in the linked list
+     * when data is deleted. 
+     */
+//    @Override
+//    public void removeDataItemRef(Data<X,Y> item) {
+//        if (begin == item) {
+//            begin = item.next;
+//        } else {
+//            Data<X,Y> ptr = begin;
+//            while(ptr != null && ptr.next != item) {
+//                ptr = ptr.next;
+//            }
+//            if(ptr != null) ptr.next = item.next;
+//        }
+//    }
+
+    @Override
+    public int getItemIndex(Data<X,Y> item) {
+//        int itemIndex = 0;
+//        for (Data<X,Y> d = begin; d != null; d = d.next) {
+//            if (d == item) break;
+//            itemIndex++;
+//        }
+//        return itemIndex;
+      return getData().indexOf(item);
+    }
+
+    @Override
+    public int getDataSize() {
+//        int count = 0;
+//        for (Data<X,Y> d = begin; d != null; d = d.next) {
+//            count++;
+//        }
+//        return count;
+      return getData().size();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/BasicDataSet.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/BasicDataSet.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/BasicDataSet.java
new file mode 100644
index 0000000..3328328
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/BasicDataSet.java
@@ -0,0 +1,152 @@
+/*
+ * 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.geode.jvsd.javafx.scene.chart;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import com.pivotal.javafx.scene.chart.Data;
+
+import javafx.beans.InvalidationListener;
+
+public class BasicDataSet<X extends Number & Comparable<X>, Y extends Number & Comparable<Y>> implements DataSet<X, Y> {
+
+  protected final List<Data<X,Y>> list = new ArrayList<>();
+  
+  public void addData(final Data<X,Y> data) {
+    list.add(data);
+    
+    // TODO fire change;
+  }
+  
+  @Override
+  public List<Data<X, Y>> getData(final X from, final X to, final int limit) {
+    
+    List<Data<X, Y>> visible = list.stream().filter(new Predicate<Data<X,Y>>() {
+      @Override
+      public boolean test(Data<X, Y> item) {
+        final X x = item.getXValue();
+        return between(from, to, x);
+      }
+
+    }).collect(Collectors.toList());
+    
+    //System.out.println(getData().size() + " - " + visible.size());
+    
+    if (visible.size() > limit) {
+      visible = getVisibleDataSubsampled(visible, limit);
+    }
+    
+    return visible;
+  }
+  
+  private List<Data<X, Y>> getVisibleDataSubsampled(List<Data<X, Y>> data, int threshold) {
+    // Bucket size. Leave room for start and end data points
+    final int dataLength = data.size();
+    final double bucketSize = (double) (dataLength - 2) / (threshold - 2);
+    final ArrayList<Data<X,Y>> sampled = new ArrayList<>(threshold);
+
+    int a = 0; // Initially a is the first point in the triangle
+    int nextA = 0;
+
+    sampled.add(data.get(a)); // Always add the first point
+
+    for (int i = 0; i < threshold - 2; i++) {
+      // Calculate point average for next bucket (containing c)
+      double pointCX = 0;
+      double pointCY = 0;
+      int pointCStart = (int) Math.floor((i + 1) * bucketSize) + 1;
+      int pointCEnd = (int) Math.floor((i + 2) * bucketSize) + 1;
+      pointCEnd = pointCEnd < dataLength ? pointCEnd : dataLength;
+      final int pointCSize = pointCEnd - pointCStart;
+      for (; pointCStart < pointCEnd; pointCStart++) {
+        final Data<X, Y> item = data.get(pointCStart);
+        // TODO use the axis position? Don't have to assume number type then
+        pointCX += item.getXValue().doubleValue();
+        pointCY +=item.getYValue().doubleValue();
+      }
+      pointCX /= pointCSize;
+      pointCY /= pointCSize;
+
+      // Point a
+      final double pointAX;
+      final double pointAY;
+      {
+        final Data<X, Y> item = data.get(a);
+        pointAX = item.getXValue().doubleValue();
+        pointAY = item.getYValue().doubleValue();
+      }
+
+      // Get the range for bucket b
+      int pointBStart = (int) Math.floor((i + 0) * bucketSize) + 1;
+      final int pointBEnd = (int) Math.floor((i + 1) * bucketSize) + 1;
+      double maxArea = -1;
+      for (; pointBStart < pointBEnd; pointBStart++) {
+        // Calculate triangle area over three buckets
+        final Data<X, Y> item = data.get(pointBStart);
+        final double pointBX = item.getXValue().doubleValue();
+        final double pointBY = item.getYValue().doubleValue();
+        final double area = Math.abs((pointAX - pointCX) * (pointBY - pointAY) - (pointAX - pointBX)
+            * (pointCY - pointAY)) * 0.5;
+        if (area > maxArea) {
+          maxArea = area;
+          nextA = pointBStart; // Next a is this b
+        }
+      }
+
+     // Pick this point from the bucket
+      sampled.add(data.get(nextA)); 
+      a = nextA; // This a is the next a (chosen b)
+    }
+    
+    // Always add last
+    sampled.add(data.get(dataLength - 1));
+    
+    return sampled;
+  }
+
+  @Override
+  public void addListener(InvalidationListener listener) {
+    // TODO Auto-generated method stub
+
+  }
+
+  @Override
+  public void removeListener(InvalidationListener listener) {
+    // TODO Auto-generated method stub
+
+  }
+
+  @Override
+  public void addListener(DataChangedListener listener) {
+    // TODO Auto-generated method stub
+
+  }
+
+  @Override
+  public void removeListener(DataChangedListener listener) {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected static <T extends Comparable<T>> boolean between(final T from, final T to, final T value) {
+    return from.compareTo(value) >= 0 && to.compareTo(value) <= 0;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/ByteBufferNumberSeries.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/ByteBufferNumberSeries.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/ByteBufferNumberSeries.java
new file mode 100644
index 0000000..475334b
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/ByteBufferNumberSeries.java
@@ -0,0 +1,450 @@
+/*
+ * 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.geode.jvsd.javafx.scene.chart;
+
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.scene.Node;
+import javafx.scene.chart.Axis;
+
+import org.apache.geode.jvsd.fx.HoveredThresholdNode;
+
+import com.pivotal.javafx.scene.chart.BasicSeries;
+import com.pivotal.javafx.scene.chart.Data;
+
+/**
+ * A named series of data items
+ */
+public abstract class ByteBufferNumberSeries<X extends Number, Y extends Number> extends BasicSeries<X, Y> {
+
+  // -------------- PUBLIC PROPERTIES ----------------------------------------
+
+  // TODO remove
+  /** ObservableList of data items that make up this series */
+  private final ObjectProperty<ByteBuffer> bufferProperty = new SimpleObjectProperty<ByteBuffer>() {
+    protected void invalidated() {
+      buffer = get();
+    }
+  };
+
+  // here for speed over getBuffer();
+  protected ByteBuffer buffer;
+
+  public final ByteBuffer getBuffer() {
+    return bufferProperty.get();
+  }
+
+  public final void setBuffer(ByteBuffer value) {
+    bufferProperty.setValue(value);
+  }
+
+  public final ObjectProperty<ByteBuffer> bufferProperty() {
+    return bufferProperty;
+  }
+
+//  // TODO remove
+//  /** ObservableList of data items that make up this series */
+//  private final ObjectProperty<ObservableList<Data<X, Y>>> data = new ObjectPropertyBase<ObservableList<Data<X, Y>>>() {
+//    @Override
+//    protected void invalidated() {
+//      // TODO update buffer, minX, maxX, etc.
+//    }
+//
+//    @Override
+//    public Object getBean() {
+//      return ByteBufferNumberSeries.this;
+//    }
+//
+//    @Override
+//    public String getName() {
+//      return "data";
+//    }
+//  };
+//
+//  /*
+//   * (non-Javadoc)
+//   * 
+//   * @see com.pivotal.javafx.scene.chart.Series#getData()
+//   */
+//  // TODO remove
+//  @Override
+//  public final ObservableList<Data<X, Y>> getData() {
+//    return data.getValue();
+//    // System.out.println("getData:");
+//    // return ;
+//  }
+//
+//  /*
+//   * (non-Javadoc)
+//   * 
+//   * @see
+//   * com.pivotal.javafx.scene.chart.Series#setData(javafx.collections.ObservableList
+//   * )
+//   */
+//  // TODO remove
+//  @Override
+//  public final void setData(ObservableList<Data<X, Y>> value) {
+//    data.setValue(value);
+//  }
+//
+//  /*
+//   * (non-Javadoc)
+//   * 
+//   * @see com.pivotal.javafx.scene.chart.Series#dataProperty()
+//   */
+//  // TODO remove
+//  @Override
+//  public final ObjectProperty<ObservableList<Data<X, Y>>> dataProperty() {
+//    return data;
+//  }
+
+  // -------------- CONSTRUCTORS ----------------------------------------------
+
+  /**
+   * Construct a empty series
+   */
+  public ByteBufferNumberSeries() {
+    super();
+    buffer = null;
+  }
+
+  /**
+   * Constructs a Series and populates it with the given {@link ObservableList}
+   * data.
+   *
+   * @param data
+   *          ObservableList of MultiAxisChart.Data
+   */
+  public ByteBufferNumberSeries(ByteBuffer buffer) {
+    super();
+    setBuffer(buffer);
+    //setData(FXCollections.observableArrayList(new Data(0, 1000000), new Data(10000000000000l, -100000)));
+    setData(FXCollections.observableArrayList(new ThresholdDataCollection(0, getDataSize(), 1000)));
+    
+  }
+
+  /**
+   * Constructs a named Series and populates it with the given
+   * {@link ObservableList} data.
+   *
+   * @param name
+   *          a name for the series
+   * @param data
+   *          ObservableList of MultiAxisChart.Data
+   */
+  public ByteBufferNumberSeries(String name, ByteBuffer buffer) {
+    this(buffer);
+    setName(name);
+  }
+
+  @Override
+  public Collection<Data<X, Y>> getVisibleData() {
+
+    final Axis<X> xAxis = getChart().getXAxis();
+    final double width = xAxis.getWidth();
+
+    final int end = getDataSize() - 1;
+
+    final double min = getX(0);
+    final double max = getX(end);
+
+    final double left = xAxis.getValueForDisplay(0).doubleValue();
+    final double right = xAxis.getValueForDisplay(width).doubleValue();
+
+    // find file position for first visible point
+    int first;
+    if (left <= min) {
+      first = 0;
+    } else if (left >= max) {
+      first = end;
+    } else {
+      // time series should be linear on x, so guess file position and scan
+      first = (int) (((left - min) / (max - min)) * end);
+      if (getX(first) < left) {
+        first = findFirst(first + 1, left) - 1;
+      } else {
+        first = findLast(first - 1, left);
+      }
+    }
+
+    // find file position for last visible point
+    int last;
+    if (right <= min) {
+      last = 0;
+    } else if (right >= max) {
+      last = end;
+    } else {
+      // time series should be linear on x, so guess file position and scan
+      last = (int) (((right - min) / (max - min)) * end);
+      if (getX(last) < right) {
+        last = findFirst(last + 1, right);
+      } else {
+        last = findLast(last - 1, right) + 1;
+      }
+    }
+
+    // fit threshold to series width
+    int threshold = (int) width;
+    if (left < min || right > max) {
+      // there is space on either/both ends so adjust the threshold
+      threshold = Math.max((int) (xAxis.getDisplayPosition(convertX(Math.min(right, max))) - xAxis.getDisplayPosition(convertX(Math.max(left, min)))), 3);
+    }
+    
+    // using 2 times the width makes it look a little smoother. Consider dynamic bucket size algorithm.
+    // you can still seem some points blink in and out on zoom and pan
+    // maybe used fixed points for bucket boundaries, first/last buckets will shrink by first/last data position
+    final Collection<Data<X, Y>> v = new ThresholdDataCollection(first, last - first + 1, threshold);
+
+    return v;
+  }
+
+
+
+  protected Data<X, Y> getData(final int index) {
+    Data<X, Y> data = createData(index);
+    data.setNode(createSymbol(data));
+    return data;
+  }
+  
+  
+  private Node createSymbol(Data<X, Y> data) {
+    return new HoveredThresholdNode(NumberFormat.getNumberInstance().format(data.getYValue()));
+  }
+
+
+  // TODO Make these Abstract
+  @Override
+  public abstract int getDataSize();
+
+  protected abstract Data<X,Y> createData(final int index);
+
+  protected abstract double getX(final int index);
+
+  protected abstract X convertX(double x);
+
+  protected abstract double getY(final int index);
+
+  protected abstract Y convertY(double y);
+
+  protected int findFirst(final int start, final double left) {
+    // TODO improve over scan? since likely linear chances are we hit on first try.
+    for (int i = start; i < getDataSize(); i++) {
+      if (getX(i) > left) {
+//        System.out.println("f: " + (i - start));
+        return i;
+      }
+    }
+
+    return -1;
+  }
+
+  protected int findLast(final int start, final double right) {
+    // TODO improve over scan? since likely linear chances are we hit on first try.
+    for (int i = start; i >= 0; i--) {
+      if (getX(i) < right) {
+//        System.out.println("l: " + (start - i));
+        return i;
+      }
+    }
+
+    return getDataSize() - 1;
+  }
+
+  protected class ThresholdDataCollection extends AbstractCollection<Data<X, Y>> {
+    final int offset;
+    final int length;
+    final int threshold;
+    final int size;
+
+    public ThresholdDataCollection(final int offset, final int length, final int threshold) {
+      this.offset = offset;
+      this.length = length;
+      this.threshold = threshold;
+      this.size = Math.min(length, (int) threshold);
+
+      System.out.println(MessageFormat.format("ThresholdDataCollection: offset={0}, length={1}, threshold={2}, end={3}", offset, length, threshold, offset + length));
+    }
+
+    @Override
+    public Iterator<Data<X, Y>> iterator() {
+      if (length > threshold) {
+        return createDownsampleVisibleIterator();
+      } else {
+        return createVisibleIterator();
+      }
+    }
+
+    @Override
+    public int size() {
+      return size;
+    }
+
+    protected Iterator<Data<X, Y>> createVisibleIterator() {
+      return new VisibleIterator();
+    }
+
+    protected Iterator<Data<X, Y>> createDownsampleVisibleIterator() {
+      return new DownsampleVisibleIterator();
+    }
+
+    protected abstract class AbstractDataIterator implements Iterator<Data<X, Y>> {
+      int index = offset;
+      Data<X, Y> next = null;
+      
+      protected abstract void advance();
+
+      protected Data<X, Y> consume() {
+        final Data<X, Y> data = next;
+        next = null;
+        return data;
+      }
+
+      @Override
+      public boolean hasNext() {
+        advance();
+        return (null != next);
+      }
+
+      @Override
+      public Data<X, Y> next() {
+        if (!hasNext()) {
+          throw new NoSuchElementException();
+        }
+
+        return consume();
+      }
+
+    }
+    
+    protected class VisibleIterator extends AbstractDataIterator {
+      
+       
+      @Override
+      protected void advance() {
+        if (null != next) {
+          return;
+        }
+
+        if (index >= (offset + length)) {
+          return;
+        }
+
+        next = getData(index);
+        index++;
+      }
+    }
+
+    protected class DownsampleVisibleIterator extends AbstractDataIterator {
+      // Bucket size. Leave room for start and end data points
+      final double bucketSize = (double) (length - 2) / (threshold - 2);
+
+      int bucket = 0;
+      int a = index; // Initially a is the first point in the triangle
+
+      public DownsampleVisibleIterator() {
+        super();
+
+        System.out.println(MessageFormat.format("DownsampleVisibleIterator: bucketSize={0}", bucketSize));
+      }
+
+      @Override
+      protected void advance() {
+        // TODO when zooming out bound to visible width not chart width
+        if (null != next) {
+          return;
+        }
+
+        if (index >= (offset + length)) {
+          return;
+        }
+
+//         final long start = System.nanoTime();
+//         try {
+
+        if (offset == index) {
+          // Always add the first point
+          next = getData(index);
+          index++;
+          return;
+        }
+
+        if (bucket < threshold - 2) {
+          // final long start2 = System.nanoTime();
+          // Calculate point average for next bucket (containing c)
+          double pointCX = 0;
+          double pointCY = 0;
+          int pointCStart = (int) Math.floor((bucket + 1) * bucketSize) + offset + 1;
+          int pointCEnd = (int) Math.floor((bucket + 2) * bucketSize) + offset + 1;
+          pointCEnd = Math.min(pointCEnd, (offset + length));
+          final int pointCSize = pointCEnd - pointCStart;
+          for (; pointCStart < pointCEnd; pointCStart++) {
+            pointCX += getX(pointCStart);
+            pointCY += getY(pointCStart);
+          }
+          pointCX /= pointCSize;
+          pointCY /= pointCSize;
+          // System.out.println("time2: " + (System.nanoTime() - start2));
+
+          // Point a
+          // TODO cache?
+          final double pointAX = getX(a);
+          final double pointAY = getY(a);
+
+          // Get the range for bucket b
+          int pointBStart = (int) Math.floor((bucket + 0) * bucketSize) + offset + 1;
+          final int pointBEnd = (int) Math.floor((bucket + 1) * bucketSize) + offset + 1;
+          double maxArea = -1;
+          for (; pointBStart < pointBEnd; pointBStart++) {
+            index++;
+            // Calculate triangle area over three buckets
+            final double area = Math.abs((pointAX - pointCX) * (getY(pointBStart) - pointAY) - (pointAX - getX(pointBStart))
+                * (pointCY - pointAY)) * 0.5;
+            if (area > maxArea) {
+              maxArea = area;
+              a = pointBStart; // Next a is this b
+            }
+          }
+
+          // Pick this point from the bucket
+          next = getData(a);
+          bucket++;
+          return;
+        }
+
+        // Always add last
+        assert ((offset + length - 1) == index);
+        next = getData(index);
+        index++;
+//         } finally {
+//         System.out.println(MessageFormat.format("DownsampleVisibleIterator: bucket={0}, time={1}ms",
+//         bucket, ((double) System.nanoTime() - start) / 1000000));
+//         }
+      }
+    }
+
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataChangedListener.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataChangedListener.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataChangedListener.java
new file mode 100644
index 0000000..c88696e
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataChangedListener.java
@@ -0,0 +1,21 @@
+/*
+ * 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.geode.jvsd.javafx.scene.chart;
+
+public interface DataChangedListener {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataSet.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataSet.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataSet.java
new file mode 100644
index 0000000..c234761
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DataSet.java
@@ -0,0 +1,29 @@
+/*
+ * 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.geode.jvsd.javafx.scene.chart;
+
+import java.util.List;
+
+import com.pivotal.javafx.scene.chart.Data;
+
+public interface DataSet<X, Y> extends javafx.beans.Observable {
+  public List<Data<X, Y>> getData(X from, X to, int limit);
+
+  public void addListener(DataChangedListener listener);
+
+  public void removeListener(DataChangedListener listener);
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DateAxis.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DateAxis.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DateAxis.java
new file mode 100644
index 0000000..f423489
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/javafx/scene/chart/DateAxis.java
@@ -0,0 +1,393 @@
+/*
+ * Portions of this source copied with love from https://bitbucket.org/sco0ter/extfx
+ * under the following license:
+ * 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, Christian Schudt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.apache.geode.jvsd.javafx.scene.chart;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.beans.property.ReadOnlyDoubleWrapper;
+import javafx.scene.chart.ValueAxis;
+import javafx.util.Duration;
+import javafx.util.StringConverter;
+
+import com.sun.javafx.charts.ChartLayoutAnimator;
+
+/**
+ * Implemenation of {@link ValueAxis} similar to {@link NumberAxis} but with
+ * formatting for date and time.
+ * 
+ * @author jbarrett
+ * 
+ */
+public final class DateAxis extends ValueAxis<Number> {
+
+  private ChartLayoutAnimator animator = new ChartLayoutAnimator(this);
+
+  private Object currentAnimationID;
+
+  private Interval actualInterval = Interval.DECADE;
+
+  /**
+   * Default constructor. By default the lower and upper bound are calculated by
+   * the data.
+   */
+  public DateAxis() {
+  }
+
+  /**
+   * Constructs a date axis with fix lower and upper bounds.
+   * 
+   * @param lowerBound
+   *          The lower bound.
+   * @param upperBound
+   *          The upper bound.
+   */
+  public DateAxis(Long lowerBound, Long upperBound) {
+    this();
+    setAutoRanging(false);
+    setLowerBound(lowerBound);
+    setUpperBound(upperBound);
+  }
+
+  /**
+   * Constructs a date axis with a label and fix lower and upper bounds.
+   * 
+   * @param axisLabel
+   *          The label for the axis.
+   * @param lowerBound
+   *          The lower bound.
+   * @param upperBound
+   *          The upper bound.
+   */
+  public DateAxis(String axisLabel, Long lowerBound, Long upperBound) {
+    this(lowerBound, upperBound);
+    setLabel(axisLabel);
+  }
+
+  @Override
+  protected Object autoRange(double minValue, double maxValue, double length, double labelSize) {
+    return new Object[] { (long) minValue, (long) maxValue, calculateNewScale(length, (long) minValue, (long) maxValue) };
+  }
+
+  @Override
+  protected void setRange(Object range, boolean animating) {
+    Object[] r = (Object[]) range;
+    long oldLowerBound = (long) getLowerBound();
+    long lower = (long) r[0];
+    long upper = (long) r[1];
+    double scale = (double) r[2];
+    setLowerBound(lower);
+    setUpperBound(upper);
+
+    if (animating) {
+      animator.stop(currentAnimationID);
+      currentAnimationID = animator.animate(
+          new KeyFrame(Duration.ZERO,
+              new KeyValue(currentLowerBound, oldLowerBound),
+              new KeyValue(scalePropertyImplProtected(), getScale())),
+          new KeyFrame(Duration.millis(700),
+              new KeyValue(currentLowerBound, lower), 
+              new KeyValue(scalePropertyImplProtected(), scale)));
+
+    } else {
+      currentLowerBound.set(getLowerBound());
+      setScale(scale);
+    }
+  }
+
+  @Override
+  protected Object getRange() {
+    return new Object[] { (long) getLowerBound(), (long) getUpperBound() };
+  }
+
+  @Override
+  protected List<Number> calculateTickValues(double v, Object range) {
+    Object[] r = (Object[]) range;
+    long lower = (long) r[0];
+    long upper = (long) r[1];
+
+    List<Date> dateList = new ArrayList<Date>();
+    Calendar calendar = Calendar.getInstance();
+
+    // The preferred gap which should be between two tick marks.
+    double averageTickGap = 100;
+    double averageTicks = v / averageTickGap;
+
+    List<Date> previousDateList = new ArrayList<Date>();
+
+    Interval previousInterval = Interval.values()[0];
+
+    // Starting with the greatest interval, add one of each calendar unit.
+    for (Interval interval : Interval.values()) {
+      // Reset the calendar.
+      calendar.setTime(new Date(lower));
+      // Clear the list.
+      dateList.clear();
+      previousDateList.clear();
+      actualInterval = interval;
+
+      // Loop as long we exceeded the upper bound.
+      while (calendar.getTime().getTime() <= upper) {
+        dateList.add(calendar.getTime());
+        calendar.add(interval.interval, interval.amount);
+      }
+      // Then check the size of the list. If it is greater than the amount of
+      // ticks, take that list.
+      if (dateList.size() > averageTicks) {
+        calendar.setTime(new Date(lower));
+        // Recheck if the previous interval is better suited.
+        while (calendar.getTime().getTime() <= upper) {
+          previousDateList.add(calendar.getTime());
+          calendar.add(previousInterval.interval, previousInterval.amount);
+        }
+        break;
+      }
+
+      previousInterval = interval;
+    }
+    if (previousDateList.size() - averageTicks > averageTicks - dateList.size()) {
+      dateList = previousDateList;
+      actualInterval = previousInterval;
+    }
+
+    // At last add the upper bound.
+    dateList.add(new Date(upper));
+
+    List<Number> evenDateList = makeDatesEven(dateList, calendar);
+    // If there are at least three dates, check if the gap between the lower
+    // date and the second date is at least half the gap of the second and third
+    // date.
+    // Do the same for the upper bound.
+    // If gaps between dates are to small, remove one of them.
+    // This can occur, e.g. if the lower bound is 25.12.2013 and years are
+    // shown. Then the next year shown would be 2014 (01.01.2014) which would be
+    // too narrow to 25.12.2013.
+    if (evenDateList.size() > 2) {
+
+      long secondDate = evenDateList.get(1).longValue();
+      long thirdDate = evenDateList.get(2).longValue();
+      long lastDate = evenDateList.get(dateList.size() - 2).longValue();
+      long previousLastDate = evenDateList.get(dateList.size() - 3).longValue();
+
+      // If the second date is too near by the lower bound, remove it.
+      if (secondDate - lower < (thirdDate - secondDate) / 2) {
+        evenDateList.remove(secondDate);
+      }
+
+      // If difference from the upper bound to the last date is less than the
+      // half of the difference of the previous two dates,
+      // we better remove the last date, as it comes to close to the upper
+      // bound.
+      if (upper - lastDate < (lastDate - previousLastDate) / 2) {
+        evenDateList.remove(lastDate);
+      }
+    }
+
+    return evenDateList;
+  }
+
+  @Override
+  protected String getTickMarkLabel(final Number ts) {
+    final Date date = new Date(ts.longValue());
+
+    StringConverter<Number> converter = getTickLabelFormatter();
+    if (converter != null) {
+      return converter.toString(date.getTime());
+    }
+
+    DateFormat dateFormat;
+    Calendar calendar = Calendar.getInstance();
+    calendar.setTime(date);
+
+    if (actualInterval.interval == Calendar.YEAR && calendar.get(Calendar.MONTH) == 0 && calendar.get(Calendar.DATE) == 1) {
+      dateFormat = new SimpleDateFormat("yyyy");
+    } else if (actualInterval.interval == Calendar.MONTH && calendar.get(Calendar.DATE) == 1) {
+      dateFormat = new SimpleDateFormat("MMM yy");
+    } else {
+      switch (actualInterval.interval) {
+      case Calendar.DATE:
+      case Calendar.WEEK_OF_YEAR:
+      default:
+        dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
+        break;
+      case Calendar.HOUR:
+      case Calendar.MINUTE:
+        dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
+        break;
+      case Calendar.SECOND:
+        dateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM);
+        break;
+      case Calendar.MILLISECOND:
+        dateFormat = DateFormat.getTimeInstance(DateFormat.FULL);
+        break;
+      }
+    }
+    return dateFormat.format(date);
+  }
+
+  /**
+   * Makes dates even, in the sense of that years always begin in January,
+   * months always begin on the 1st and days always at midnight.
+   * 
+   * @param dates
+   *          The list of dates.
+   * @return The new list of dates.
+   */
+  private List<Number> makeDatesEven(List<Date> dates, Calendar calendar) {
+    // If the dates contain more dates than just the lower and upper bounds,
+    // make the dates in between even.
+    // TODO if (dates.size() > 2) {
+    List<Number> evenDates = new ArrayList<Number>();
+
+    // For each interval, modify the date slightly by a few millis, to make sure
+    // they are different days.
+    // This is because Axis stores each value and won't update the tick labels,
+    // if the value is already known.
+    // This happens if you display days and then add a date many years in the
+    // future the tick label will still be displayed as day.
+    for (int i = 0; i < dates.size(); i++) {
+      calendar.setTime(dates.get(i));
+      switch (actualInterval.interval) {
+      case Calendar.YEAR:
+        // If its not the first or last date (lower and upper bound), make the
+        // year begin with first month and let the months begin with first day.
+        if (i != 0 && i != dates.size() - 1) {
+          calendar.set(Calendar.MONTH, 0);
+          calendar.set(Calendar.DATE, 1);
+        }
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 6);
+        break;
+      case Calendar.MONTH:
+        // If its not the first or last date (lower and upper bound), make the
+        // months begin with first day.
+        if (i != 0 && i != dates.size() - 1) {
+          calendar.set(Calendar.DATE, 1);
+        }
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 5);
+        break;
+      case Calendar.WEEK_OF_YEAR:
+        // Make weeks begin with first day of week?
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 4);
+        break;
+      case Calendar.DATE:
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 3);
+        break;
+      case Calendar.HOUR:
+        if (i != 0 && i != dates.size() - 1) {
+          calendar.set(Calendar.MINUTE, 0);
+          calendar.set(Calendar.SECOND, 0);
+        }
+        calendar.set(Calendar.MILLISECOND, 2);
+        break;
+      case Calendar.MINUTE:
+        if (i != 0 && i != dates.size() - 1) {
+          calendar.set(Calendar.SECOND, 0);
+        }
+        calendar.set(Calendar.MILLISECOND, 1);
+        break;
+      case Calendar.SECOND:
+        calendar.set(Calendar.MILLISECOND, 0);
+        break;
+
+      }
+      evenDates.add(calendar.getTime().getTime());
+    }
+
+    return evenDates;
+    // } else {
+    // return dates;
+    // }
+  }
+
+  /**
+   * The intervals, which are used for the tick labels. Beginning with the
+   * largest interval, the axis tries to calculate the tick values for this
+   * interval. If a smaller interval is better suited for, that one is taken.
+   */
+  private enum Interval {
+    DECADE(Calendar.YEAR, 10), YEAR(Calendar.YEAR, 1), MONTH_6(Calendar.MONTH, 6), MONTH_3(Calendar.MONTH, 3), MONTH_1(Calendar.MONTH, 1), WEEK(
+        Calendar.WEEK_OF_YEAR, 1), DAY(Calendar.DATE, 1), HOUR_12(Calendar.HOUR, 12), HOUR_6(Calendar.HOUR, 6), HOUR_3(Calendar.HOUR, 3), HOUR_1(Calendar.HOUR,
+        1), MINUTE_15(Calendar.MINUTE, 15), MINUTE_5(Calendar.MINUTE, 5), MINUTE_1(Calendar.MINUTE, 1), SECOND_15(Calendar.SECOND, 15), SECOND_5(
+        Calendar.SECOND, 5), SECOND_1(Calendar.SECOND, 1), MILLISECOND(Calendar.MILLISECOND, 1);
+
+    private final int amount;
+
+    private final int interval;
+
+    private Interval(int interval, int amount) {
+      this.interval = interval;
+      this.amount = amount;
+    }
+  }
+
+  @Override
+  protected List<Number> calculateMinorTickMarks() {
+    return Collections.<Number>emptyList();
+  }
+
+  /* Access to package protected method */
+  private static final Method scalePropertyImplMethod;
+
+  static {
+    try {
+      scalePropertyImplMethod = ValueAxis.class.getDeclaredMethod("scalePropertyImpl");
+      scalePropertyImplMethod.setAccessible(true);
+    } catch (SecurityException | NoSuchMethodException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  protected ReadOnlyDoubleWrapper scalePropertyImplProtected() {
+    try {
+      return (ReadOnlyDoubleWrapper) scalePropertyImplMethod.invoke(this);
+    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a86c01a/geode-jvsd/src/main/java/org/apache/geode/jvsd/model/ResourceWrapper.java
----------------------------------------------------------------------
diff --git a/geode-jvsd/src/main/java/org/apache/geode/jvsd/model/ResourceWrapper.java b/geode-jvsd/src/main/java/org/apache/geode/jvsd/model/ResourceWrapper.java
new file mode 100644
index 0000000..fdd2f4a
--- /dev/null
+++ b/geode-jvsd/src/main/java/org/apache/geode/jvsd/model/ResourceWrapper.java
@@ -0,0 +1,73 @@
+/*
+ * 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.geode.jvsd.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.geode.jvsd.model.stats.StatArchiveFile;
+
+/**
+* @author Jens Deppe
+*/
+public class ResourceWrapper {
+  private int row;
+
+  private StatArchiveFile.ResourceInst inst;
+
+  public ResourceWrapper(StatArchiveFile.ResourceInst inst, int idx) {
+    this.inst = inst;
+    this.row = idx;
+  }
+
+  public int getRow() {
+    return row;
+  }
+
+  public Date getStartTime() {
+    return new Date(inst.getFirstTimeMillis());
+  }
+
+  public int getSamples() {
+    return inst.getSampleCount();
+  }
+
+  public String getType() {
+    return inst.getType().getName();
+  }
+
+  public String getName() {
+    return inst.getName();
+  }
+
+  public List<String> getStatNames() {
+    List<String> statNames = new ArrayList<>();
+
+    for (StatArchiveFile.StatValue sv : inst.getStatValues()) {
+      if (!(sv.getSnapshotsAverage() == 0 && sv.getSnapshotsMaximum() == 0 && sv.
+          getSnapshotsMinimum() == 0)) {
+        statNames.add(sv.getDescriptor().getName());
+      }
+    }
+    return statNames;
+  }
+
+  public StatArchiveFile.StatValue getStatValue(String name) {
+    return inst.getStatValue(name);
+  }
+}


Mime
View raw message