custom charts: Add interfaces for computing data
authorGabriel-Andrew Pollo-Guilbert <gabrielpolloguilbert@gmail.com>
Tue, 26 Jul 2016 18:49:10 +0000 (14:49 -0400)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Sat, 13 Aug 2016 00:39:07 +0000 (20:39 -0400)
This patch adds three interfaces that are used for
consuming objects in the source of the data provider.
An object is first consumed by a chart consumer. This
first consumer sends the object to all of its series
consumers. Then, each series consumer passes the
object to individual data consumer.

While this may seems a lot, it is rather simple and
it allows going to the stream of data only once. It
also provides flexible data computing as well as
reusing code for different charts.

Change-Id: Ife9f321fa840cde6f499a09094ec996d6bf669f2
Signed-off-by: Gabriel-Andrew Pollo-Guilbert <gabrielpolloguilbert@gmail.com>
Reviewed-on: https://git.eclipse.org/r/78011
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Hudson CI
tmf/org.eclipse.tracecompass.tmf.chart.ui/META-INF/MANIFEST.MF
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/IConsumerAggregator.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/NumericalConsumerAggregator.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/IChartConsumer.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/IDataConsumer.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/ISeriesConsumer.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/NumericalConsumer.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/package-info.java [new file with mode: 0644]

index a27bd601dd4f1ef4b1ec87174f7acf9c9e689862..171e0ec1d4162bc806862f04c75af6631aaca842 100644 (file)
@@ -12,8 +12,11 @@ Require-Bundle: org.eclipse.ui,
  org.eclipse.core.runtime,
  org.eclipse.jface,
  org.eclipse.tracecompass.common.core,
+ org.eclipse.tracecompass.tmf.chart.core,
  org.eclipse.tracecompass.tmf.core
 Export-Package: org.eclipse.tracecompass.internal.tmf.chart.ui;x-internal:=true,
+ org.eclipse.tracecompass.internal.tmf.chart.ui.aggregator;x-internal:=true,
+ org.eclipse.tracecompass.internal.tmf.chart.ui.consumer;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.chart.ui.data;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.chart.ui.format;x-internal:=true
 Import-Package: com.google.common.collect
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/IConsumerAggregator.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/IConsumerAggregator.java
new file mode 100644 (file)
index 0000000..d66d379
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.chart.ui.aggregator;
+
+import java.util.function.Consumer;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.internal.tmf.chart.ui.consumer.IDataConsumer;
+import org.eclipse.tracecompass.internal.tmf.chart.ui.consumer.NumericalConsumer;
+
+/**
+ * This interface is used for performing operations on multiple
+ * {@link IDataConsumer}. As of right now, it is used for computing total range
+ * of multiple {@link NumericalConsumer}. Normally, it should process the data
+ * consumers only when they are done processing individual object from the
+ * stream of data.
+ *
+ * FIXME: Find a better name. It consumes consumer, but it kind of seems
+ * confusing calling it IConsumerConsumer.
+ *
+ * @author Gabriel-Andrew Pollo-Guilbert
+ */
+public interface IConsumerAggregator extends Consumer<@NonNull IDataConsumer> {
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/NumericalConsumerAggregator.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/NumericalConsumerAggregator.java
new file mode 100644 (file)
index 0000000..fab063a
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.chart.ui.aggregator;
+
+import java.math.BigDecimal;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.chart.ui.consumer.IDataConsumer;
+import org.eclipse.tracecompass.internal.tmf.chart.ui.consumer.NumericalConsumer;
+import org.eclipse.tracecompass.internal.tmf.chart.ui.data.ChartRange;
+import org.eclipse.tracecompass.internal.tmf.chart.ui.data.ChartRangeMap;
+
+/**
+ * This class is used for processing {@link NumericalConsumer} after they are
+ * done processing objects from the stream of data. Right now, it only computes
+ * the total range of multiple consumers.
+ *
+ * FIXME: This should not be implemented as a Consumer. A consumer should be
+ * stateless. This could be implemented via a andThen on the data consumers and
+ * modify an object that contains the information of this class.
+ *
+ * @author Gabriel-Andrew Pollo-Guilbert
+ */
+public class NumericalConsumerAggregator implements IConsumerAggregator {
+
+    // ------------------------------------------------------------------------
+    // Members
+    // ------------------------------------------------------------------------
+
+    private @Nullable BigDecimal fMinimum;
+    private @Nullable BigDecimal fMaximum;
+
+    // ------------------------------------------------------------------------
+    // Overriden Methods
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void accept(IDataConsumer obj) {
+        NumericalConsumer consumer = (NumericalConsumer) obj;
+
+        BigDecimal nextMin = new BigDecimal(consumer.getMin().toString());
+        BigDecimal nextMax = new BigDecimal(consumer.getMax().toString());
+
+        BigDecimal min = fMinimum;
+        BigDecimal max = fMaximum;
+
+        /* Set initial min and max values */
+        if (min == null || max == null) {
+            fMinimum = nextMin;
+            fMaximum = nextMax;
+
+            return;
+        }
+
+        /* Update min and max values */
+        fMinimum = min.min(nextMin);
+        fMaximum = max.max(nextMax);
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Accessor that returns a range map of all the numerical consumers. The
+     * internal range of the map created with default values and the external
+     * range is created from the computed minimum and maximum values of this
+     * aggregator.
+     *
+     * @return The chart range map that covers all data points
+     */
+    public ChartRangeMap getChartRanges() {
+        BigDecimal min = fMinimum;
+        BigDecimal max = fMaximum;
+
+        if (min == null || max == null) {
+            return new ChartRangeMap();
+        }
+
+        ChartRange external = new ChartRange(min, max);
+        return new ChartRangeMap(external);
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/package-info.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/aggregator/package-info.java
new file mode 100644 (file)
index 0000000..8398ba7
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.tmf.chart.ui.aggregator;
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/IChartConsumer.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/IChartConsumer.java
new file mode 100644 (file)
index 0000000..95b7897
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.chart.ui.consumer;
+
+import java.util.function.Consumer;
+
+/**
+ * This interface is the entry point for consuming data in the chart plugin.
+ * Each chart type should implement this interface. When an object needs to be
+ * consumed, it is first sent to this consumer which passes the object all its
+ * {@link ISeriesConsumer}. When all the data has been consumed,
+ * {@link #finish()} is called.
+ * <p>
+ * Consider a XY chart with <i>n</i> series where both axes are numerical. Thus,
+ * the implemented class should have <i>n</i> {@link ISeriesConsumer}. This
+ * consumer first receives an object from the stream of data and passes it to
+ * all its series consumer. Since both axes are numerical, the series consumer
+ * test and send the object to their X and Y {@link IDataConsumer}. This last
+ * consumer contains the final series that can be plotted. When all the data has
+ * been processed, the {@link #finish()} method is called. In the case of an XY
+ * chart with numerical axes, it is used for computing the total range of the
+ * all the series.
+ *
+ * @see ISeriesConsumer
+ * @see IDataConsumer
+ *
+ * @author Gabriel-Andrew Pollo-Guilbert
+ */
+public interface IChartConsumer extends Consumer<Object> {
+
+    /**
+     * This method is called when all the data has been processed. It can be
+     * used by the implemented chart consumer or not.
+     */
+    void finish();
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/IDataConsumer.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/IDataConsumer.java
new file mode 100644 (file)
index 0000000..d3c79c3
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.chart.ui.consumer;
+
+import java.util.function.Consumer;
+
+/**
+ * This interface consumes any data that comes from a {@link ISeriesConsumer}.
+ * <p>
+ * For example, it can be though of an axis consumer in XY charts since there
+ * should be one for the X and Y axis.
+ *
+ * @author Gabriel-Andrew Pollo-Guilbert
+ */
+public interface IDataConsumer extends Consumer<Object> {
+
+    /**
+     * This method maps and tests if a value is valid for the chart. It should
+     * always be called before {@link #accept(Object)}.
+     *
+     * @param obj
+     *            The object to map the value from
+     * @return {@code true} if the mapped value is valid, else {@code false}
+     */
+    boolean test(Object obj);
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/ISeriesConsumer.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/ISeriesConsumer.java
new file mode 100644 (file)
index 0000000..8e57255
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.chart.ui.consumer;
+
+import java.util.function.Consumer;
+
+/**
+ * This interface consumes any data that comes from a {@link IChartConsumer}.
+ * Every object that it receives is sent to its own {@link IDataConsumer}. The
+ * main benefit of this consumer is that it can easily reject (x, y) couple that
+ * are invalid for plotting. An object can be tested with
+ * {@link IDataConsumer#test(Object)} before being consumed into an (x, y)
+ * couple.
+ * <p>
+ * For example, a XY chart should have a series consumer for each of the plotted
+ * series. There would have two consumer in a XY chart that plot the following
+ * series: "start VS name" and "end VS name".
+ *
+ * @see IChartConsumer
+ * @see IDataConsumer
+ *
+ * @author Gabriel-Andrew Pollo-Guilbert
+ */
+public interface ISeriesConsumer extends Consumer<Object> {
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/NumericalConsumer.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/NumericalConsumer.java
new file mode 100644 (file)
index 0000000..bd4b308
--- /dev/null
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.chart.ui.consumer;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.resolver.INumericalResolver;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * This class processes numerical values in order to create valid data for a XY
+ * chart. It takes a {@link INumericalResolver} for mapping values and a
+ * {@link Predicate} for testing them.
+ * <p>
+ * It also computes the minimum and maximum values of all the numbers it has
+ * consumed.
+ *
+ * @author Gabriel-Andrew Pollo-Guilbert
+ */
+public class NumericalConsumer implements IDataConsumer {
+
+    // ------------------------------------------------------------------------
+    // Members
+    // ------------------------------------------------------------------------
+
+    private final INumericalResolver<Object, Number> fResolver;
+    private final Predicate<@Nullable Number> fPredicate;
+    private final List<Number> fData = new ArrayList<>();
+    private Number fMin;
+    private Number fMax;
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Constructor with a default non null predicate.
+     *
+     * @param resolver
+     *            The resolver that maps values
+     */
+    public NumericalConsumer(INumericalResolver<Object, Number> resolver) {
+        fResolver = resolver;
+        fPredicate = Objects::nonNull;
+        fMin = fResolver.getMaxValue();
+        fMax = fResolver.getMinValue();
+    }
+
+    /**
+     * Overloaded constructor with a predicate.
+     *
+     * @param resolver
+     *            The resolver that maps values
+     * @param predicate
+     *            The predicate for testing values
+     */
+    public NumericalConsumer(INumericalResolver<Object, Number> resolver, Predicate<@Nullable Number> predicate) {
+        fResolver = resolver;
+        fPredicate = predicate;
+        fMin = fResolver.getMaxValue();
+        fMax = fResolver.getMinValue();
+    }
+
+    // ------------------------------------------------------------------------
+    // Overriden methods
+    // ------------------------------------------------------------------------
+
+    @Override
+    public boolean test(Object obj) {
+        Number number = fResolver.getMapper().apply(obj);
+        return fPredicate.test(number);
+    }
+
+    @Override
+    public void accept(Object obj) {
+        Number number = checkNotNull(fResolver.getMapper().apply(obj));
+
+        /* Update the minimum value */
+        if (fResolver.getComparator().compare(number, fMin) < 0) {
+            fMin = number;
+        }
+
+        /* Update the maximum value */
+        if (fResolver.getComparator().compare(number, fMax) > 0) {
+            fMax = number;
+        }
+
+        fData.add(number);
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Accessor that returns the generated list of number.
+     *
+     * @return The list of number
+     */
+    public List<Number> getData() {
+        return ImmutableList.copyOf(fData);
+    }
+
+    /**
+     * Accessor that returns the minimum numerical value that has been consumed.
+     *
+     * @return The minimum value
+     */
+    public Number getMin() {
+        return fMin;
+    }
+
+    /**
+     * Accessor that returns the maximum numerical value that has been consumed.
+     *
+     * @return The maximum value
+     */
+    public Number getMax() {
+        return fMax;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/package-info.java b/tmf/org.eclipse.tracecompass.tmf.chart.ui/src/org/eclipse/tracecompass/internal/tmf/chart/ui/consumer/package-info.java
new file mode 100644 (file)
index 0000000..4a0d816
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.tmf.chart.ui.consumer;
This page took 0.032065 seconds and 5 git commands to generate.