Add a get method to CacheAccess that allows a Supplier to be specified

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/jcs/trunk@1852302 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java
index 7fe0a73..71095eb 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java
@@ -23,6 +23,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import org.apache.commons.jcs.access.behavior.ICacheAccess;
@@ -80,6 +81,29 @@
     }
 
     /**
+     * Retrieve an object from the cache region this instance provides access to.
+     * If the object cannot be found in the cache, it will be retrieved by
+     * calling the supplier and subsequently storing it in the cache.
+     * <p>
+     * @param name
+     * @param supplier supplier to be called if the value is not found
+     * @return Object.
+     */
+    @Override
+    public V get(K name, Supplier<V> supplier)
+    {
+        V value = get(name);
+
+        if (value == null)
+        {
+            value = supplier.get();
+            put(name, value);
+        }
+
+        return value;
+    }
+
+    /**
      * Retrieve matching objects from the cache region this instance provides access to.
      * <p>
      * @param pattern - a key pattern for the objects stored
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/PartitionedCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/PartitionedCacheAccess.java
index e100002..a12e039 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/PartitionedCacheAccess.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/PartitionedCacheAccess.java
@@ -24,6 +24,7 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.apache.commons.jcs.JCS;
 import org.apache.commons.jcs.access.behavior.ICacheAccess;
@@ -205,6 +206,29 @@
     }
 
     /**
+     * Retrieve an object from the cache region this instance provides access to.
+     * If the object cannot be found in the cache, it will be retrieved by
+     * calling the supplier and subsequently storing it in the cache.
+     * <p>
+     * @param name
+     * @param supplier supplier to be called if the value is not found
+     * @return Object.
+     */
+    @Override
+    public V get(K name, Supplier<V> supplier)
+    {
+        V value = get(name);
+
+        if (value == null)
+        {
+            value = supplier.get();
+            put(name, value);
+        }
+
+        return value;
+    }
+
+    /**
      * Gets the ICacheElement&lt;K, V&gt; (the wrapped object) for the key from the desired partition.
      * <p>
      * @param key key
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java
index 7c0db96..f48abdd 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java
@@ -1,5 +1,9 @@
 package org.apache.commons.jcs.access.behavior;
 
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -23,9 +27,6 @@
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.behavior.IElementAttributes;
 
-import java.util.Map;
-import java.util.Set;
-
 /**
  * ICacheAccess defines the behavior for client access.
  */
@@ -38,7 +39,17 @@
      * @param name
      * @return Object or null if not found.
      */
-    V get( K name );
+    V get(K name);
+
+    /**
+     * Basic get method. If the object cannot be found in the cache, it will be
+     * retrieved by calling the supplier and subsequently storing it in the cache.
+     * <p>
+     * @param name
+     * @param supplier supplier to be called if the value is not found
+     * @return Object.
+     */
+    V get(K name, Supplier<V> supplier);
 
     /**
      * Retrieve matching objects from the cache region this instance provides access to.
@@ -46,7 +57,7 @@
      * @param pattern - a key pattern for the objects stored
      * @return A map of key to values. These are stripped from the wrapper.
      */
-    Map<K, V> getMatching( String pattern );
+    Map<K, V> getMatching(String pattern);
 
     /**
      * Puts in cache if an item does not exist with the name in that region.
@@ -55,7 +66,7 @@
      * @param obj
      * @throws CacheException
      */
-    void putSafe( K name, V obj )
+    void putSafe(K name, V obj)
         throws CacheException;
 
     /**
@@ -65,7 +76,7 @@
      * @param obj
      * @throws CacheException
      */
-    void put( K name, V obj )
+    void put(K name, V obj)
         throws CacheException;
 
     /**
@@ -76,7 +87,7 @@
      * @param attr
      * @throws CacheException
      */
-    void put( K name, V obj, IElementAttributes attr )
+    void put(K name, V obj, IElementAttributes attr)
         throws CacheException;
 
     /**
@@ -94,7 +105,7 @@
      * @param name Key the object is stored as
      * @return The ICacheElement&lt;K, V&gt; if the object is found or null
      */
-    ICacheElement<K, V> getCacheElement( K name );
+    ICacheElement<K, V> getCacheElement(K name);
 
     /**
      * Get multiple elements from the cache based on a set of cache keys.
@@ -114,7 +125,7 @@
      * @return a map of Object key to ICacheElement&lt;K, V&gt; element, or empty map if none of the keys are
      *         present
      */
-    Map<K, ICacheElement<K, V>> getCacheElements( Set<K> names );
+    Map<K, ICacheElement<K, V>> getCacheElements(Set<K> names);
 
     /**
      * Get multiple elements from the cache based on a set of cache keys.
@@ -134,7 +145,7 @@
      * @return a map of Object key to ICacheElement&lt;K, V&gt; element, or empty map if no keys match the
      *         pattern
      */
-    Map<K, ICacheElement<K, V>> getMatchingCacheElements( String pattern );
+    Map<K, ICacheElement<K, V>> getMatchingCacheElements(String pattern);
 
     /**
      * Remove an object for this key if one exists, else do nothing.
@@ -142,7 +153,7 @@
      * @param name
      * @throws CacheException
      */
-    void remove( K name )
+    void remove(K name)
         throws CacheException;
 
     /**
@@ -152,7 +163,7 @@
      * @param attributes
      * @throws CacheException
      */
-    void resetElementAttributes( K name, IElementAttributes attributes )
+    void resetElementAttributes(K name, IElementAttributes attributes)
         throws CacheException;
 
     /**
@@ -162,6 +173,6 @@
      * @return The elementAttributes value
      * @throws CacheException
      */
-    IElementAttributes getElementAttributes( K name )
+    IElementAttributes getElementAttributes(K name)
         throws CacheException;
 }
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java
index 900323e..7e5b30a 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java
@@ -167,9 +167,11 @@
         String keyOne = "mykeyone";
         String keyTwo = "mykeytwo";
         String keyThree = "mykeythree";
+        String keyFour = "mykeyfour";
         String valueOne = "myvalueone";
         String valueTwo = "myvaluetwo";
         String valueThree = "myvaluethree";
+        String valueFour = "myvaluefour";
 
         access.put( keyOne, valueOne );
         access.put( keyTwo, valueTwo );
@@ -190,6 +192,14 @@
         ICacheElement<String, String> elementTwo = result.get( keyTwo );
         assertEquals( "value two", keyTwo, elementTwo.getKey() );
         assertEquals( "value two", valueTwo, elementTwo.getVal() );
+
+        assertNull(access.get(keyFour));
+        String suppliedValue1 = access.get(keyFour, () -> valueFour);
+        assertNotNull( "value four", suppliedValue1);
+        assertEquals( "value four", valueFour, suppliedValue1);
+        String suppliedValue2 = access.get(keyFour);
+        assertNotNull( "value four", suppliedValue2);
+        assertEquals( "value four", suppliedValue1, suppliedValue2);
     }
 
     /**
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 4376e99..898be86 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -20,6 +20,9 @@
 	</properties>
 	<body>
         <release version="3.0" date="unreleased">
+            <action dev="tv" type="add">
+                Add a get method to CacheAccess that allows a Supplier to be specified
+            </action>
             <action dev="tv" type="remove">
                 Remove dependency on velocity-tools
             </action>
diff --git a/xdocs/UsingJCSBasicWeb.xml b/xdocs/UsingJCSBasicWeb.xml
index b54f6d8..7e139e3 100644
--- a/xdocs/UsingJCSBasicWeb.xml
+++ b/xdocs/UsingJCSBasicWeb.xml
@@ -214,18 +214,14 @@
     {
         BookVObj vObj = null;
 
-        // First, if requested, attempt to load from cache
-
+        // If requested, attempt to load from cache
         if (fromCache)
         {
-            vObj = bookCache.get("BookVObj" + id);
+            vObj = bookCache.get("BookVObj" + id, () -> loadvObj(id));
         }
-
-        // Either fromCache was false or the object was not found, so
-        // call loadBookVObj to create it
-
-        if (vObj == null)
+        else
         {
+            // otherwise, load directly
             vObj = loadvObj(id);
         }