~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to substance/src/main/java/org/pushingpixels/substance/internal/utils/LazyResettableHashMap.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions are met:
 
6
 *
 
7
 *  o Redistributions of source code must retain the above copyright notice,
 
8
 *    this list of conditions and the following disclaimer.
 
9
 *
 
10
 *  o Redistributions in binary form must reproduce the above copyright notice,
 
11
 *    this list of conditions and the following disclaimer in the documentation
 
12
 *    and/or other materials provided with the distribution.
 
13
 *
 
14
 *  o Neither the name of Substance Kirill Grouchnikov nor the names of
 
15
 *    its contributors may be used to endorse or promote products derived
 
16
 *    from this software without specific prior written permission.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
19
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
20
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
21
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
22
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
23
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
24
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
25
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
26
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 
27
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 
28
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 */
 
30
package org.pushingpixels.substance.internal.utils;
 
31
 
 
32
import net.jcip.annotations.GuardedBy;
 
33
 
 
34
import java.util.LinkedList;
 
35
import java.util.List;
 
36
import java.util.Map;
 
37
import java.util.TreeMap;
 
38
 
 
39
/**
 
40
 * Lazily initialized hash map for caching images. Note that this class is
 
41
 * <b>not</b> thread safe. In Substance, it is used only from EDT.
 
42
 * 
 
43
 * @author Kirill Grouchnikov
 
44
 * @param <T>
 
45
 *            Class for the stored values.
 
46
 */
 
47
public class LazyResettableHashMap<T> {
 
48
 
 
49
    private static final Object staticLock = new Object();
 
50
    private final Object instanceLock = new Object();
 
51
 
 
52
        /**
 
53
         * List of all existing maps.
 
54
         */
 
55
    @GuardedBy("staticLock")
 
56
        private static List<LazyResettableHashMap<?>> all;
 
57
 
 
58
        /**
 
59
         * The delegate cache.
 
60
         */
 
61
    @GuardedBy("instanceLock")
 
62
        private Map<HashMapKey, T> cache;
 
63
 
 
64
        /**
 
65
         * Display name of this hash map. Is used for tracking the statistics.
 
66
         */
 
67
        private String displayName;
 
68
 
 
69
        /**
 
70
         * Creates a new hash map.
 
71
         * 
 
72
         * @param displayName
 
73
         *            Display name of the new hash map.
 
74
         */
 
75
        public LazyResettableHashMap(String displayName) {
 
76
                this.displayName = displayName;
 
77
        synchronized (staticLock) {
 
78
            if (all == null) {
 
79
                all = new LinkedList<LazyResettableHashMap<?>>();
 
80
            }
 
81
            all.add(this);
 
82
        }
 
83
        }
 
84
 
 
85
        /**
 
86
         * Creates the delegate cache if necessary.
 
87
         */
 
88
        private void createIfNecessary() {
 
89
        synchronized (instanceLock) {
 
90
            if (this.cache == null)
 
91
                this.cache = new SoftHashMap<HashMapKey, T>();
 
92
        }
 
93
        }
 
94
 
 
95
        /**
 
96
         * Puts a new key-value pair in the map.
 
97
         * 
 
98
         * @param key
 
99
         *            Pair key.
 
100
         * @param entry
 
101
         *            Pair value.
 
102
         */
 
103
        public void put(HashMapKey key, T entry) {
 
104
        synchronized (instanceLock) {
 
105
            this.createIfNecessary();
 
106
                this.cache.put(key, entry);
 
107
        }
 
108
        }
 
109
 
 
110
        /**
 
111
         * Returns the value registered for the specified key.
 
112
         * 
 
113
         * @param key
 
114
         *            Key.
 
115
         * @return Registered value or <code>null</code> if none.
 
116
         */
 
117
        public T get(HashMapKey key) {
 
118
        synchronized (instanceLock) {
 
119
            if (this.cache == null)
 
120
                return null;
 
121
            return this.cache.get(key);
 
122
        }
 
123
        }
 
124
 
 
125
        /**
 
126
         * Checks whether there is a value associated with the specified key.
 
127
         * 
 
128
         * @param key
 
129
         *            Key.
 
130
         * @return <code>true</code> if there is an associated value,
 
131
         *         <code>false</code> otherwise.
 
132
         */
 
133
        public boolean containsKey(HashMapKey key) {
 
134
        synchronized (instanceLock) {
 
135
            if (this.cache == null)
 
136
                return false;
 
137
            return this.cache.containsKey(key);
 
138
        }
 
139
        }
 
140
 
 
141
        /**
 
142
         * Returns the number of key-value pairs of this hash map.
 
143
         * 
 
144
         * @return The number of key-value pairs of this hash map.
 
145
         */
 
146
        public int size() {
 
147
        synchronized (instanceLock) {
 
148
            if (this.cache == null)
 
149
                return 0;
 
150
            return this.cache.size();
 
151
        }
 
152
        }
 
153
 
 
154
        /**
 
155
         * Resets all existing hash maps.
 
156
         */
 
157
        public static void reset() {
 
158
        synchronized (staticLock) {
 
159
            if (all != null) {
 
160
                for (LazyResettableHashMap<?> map : all) {
 
161
                    // this is too locked!
 
162
                    synchronized(map.instanceLock) {
 
163
                        //noinspection FieldAccessNotGuarded
 
164
                        if (map.cache != null)
 
165
                            //noinspection FieldAccessNotGuarded
 
166
                            map.cache.clear();
 
167
                    }
 
168
                }
 
169
            }
 
170
        }
 
171
        }
 
172
 
 
173
        /**
 
174
         * Returns statistical information of the existing hash maps.
 
175
         * 
 
176
         * @return Statistical information of the existing hash maps.
 
177
         */
 
178
        public static List<String> getStats() {
 
179
        synchronized (staticLock) {
 
180
            if (all != null) {
 
181
                List<String> result = new LinkedList<String>();
 
182
 
 
183
                Map<String, Integer> mapCounter = new TreeMap<String, Integer>();
 
184
                Map<String, Integer> entryCounter = new TreeMap<String, Integer>();
 
185
 
 
186
                for (LazyResettableHashMap<?> map : all) {
 
187
                    String key = map.displayName;
 
188
                    if (!mapCounter.containsKey(key)) {
 
189
                        mapCounter.put(key, 0);
 
190
                        entryCounter.put(key, 0);
 
191
                    }
 
192
                    mapCounter.put(key, mapCounter.get(key) + 1);
 
193
                    entryCounter.put(key, entryCounter.get(key) + map.size());
 
194
                }
 
195
 
 
196
                for (Map.Entry<String, Integer> entry : mapCounter.entrySet()) {
 
197
                    String key = entry.getKey();
 
198
                    result.add(entry.getValue() + " " + key + " with "
 
199
                            + entryCounter.get(key) + " entries total");
 
200
                }
 
201
 
 
202
                return result;
 
203
            }
 
204
                return null;
 
205
        }
 
206
        }
 
207
}