package org.openmole.commons.aspect.caching;

import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SoftMethodCache {
    
    final static Logger LOGGER = Logger.getLogger(SoftMethodCache.class.getName());
    
    class ObjectContainer {
        
        final String key;
        final Object obj;

        ObjectContainer(String key, Object obj) {
            this.key = key;
            this.obj = obj;
        }

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            LOGGER.log(Level.FINE, "Remove cache for {0}", key);
            clear(key);
        }
    }
    final Map<Object, Map<String, SoftReference<ObjectContainer>>> cache = new WeakHashMap<Object, Map<String, SoftReference<ObjectContainer>>>();

    void putCachedMethodResult(Object object, String method, Object result) {
        LOGGER.log(Level.FINE, "Softcache size {0}", size());
        
        final Map<String, SoftReference<ObjectContainer>> methodMap = getMethodMap(object);
        methodMap.put(method, new SoftReference<ObjectContainer>(new ObjectContainer(method, result)));
    }

    Object getCachedMethodResult(Object object, String method) {
        Map<String, SoftReference<ObjectContainer>> methodMap = cache.get(object);
        if (methodMap == null) {
            return null;

            
        }
        SoftReference<ObjectContainer> ref = methodMap.get(method);
        if (ref == null) {
            return null;
        } else {
            ObjectContainer objectContainer = ref.get();
            if (objectContainer == null) {
                return null;
                
            } else {
                return objectContainer.obj;
                
            }
        }
    }

    private Map<String, SoftReference<ObjectContainer>> getMethodMap(Object object) {
        Map<String, SoftReference<ObjectContainer>> methodMap = cache.get(object);
        if (methodMap != null) {
            return methodMap;
        }

        synchronized (cache) {
            methodMap = cache.get(object);
            if (methodMap == null) {
                methodMap = Collections.synchronizedMap(new TreeMap<String, SoftReference<ObjectContainer>>());
                cache.put(object, methodMap);
            }
            return methodMap;
        }
    }
    
    void clear(String key) {
        synchronized (cache) {
            cache.remove(key);            
        }
    }
    
    public int size() {
        return cache.size();
    }
}

@@ -60,20 +60,16 @@
 ang.ref.
-Soft
 Referenc
@@ -69,16 +69,21 @@
 eference
+Queue
 ;%0Aimport
@@ -132,34 +132,8 @@
 ap;%0A
-import java.util.TreeMap;%0A
 impo
@@ -154,24 +154,63 @@
 eakHashMap;%0A
+import java.util.concurrent.Executors;%0A
 import java.
@@ -261,16 +261,74 @@
 .Logger;
+%0Aimport org.apache.commons.collections15.map.ReferenceMap;
 %0A%0Apublic
@@ -352,20 +352,16 @@
 Cache %7B%0A
-    
 %0A    fin
@@ -445,141 +445,97 @@
     
-%0A    class ObjectContainer %7B%0A        %0A        final String key;%0A        final Object obj;%0A%0A        ObjectContainer(
+final Map%3CObject, Map%3CString, Object%3E%3E cache = new WeakHashMap%3CObject, Map%3C
 String
- key
 , Object
  obj
@@ -534,435 +534,264 @@
 ject
- obj) %7B%0A            this.key = key;%0A            this.obj = obj;%0A        %7D%0A%0A        @Override%0A        protected void finalize() throws Throwable %7B%0A            super.finalize();%0A            LOGGER.log(Level.FINE, %22Remove cache for %7B0%7D%22, key);%0A            clear(key);%0A        %7D%0A    %7D%0A    final Map%3CObject, Map%3CString, SoftReference%3CObjectContainer%3E%3E%3E cache = new WeakHashMap%3CObject, Map%3CString, SoftReference%3CObjectContainer%3E%3E%3E();
+%3E%3E();%0A    final ReferenceQueue referenceQueue = new ReferenceQueue();%0A%0A    public SoftMethodCache() %7B%0A        Executors.newSingleThreadExecutor().submit(new Runnable() %7B%0A%0A            @Override%0A            public void run() %7B%0A            %7D%0A        %7D);%0A    %7D
 %0A%0A  
@@ -928,24 +928,16 @@
 ize());%0A
-        
 %0A       
@@ -959,38 +959,14 @@
 ng, 
-SoftReference%3CObjectContainer%3E
+Object
 %3E me
@@ -1030,79 +1030,16 @@
 hod,
- new SoftReference%3CObjectContainer%3E(new ObjectContainer(method,
  result)
 ));%0A
@@ -1034,18 +1034,16 @@
  result)
-))
 ;%0A    %7D%0A
@@ -1132,38 +1132,14 @@
 ng, 
-SoftReference%3CObjectContainer%3E
+Object
 %3E me
@@ -1225,29 +1225,24 @@
 n null;%0A
-%0A    
         
 %0A       
@@ -1237,469 +1237,86 @@
     
-%0A        %7D%0A        SoftReference%3CObjectContainer%3E ref = methodMap.get(method);%0A        if (ref == null) %7B%0A            return null;%0A        %7D else %7B%0A            ObjectContainer objectContainer = ref.get();%0A            if (objectContainer == null) %7B%0A                return null;%0A                %0A            %7D else %7B%0A                return objectContainer.obj;%0A                %0A            %7D%0A        %7D%0A    %7D%0A%0A    private Map%3CString, SoftReference%3CObjectContainer%3E
+%7D%0A%0A        return methodMap.get(method);%0A    %7D%0A%0A    private Map%3CString, Object
 %3E ge
@@ -1367,38 +1367,14 @@
 ng, 
-SoftReference%3CObjectContainer%3E
+Object
 %3E me
@@ -1651,11 +1651,16 @@
 new 
-Tre
+Referenc
 eMap
@@ -1668,20 +1668,24 @@
 String, 
-Soft
+Object%3E(
 Referenc
@@ -1689,27 +1689,35 @@
 ence
-%3CObjectContainer%3E%3E(
+Map.HARD, ReferenceMap.SOFT
 ));%0A
@@ -1826,136 +1826,8 @@
   %7D%0A
-    %0A    void clear(String key) %7B%0A        synchronized (cache) %7B%0A            cache.remove(key);            %0A        %7D%0A    %7D%0A    
 %0A   

Fix memory leak.