Bug 459246 - introduced ICalculatedValueCache interface to be able to
exchange the caching implementation for summary and groupby summary
values

Change-Id: Ib1e2df32699ef9f800400bb0c6dabf53b7667512
Signed-off-by: Dirk Fauth <dirk.fauth@googlemail.com>
diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCacheTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCacheTest.java
index 0b6e3fc..d131ca4 100644
--- a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCacheTest.java
+++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCacheTest.java
@@ -24,7 +24,7 @@
  */
 public class CalculatedValueCacheTest {
 
-    CalculatedValueCache valueCache;
+    ICalculatedValueCache valueCache;
 
     ICalculator calculator = new ICalculator() {
 
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/summaryrow/SummaryRowLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/summaryrow/SummaryRowLayer.java
index 577005e..ac833a0 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/summaryrow/SummaryRowLayer.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/summaryrow/SummaryRowLayer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 Original authors and others.
+ * Copyright (c) 2012, 2013, 2015 Original authors and others.
  * 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
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     Original authors and others - initial API and implementation
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 459246
  ******************************************************************************/
 package org.eclipse.nebula.widgets.nattable.summaryrow;
 
@@ -30,6 +31,7 @@
 import org.eclipse.nebula.widgets.nattable.summaryrow.command.CalculateSummaryRowValuesCommand;
 import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
 import org.eclipse.nebula.widgets.nattable.util.CalculatedValueCache;
+import org.eclipse.nebula.widgets.nattable.util.ICalculatedValueCache;
 import org.eclipse.nebula.widgets.nattable.util.ICalculator;
 
 /**
@@ -82,7 +84,7 @@
      * The value cache that contains the summary values and performs summary
      * calculation in background processes if necessary.
      */
-    private CalculatedValueCache valueCache;
+    private ICalculatedValueCache valueCache;
     /**
      * Converter that is used to ensure the row height of the summary row is
      * scaled correctly.
@@ -488,4 +490,32 @@
     public void setStandalone(boolean standalone) {
         this.standalone = standalone;
     }
+
+    /**
+     * @return The {@link ICalculatedValueCache} that contains the summary
+     *         values and performs summary calculation in background processes
+     *         if necessary.
+     */
+    public ICalculatedValueCache getValueCache() {
+        return this.valueCache;
+    }
+
+    /**
+     * Set the {@link ICalculatedValueCache} that should be used internally to
+     * calculate the summary values in a background thread and cache the
+     * results.
+     * <p>
+     * <b><u>Note:</u></b> By default the {@link CalculatedValueCache} is used.
+     * Be sure you know what you are doing when you are trying to exchange the
+     * implementation.
+     * </p>
+     *
+     * @param valueCache
+     *            The {@link ICalculatedValueCache} that contains the summary
+     *            values and performs summary calculation in background
+     *            processes if necessary.
+     */
+    public void setValueCache(ICalculatedValueCache valueCache) {
+        this.valueCache = valueCache;
+    }
 }
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCache.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCache.java
index b9a68af..eee604b 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCache.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/CalculatedValueCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014 Dirk Fauth and others.
+ * Copyright (c) 2014, 2015 Dirk Fauth and others.
  * 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
@@ -8,6 +8,7 @@
  * Contributors:
  *    Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation
  *    Roman Flueckiger <roman.flueckiger@mac.com - switched to concurrent hash maps to prevent a concurrency issue
+ *    Dirk Fauth <dirk.fauth@googlemail.com> - Bug 459246
  *******************************************************************************/
 package org.eclipse.nebula.widgets.nattable.util;
 
@@ -29,10 +30,8 @@
  * {@link ICalculatedValueCacheKey} as the key for the value cache. Usually the
  * internal default implementations for column or row position, or the
  * column-row coordinates should fit most of the use cases.
- *
- * @author Dirk Fauth
  */
-public class CalculatedValueCache {
+public class CalculatedValueCache implements ICalculatedValueCache {
 
     /**
      * The ILayer this value cache is connected to. Needed to perform cell
@@ -114,8 +113,7 @@
      *            Flag to specify if the row position should be used as cache
      *            key.
      */
-    public CalculatedValueCache(ILayer layer, boolean useColumnAsKey,
-            boolean useRowAsKey) {
+    public CalculatedValueCache(ILayer layer, boolean useColumnAsKey, boolean useRowAsKey) {
         this(layer, useColumnAsKey, useRowAsKey, true);
     }
 
@@ -146,8 +144,7 @@
      *            Flag to specify if the update of the calculated values should
      *            be performed smoothly.
      */
-    public CalculatedValueCache(ILayer layer, boolean useColumnAsKey,
-            boolean useRowAsKey, boolean smoothUpdates) {
+    public CalculatedValueCache(ILayer layer, boolean useColumnAsKey, boolean useRowAsKey, boolean smoothUpdates) {
         this.layer = layer;
         this.executor = Executors.newCachedThreadPool();
 
@@ -156,36 +153,9 @@
         this.smoothUpdates = smoothUpdates;
     }
 
-    /**
-     * Returns the calculated value for the specified column and row position.
-     * If there is no calculated value for that coordinates in the cache or
-     * there is a potentially stale value, the re-calculation of the value is
-     * executed.
-     * <p>
-     * This method tries to use a predefined cache key dependent on the
-     * configuration of this CalculatedValueCache.
-     *
-     * @param columnPosition
-     *            The column position of the requested value.
-     * @param rowPosition
-     *            The row position of the requested value.
-     * @param calculateInBackground
-     *            Flag to specify whether the value calculation should be
-     *            processed in the background or not. Setting this value to
-     *            <code>false</code> will cause calculation in the UI thread,
-     *            which is usually necessary in case of exporting and printing.
-     * @param calculator
-     *            The {@link ICalculator} that is used for calculating the
-     *            values.
-     * @return The value for the given coordinates.
-     *
-     * @throws IllegalStateException
-     *             if this CalculatedValueCache is configured to not use the
-     *             column and row position for cache key definition.
-     */
-    public Object getCalculatedValue(final int columnPosition,
-            final int rowPosition, boolean calculateInBackground,
-            final ICalculator calculator) {
+    @Override
+    public Object getCalculatedValue(final int columnPosition, final int rowPosition,
+            boolean calculateInBackground, final ICalculator calculator) {
 
         ICalculatedValueCacheKey key = null;
         if (this.useColumnAsKey && this.useRowAsKey) {
@@ -204,35 +174,9 @@
                 calculateInBackground, calculator);
     }
 
-    /**
-     * Returns the calculated value for the specified column and row position.
-     * If there is no calculated value for that coordinates in the cache or
-     * there is a potentially stale value, the re-calculation of the value is
-     * executed.
-     * <p>
-     * This method uses the given ICalculatedValueCacheKey instead of
-     * determining the cache key out of the CalculatedValueCache key
-     * configuration.
-     *
-     * @param columnPosition
-     *            The column position of the requested value.
-     * @param rowPosition
-     *            The row position of the requested value.
-     * @param key
-     *            The key that is used by this CalculatedValueCache.
-     * @param calculateInBackground
-     *            Flag to specify whether the value calculation should be
-     *            processed in the background or not. Setting this value to
-     *            <code>false</code> will cause calculation in the UI thread,
-     *            which is usually necessary in case of exporting and printing.
-     * @param calculator
-     *            The {@link ICalculator} that is used for calculating the
-     *            values.
-     * @return The value for the given coordinates.
-     */
-    public Object getCalculatedValue(final int columnPosition,
-            final int rowPosition, final ICalculatedValueCacheKey key,
-            boolean calculateInBackground, final ICalculator calculator) {
+    @Override
+    public Object getCalculatedValue(final int columnPosition, final int rowPosition,
+            final ICalculatedValueCacheKey key, boolean calculateInBackground, final ICalculator calculator) {
 
         Object result = null;
 
@@ -243,14 +187,12 @@
             result = cacheCopyValue;
 
             // if the calculated value is not the same as the cache value, we
-            // need to
-            // start the calculation process
+            // need to start the calculation process
             if (cacheCopyValue == null
                     || !cacheValuesEqual(cacheValue, cacheCopyValue)) {
 
                 // if this CalculatedValueCache is not configured for smooth
-                // updates, return null
-                // instead of the previous calculated value
+                // updates, return null instead of the previous calculated value
                 if (!this.smoothUpdates) {
                     result = null;
                 }
@@ -262,8 +204,7 @@
                         addToCache(key, summaryValue);
 
                         // only fire an update event if the new calculated value
-                        // is
-                        // different to the value in the cache copy
+                        // is different to the value in the cache copy
                         if (!cacheValuesEqual(summaryValue, cacheCopyValue)
                                 && CalculatedValueCache.this.layer != null) {
                             CalculatedValueCache.this.layer.fireLayerEvent(new CellVisualChangeEvent(
@@ -284,22 +225,12 @@
         return result;
     }
 
-    /**
-     * Clear the internal cache. Doing this will result in triggering new
-     * calculations. If the values where calculated before, using the cache copy
-     * still the already calculated values will be returned until the new
-     * calculation is done.
-     */
+    @Override
     public void clearCache() {
         this.cache.clear();
     }
 
-    /**
-     * Kills all cached values. The internal cache aswell as the cache copy to
-     * support smooth updates of values. This is necessary because on structural
-     * changes, e.g. deleting/adding rows, the cache copy would return false
-     * values.
-     */
+    @Override
     public void killCache() {
         this.cache.clear();
         this.cacheCopy.clear();
@@ -324,9 +255,7 @@
         }
     }
 
-    /**
-     * Cleaning up internal resources like shutting down the ExecutorService.
-     */
+    @Override
     public void dispose() {
         this.executor.shutdownNow();
     }
@@ -346,17 +275,7 @@
                 && value2 != null && value1.equals(value2)));
     }
 
-    /**
-     * Set the layer that should be used by this CalculatedValueCache to trigger
-     * updates after the calculation processing is done. Necessary if the
-     * caching is connected to a data provider for example, which is not able to
-     * fire events itself.
-     *
-     * @param layer
-     *            The ILayer that should be used to fire the
-     *            CellVisualChangeEvent after the background calculation process
-     *            is done.
-     */
+    @Override
     public void setLayer(ILayer layer) {
         this.layer = layer;
     }
@@ -364,8 +283,6 @@
     /**
      * ICalculatedValueCacheKey that uses either the column or row position as
      * key.
-     *
-     * @author Dirk Fauth
      */
     class PositionValueCacheKey implements ICalculatedValueCacheKey {
 
@@ -407,8 +324,6 @@
 
     /**
      * ICalculatedValueCacheKey that uses the column and row position as key.
-     *
-     * @author Dirk Fauth
      */
     class CoordinateValueCacheKey implements ICalculatedValueCacheKey {
 
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/ICalculatedValueCache.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/ICalculatedValueCache.java
new file mode 100644
index 0000000..30d8d4c
--- /dev/null
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/util/ICalculatedValueCache.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Dirk Fauth and others.
+ * 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
+ *
+ * Contributors:
+ *    Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.nebula.widgets.nattable.util;
+
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+
+/**
+ * Interface for specifying a value cache to support value calculations in a
+ * background thread.
+ *
+ * @see CalculatedValueCache
+ */
+public interface ICalculatedValueCache {
+
+    /**
+     * Returns the calculated value for the specified column and row position.
+     * If there is no calculated value for that coordinates in the cache or
+     * there is a potentially stale value, the re-calculation of the value is
+     * executed.
+     * <p>
+     * This method tries to use a predefined cache key dependent on the
+     * configuration of this CalculatedValueCache.
+     *
+     * @param columnPosition
+     *            The column position of the requested value.
+     * @param rowPosition
+     *            The row position of the requested value.
+     * @param calculateInBackground
+     *            Flag to specify whether the value calculation should be
+     *            processed in the background or not. Setting this value to
+     *            <code>false</code> will cause calculation in the UI thread,
+     *            which is usually necessary in case of exporting and printing.
+     * @param calculator
+     *            The {@link ICalculator} that is used for calculating the
+     *            values.
+     * @return The value for the given coordinates.
+     *
+     * @throws IllegalStateException
+     *             if this CalculatedValueCache is configured to not use the
+     *             column and row position for cache key definition.
+     */
+    public abstract Object getCalculatedValue(int columnPosition,
+            int rowPosition, boolean calculateInBackground,
+            ICalculator calculator);
+
+    /**
+     * Returns the calculated value for the specified column and row position.
+     * If there is no calculated value for that coordinates in the cache or
+     * there is a potentially stale value, the re-calculation of the value is
+     * executed.
+     * <p>
+     * This method uses the given ICalculatedValueCacheKey instead of
+     * determining the cache key out of the CalculatedValueCache key
+     * configuration.
+     *
+     * @param columnPosition
+     *            The column position of the requested value.
+     * @param rowPosition
+     *            The row position of the requested value.
+     * @param key
+     *            The key that is used by this CalculatedValueCache.
+     * @param calculateInBackground
+     *            Flag to specify whether the value calculation should be
+     *            processed in the background or not. Setting this value to
+     *            <code>false</code> will cause calculation in the UI thread,
+     *            which is usually necessary in case of exporting and printing.
+     * @param calculator
+     *            The {@link ICalculator} that is used for calculating the
+     *            values.
+     * @return The value for the given coordinates.
+     */
+    public abstract Object getCalculatedValue(int columnPosition,
+            int rowPosition, ICalculatedValueCacheKey key,
+            boolean calculateInBackground, ICalculator calculator);
+
+    /**
+     * Clear the internal cache. Doing this will result in triggering new
+     * calculations. If the values where calculated before, using the cache copy
+     * still the already calculated values will be returned until the new
+     * calculation is done.
+     */
+    public abstract void clearCache();
+
+    /**
+     * Kills all cached values. The internal cache aswell as the cache copy to
+     * support smooth updates of values. This is necessary because on structural
+     * changes, e.g. deleting/adding rows, the cache copy would return false
+     * values.
+     */
+    public abstract void killCache();
+
+    /**
+     * Cleaning up internal resources like shutting down the ExecutorService.
+     */
+    public abstract void dispose();
+
+    /**
+     * Set the layer that should be used by this CalculatedValueCache to trigger
+     * updates after the calculation processing is done. Necessary if the
+     * caching is connected to a data provider for example, which is not able to
+     * fire events itself.
+     *
+     * @param layer
+     *            The ILayer that should be used to fire the
+     *            CellVisualChangeEvent after the background calculation process
+     *            is done.
+     */
+    public abstract void setLayer(ILayer layer);
+
+}
\ No newline at end of file
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_803_CachedCalculatingGridExample.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_803_CachedCalculatingGridExample.java
index bc1f30b..a9a7cd4 100644
--- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_803_CachedCalculatingGridExample.java
+++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_803_CachedCalculatingGridExample.java
@@ -63,6 +63,7 @@
 import org.eclipse.nebula.widgets.nattable.summaryrow.SummationSummaryProvider;
 import org.eclipse.nebula.widgets.nattable.util.CalculatedValueCache;
 import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
+import org.eclipse.nebula.widgets.nattable.util.ICalculatedValueCache;
 import org.eclipse.nebula.widgets.nattable.util.ICalculator;
 import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
 import org.eclipse.swt.SWT;
@@ -288,7 +289,7 @@
     class CachedValueCalculatingDataProvider<T> extends
             GlazedListsDataProvider<T> {
 
-        private CalculatedValueCache valueCache;
+        private ICalculatedValueCache valueCache;
 
         public CachedValueCalculatingDataProvider(EventList<T> list,
                 IColumnAccessor<T> columnAccessor) {
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/groupBy/GroupByDataLayer.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/groupBy/GroupByDataLayer.java
index a15f181..a70c978 100644
--- a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/groupBy/GroupByDataLayer.java
+++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/groupBy/GroupByDataLayer.java
@@ -10,6 +10,7 @@
  *     Roman Flueckiger <roman.flueckiger@mac.com> - Bug 454566
  *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 448115, 449361, 453874
  *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 444839, 444855, 453885
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 459246
  ******************************************************************************/
 package org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy;
 
@@ -44,6 +45,7 @@
 import org.eclipse.nebula.widgets.nattable.summaryrow.command.CalculateSummaryRowValuesCommand;
 import org.eclipse.nebula.widgets.nattable.tree.TreeLayer;
 import org.eclipse.nebula.widgets.nattable.util.CalculatedValueCache;
+import org.eclipse.nebula.widgets.nattable.util.ICalculatedValueCache;
 import org.eclipse.nebula.widgets.nattable.util.ICalculatedValueCacheKey;
 import org.eclipse.nebula.widgets.nattable.util.ICalculator;
 import org.eclipse.swt.custom.BusyIndicator;
@@ -106,7 +108,7 @@
      * The value cache that contains the summary values and performs summary
      * calculation in background processes if necessary.
      */
-    private CalculatedValueCache valueCache;
+    private ICalculatedValueCache valueCache;
 
     /** Map the group to a dynamic list of group elements */
     private final Map<GroupByObject, FilterList<T>> filtersByGroup = new ConcurrentHashMap<GroupByObject, FilterList<T>>();
@@ -503,6 +505,34 @@
     }
 
     /**
+     * @return The {@link ICalculatedValueCache} that contains the summary
+     *         values and performs summary calculation in background processes
+     *         if necessary.
+     */
+    public ICalculatedValueCache getValueCache() {
+        return this.valueCache;
+    }
+
+    /**
+     * Set the {@link ICalculatedValueCache} that should be used internally to
+     * calculate the summary values in a background thread and cache the
+     * results.
+     * <p>
+     * <b><u>Note:</u></b> By default the {@link CalculatedValueCache} is used.
+     * Be sure you know what you are doing when you are trying to exchange the
+     * implementation.
+     * </p>
+     *
+     * @param valueCache
+     *            The {@link ICalculatedValueCache} that contains the summary
+     *            values and performs summary calculation in background
+     *            processes if necessary.
+     */
+    public void setValueCache(ICalculatedValueCache valueCache) {
+        this.valueCache = valueCache;
+    }
+
+    /**
      * Simple {@link ExpansionModel} that shows every node expanded initially.
      * <p>
      * It is not strictly necessary for implementors to record the