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();
    }
}

package org.openmole.commons.aspect.caching;

import java.lang.ref.ReferenceQueue;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.collections15.map.ReferenceMap;

public class SoftMethodCache {

    final static Logger LOGGER = Logger.getLogger(SoftMethodCache.class.getName());
    final Map<Object, Map<String, Object>> cache = new WeakHashMap<Object, Map<String, Object>>();
    final ReferenceQueue referenceQueue = new ReferenceQueue();

    public SoftMethodCache() {
        Executors.newSingleThreadExecutor().submit(new Runnable() {

            @Override
            public void run() {
            }
        });
    }

    void putCachedMethodResult(Object object, String method, Object result) {
        LOGGER.log(Level.FINE, "Softcache size {0}", size());

        final Map<String, Object> methodMap = getMethodMap(object);
        methodMap.put(method, result);
    }

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

        return methodMap.get(method);
    }

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

        synchronized (cache) {
            methodMap = cache.get(object);
            if (methodMap == null) {
                methodMap = Collections.synchronizedMap(new ReferenceMap<String, Object>(ReferenceMap.HARD, ReferenceMap.SOFT));
                cache.put(object, methodMap);
            }
            return methodMap;
        }
    }

    public int size() {
        return cache.size();
    }
}

Fix memory leak.