/* * Copyright (c) 2005-2016 Substance Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Substance Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.substance.internal.utils; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.swing.SwingUtilities; /** * Lazily initialized hash map for caching images. Note that this class is * <b>not</b> thread safe. In Substance, it is used only from EDT. * * @author Kirill Grouchnikov * @param <T> * Class for the stored values. */ public class LazyResettableHashMap<T> { /** * List of all existing maps. */ private static List<LazyResettableHashMap<?>> all; /** * The delegate cache. */ private Map<HashMapKey, T> cache; /** * Display name of this hash map. Is used for tracking the statistics. */ private String displayName; /** * Creates a new hash map. * * @param displayName * Display name of the new hash map. */ public LazyResettableHashMap(String displayName) { this.displayName = displayName; if (all == null) { all = new LinkedList<LazyResettableHashMap<?>>(); } all.add(this); } /** * Creates the delegate cache if necessary. */ private void createIfNecessary() { if (this.cache == null) this.cache = new SoftHashMap<HashMapKey, T>(); } /** * Puts a new key-value pair in the map. * * @param key * Pair key. * @param entry * Pair value. */ public void put(HashMapKey key, T entry) { if (!SwingUtilities.isEventDispatchThread()) throw new IllegalArgumentException( "Called outside Event Dispatch Thread"); this.createIfNecessary(); this.cache.put(key, entry); } /** * Returns the value registered for the specified key. * * @param key * Key. * @return Registered value or <code>null</code> if none. */ public T get(HashMapKey key) { if (this.cache == null) return null; return this.cache.get(key); } /** * Checks whether there is a value associated with the specified key. * * @param key * Key. * @return <code>true</code> if there is an associated value, * <code>false</code> otherwise. */ public boolean containsKey(HashMapKey key) { if (this.cache == null) return false; return this.cache.containsKey(key); } /** * Returns the number of key-value pairs of this hash map. * * @return The number of key-value pairs of this hash map. */ public int size() { if (this.cache == null) return 0; return this.cache.size(); } /** * Resets all existing hash maps. */ public static void reset() { if (all != null) { for (LazyResettableHashMap<?> map : all) { if (map.cache != null) map.cache.clear(); } } } /** * Returns statistical information of the existing hash maps. * * @return Statistical information of the existing hash maps. */ public static List<String> getStats() { if (all != null) { List<String> result = new LinkedList<String>(); Map<String, Integer> mapCounter = new TreeMap<String, Integer>(); Map<String, Integer> entryCounter = new TreeMap<String, Integer>(); for (LazyResettableHashMap<?> map : all) { String key = map.displayName; if (!mapCounter.containsKey(key)) { mapCounter.put(key, 0); entryCounter.put(key, 0); } mapCounter.put(key, mapCounter.get(key) + 1); entryCounter.put(key, entryCounter.get(key) + map.size()); } for (Map.Entry<String, Integer> entry : mapCounter.entrySet()) { String key = entry.getKey(); result.add(entry.getValue() + " " + key + " with " + entryCounter.get(key) + " entries total"); } return result; } return null; } }