cache

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/Cache.java b/src/main/java/br/ufrgs/inf/prosoft/cache/Cache.java
index 3b2a650..94c7fea 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/Cache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/Cache.java
@@ -5,18 +5,41 @@
  */
 package br.ufrgs.inf.prosoft.cache;
 
+import java.util.function.Function;
+
 /**
  *
  * @author romulo
+ * @param <K>
+ * @param <V>
  */
-public interface Cache {
+public interface Cache<K, V> {
+
+    public V put(K key, V value, long timeToLive);
 
-    public Object put(Object key, Object value, long timeToLive);
+    public V put(K key, V value);
 
-    public Object put(Object key, Object value);
+    public V get(K key);
 
-    public Object get(Object key);
+    public void invalidate(K key);
 
-    public void invalidate(Object key);
+    public default V computeIfAbsent(K key, Function<K, V> function, long timeToLive) {
+        V get = get(key);
+        if (get != null) {
+            return get;
+        }
+        V apply = function.apply(key);
+        put(key, apply, timeToLive);
+        return apply;
+    }
 
+    public default V computeIfAbsent(K key, Function<K, V> function) {
+        V get = get(key);
+        if (get != null) {
+            return get;
+        }
+        V apply = function.apply(key);
+        put(key, apply);
+        return apply;
+    }
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/CachingPerformance.java b/src/main/java/br/ufrgs/inf/prosoft/cache/CachingPerformance.java
index 7e9b4f4..cfffd66 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/CachingPerformance.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/CachingPerformance.java
@@ -5,6 +5,9 @@
  */
 package br.ufrgs.inf.prosoft.cache;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -16,6 +19,7 @@ public class CachingPerformance {
 
     private int misses;
     private int hits;
+    private int bytesHits;
     private int invalidations;
     private int maximumSize;
     private String name;
@@ -49,6 +53,10 @@ public class CachingPerformance {
         this.hits++;
     }
 
+    public void registerBytesHit(int size) {
+        this.bytesHits += size;
+    }
+
     public void registerMiss() {
         this.misses++;
     }
@@ -73,10 +81,26 @@ public class CachingPerformance {
         return this.hits * 100.0 / (this.hits + this.misses);
     }
 
+    public double getByteHitRatio() {
+        return 100.0 * (this.bytesHits / (this.bytesHits + (this.bytesHits / this.hits) * this.misses));
+    }
+
     public String needInvalidation() {
         return this.invalidations > 0 ? "yes" : "no";
     }
 
+    public static int calculateObjectSize(Object object) {
+        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+                ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream)) {
+            objectOutputStream.writeObject(object);
+            byte[] toByteArray = outputStream.toByteArray();
+            return toByteArray.length;
+        } catch (IOException ex) {
+            System.err.println("[Cache] size exception: " + ex);
+        }
+        return 0;
+    }
+
     @Override
     public String toString() {
         StringBuilder stringBuilder = new StringBuilder();
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/GetterCache.java b/src/main/java/br/ufrgs/inf/prosoft/cache/GetterCache.java
index 380ca1c..c9936b5 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/GetterCache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/GetterCache.java
@@ -11,11 +11,12 @@ import java.util.logging.Logger;
 /**
  *
  * @author romulo
+ * @param <V>
  */
-public class GetterCache {
+public class GetterCache<V> {
 
     private final CachingPerformance cachingPerformance;
-    private Object result;
+    private V result;
     private boolean isFilled;
 
     public GetterCache() {
@@ -33,8 +34,8 @@ public class GetterCache {
         this.cachingPerformance = cachingPerformance;
     }
 
-    public Object put(Object value, long timeToLive) {
-        Object put = put(value);
+    public V put(V value, long timeToLive) {
+        V put = put(value);
         Thread thread = new Thread(() -> {
             try {
                 Thread.sleep(timeToLive);
@@ -48,18 +49,19 @@ public class GetterCache {
         return put;
     }
 
-    public Object put(Object value) {
+    public V put(V value) {
         this.result = value;
         this.isFilled = true;
         this.cachingPerformance.registerSize(1);
         return this.result;
     }
 
-    public Object get() {
+    public V get() {
         if (this.isFilled == false) {
             this.cachingPerformance.registerMiss();
             return null;
         }
+        this.cachingPerformance.registerBytesHit(CachingPerformance.calculateObjectSize(this.result));
         this.cachingPerformance.registerHit();
         return this.result;
     }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/MultiCache.java b/src/main/java/br/ufrgs/inf/prosoft/cache/MultiCache.java
index a4476f2..43d3cab 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/MultiCache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/MultiCache.java
@@ -12,21 +12,27 @@ import java.util.logging.Logger;
 /**
  *
  * @author romulo
+ * @param <K>
+ * @param <V>
  */
-public class MultiCache extends HashMap<Object, Object> implements Cache {
+public class MultiCache<K, V> implements Cache<K, V> {
 
+    private final HashMap<K, V> map;
     private final CachingPerformance cachingPerformance;
 
     public MultiCache() {
         this.cachingPerformance = new CachingPerformance();
+        this.map = new HashMap<>();
     }
-    
+
     public MultiCache(String name) {
         this.cachingPerformance = new CachingPerformance(name);
+        this.map = new HashMap<>();
     }
 
     public MultiCache(CachingPerformance cachingPerformance) {
         this.cachingPerformance = cachingPerformance;
+        this.map = new HashMap<>();
     }
 
     public CachingPerformance getCachingPerformance() {
@@ -34,43 +40,44 @@ public class MultiCache extends HashMap<Object, Object> implements Cache {
     }
 
     @Override
-    public Object put(Object key, Object value, long timeToLive) {
-        Object put = put(key, value);
+    public V put(K key, V value, long timeToLive) {
+        V put = put(key, value);
         Thread thread = new Thread(() -> {
             try {
                 Thread.sleep(timeToLive);
             } catch (InterruptedException ex) {
                 Logger.getLogger(MultiCache.class.getName()).log(Level.SEVERE, "interrupted time to live");
             }
-            MultiCache.super.remove(key);
+            this.map.remove(key);
         });
         thread.start();
         return put;
     }
 
     @Override
-    public Object put(Object key, Object value) {
-        Object oldReference = super.put(key, value);
+    public V put(K key, V value) {
+        V oldReference = this.map.put(key, value);
         if (oldReference == null) {
-            this.cachingPerformance.registerSize(size());
+            this.cachingPerformance.registerSize(this.map.size());
         }
         return oldReference;
     }
 
     @Override
-    public Object get(Object key) {
-        Object get = super.get(key);
+    public V get(K key) {
+        V get = this.map.get(key);
         if (get == null) {
             this.cachingPerformance.registerMiss();
         } else {
             this.cachingPerformance.registerHit();
+            this.cachingPerformance.registerBytesHit(CachingPerformance.calculateObjectSize(get));
         }
         return get;
     }
 
     @Override
-    public void invalidate(Object key) {
-        Object remove = this.remove(key);
+    public void invalidate(K key) {
+        V remove = this.map.remove(key);
         if (remove != null) {
             this.cachingPerformance.registerInvalidation();
         }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/SingleCache.java b/src/main/java/br/ufrgs/inf/prosoft/cache/SingleCache.java
index 9427f1c..37c32d9 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/SingleCache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/SingleCache.java
@@ -11,17 +11,19 @@ import java.util.logging.Logger;
 /**
  *
  * @author romulo
+ * @param <K>
+ * @param <V>
  */
-public class SingleCache implements Cache {
+public class SingleCache<K, V> implements Cache<K, V> {
 
     private final CachingPerformance cachingPerformance;
-    private Object lastInput;
-    private Object result;
+    private K lastInput;
+    private V result;
 
     public SingleCache() {
         this.cachingPerformance = new CachingPerformance();
     }
-    
+
     public SingleCache(String name) {
         this.cachingPerformance = new CachingPerformance(name);
     }
@@ -35,8 +37,8 @@ public class SingleCache implements Cache {
     }
 
     @Override
-    public Object put(Object key, Object value, long timeToLive) {
-        Object put = put(key, value);
+    public V put(K key, V value, long timeToLive) {
+        V put = put(key, value);
         Thread thread = new Thread(() -> {
             try {
                 Thread.sleep(timeToLive);
@@ -51,7 +53,7 @@ public class SingleCache implements Cache {
     }
 
     @Override
-    public Object put(Object key, Object value) {
+    public V put(K key, V value) {
         this.lastInput = key;
         this.result = value;
         this.cachingPerformance.registerSize(1);
@@ -59,9 +61,10 @@ public class SingleCache implements Cache {
     }
 
     @Override
-    public Object get(Object key) {
+    public V get(K key) {
         if (key.equals(this.lastInput)) {
             this.cachingPerformance.registerHit();
+            this.cachingPerformance.registerBytesHit(CachingPerformance.calculateObjectSize(this.result));
             return this.result;
         }
         this.cachingPerformance.registerMiss();
@@ -69,7 +72,7 @@ public class SingleCache implements Cache {
     }
 
     @Override
-    public void invalidate(Object key) {
+    public void invalidate(K key) {
         this.lastInput = null;
         this.result = null;
         this.cachingPerformance.registerInvalidation();