All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.util.LRUMapMultiKey Maven / Gradle / Ivy

There is a newer version: 3.1
Show newest version
/*
 * #%L
 * Nuiton Utils
 * %%
 * Copyright (C) 2004 - 2010 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;


/** Created: 23 mai 2006 04:08:03
 * @author Benjamin Poussin - [email protected] */

public class LRUMapMultiKey extends LinkedHashMap {

    private static final long serialVersionUID = 1L;

    private static final Log log = LogFactory.getLog(LRUMapMultiKey.class);

    /** @author Benjamin Poussin - [email protected] */
    public static class Key extends ArrayList {

        private static final long serialVersionUID = 1L;

        //        protected LRUMapMultiKey map = null;
        //        protected Reference ref = null;
        protected int hash = 0;

        public Key(Object... k) {
            Collections.addAll(this, k);
        }

        @Override
        public int hashCode() {
            if (hash == 0) {
                hash = super.hashCode();
            }
            return hash;
        }

//        /* (non-Javadoc)
//         * @see java.util.AbstractList#equals(java.lang.Object)
//         */
//        @Override
//        public boolean equals(Object o) {
//            if (o != null && o instanceof Reference) {
//                Object ref = ((Reference)o).get(); 
//                if (ref == null) {
//                    boolean result = o.hashCode() == hashCode();
//                    return result;
//                }
//            }
//            return super.equals(o);
//        }

//        /* (non-Javadoc)
//         * @see java.lang.Object#finalize()
//         */
//        @Override
//        protected void finalize() throws Throwable {
//            if (map != null) {
//                for (Iterator i=iterator(); i.hasNext();) {
//                    Object k = i.next();
//                    Set> list = map.keys.get(k);
//                    if (list != null) {
//                        Object o = ref;
//                        if (o == null) {
//                            o = this;
//                        }
//                        boolean ok = list.remove(o);
//                        if (list.size() == 0) {
//                            map.keys.remove(k);
//                        }
//                    }
//                }
//            }
//        }

    }


    protected Map> keys = new HashMap>();

    protected int maxSize;

    public LRUMapMultiKey(int maxSize) {
        super(maxSize <= 0 ? 1000 : maxSize * 100 / 75, (float) 0.75, true);
        this.maxSize = maxSize;
    }

    public Key createKey(Object... k) {
        return new Key(k);
    }

    /* (non-Javadoc)
    * @see java.util.WeakHashMap#clear()
    */
    @Override
    public void clear() {
        keys.clear();
        super.clear();
    }

    /* (non-Javadoc)
    * @see java.util.WeakHashMap#remove(java.lang.Object)
    */
    @Override
    public Object remove(Object k) {
        if (k instanceof Key) {
            return super.remove(k);
        } else {
            ArrayList result = new ArrayList();
            Set list = keys.remove(k);
            if (list != null) {
                for (Iterator i = list.iterator(); i.hasNext(); ) {
                    Key key = i.next();
                    result.add(key);
                    super.remove(key);
                }
                list.clear(); // not necessary but perhaps help the garbage
            }
            return result;
        }
    }

    /* (non-Javadoc)
    * @see java.util.WeakHashMap#put(java.lang.Object, java.lang.Object)
    */
    @Override
    public Object put(Key key, Object value) {
//        if (!(akey instanceof Key)) {
//            throw new IllegalArgumentException("key must be Key object");
//        }
//        Key key = (Key)akey;
        for (Iterator i = key.iterator(); i.hasNext(); ) {
            Object k = i.next();
            Set list = keys.get(k);
            if (list == null) {
                list = new HashSet();
                keys.put(k, list);
            }
            list.add(key);
//System.out.println("+++++++++++++++++++ put key: " + key + " list("+k+") == " + list.size());
        }
//System.out.println("++++++++++++++++++++++++++++ LRU size = " + size() + " maxSize: " + maxSize);        
        Object result = super.put(key, value);
//System.out.println("+++++++++++++++++ LRU size = " + size());        
        return result;
    }

    /* (non-Javadoc)
     * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        if (this.maxSize > 0 && size() > this.maxSize) {
            Key key = eldest.getKey();
            for (Iterator i = key.iterator(); i.hasNext(); ) {
                Object k = i.next();
                Set list = keys.get(k);
                if (list != null) {
                    list.remove(key);
                    if (list.size() == 0) {
                        keys.remove(k);
                    }
                }
            }

            if (!containsKey(eldest.getKey())) {
                log.warn("possible memory leak !!! removeEldestEntry (" + eldest.getKey().getClass() + ")" + eldest.getKey() + " size " + size() + " maxSize" + maxSize);
            }
            return true;
        }
        return false;
    }

//    /* (non-Javadoc)
//     * @see org.apache.commons.collections.map.LRUMap#removeLRU(org.apache.commons.collections.map.AbstractLinkedMap.LinkEntry)
//     */
//    @Override
//    protected boolean removeLRU(AbstractLinkedMap.LinkEntry entry) {
//        Key key = (Key)entry.getKey();
//        for (Iterator i=key.iterator(); i.hasNext();) {
//            Object k = i.next();
//            Set list = keys.get(k);
//            if (list != null) {
//                boolean ok = list.remove(key);
//                if (list.size() == 0) {
//                    keys.remove(k);
//                }
//            }
//        }
//        return true;
//    }

}