EMMA Coverage Report (generated Tue Apr 17 08:51:20 BST 2007)
[all classes][org.jtoolkit.essence.data.impl]

COVERAGE SUMMARY FOR SOURCE FILE [MemoryBackingStore.java]

nameclass, %method, %block, %line, %
MemoryBackingStore.java100% (5/5)78%  (35/45)55%  (875/1591)61%  (190.7/315)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class MemoryBackingStore$1100% (1/1)50%  (1/2)8%   (3/36)8%   (1/12)
compare (MetaData, MetaData): int 0%   (0/1)0%   (0/33)0%   (0/11)
MemoryBackingStore$1 (): void 100% (1/1)100% (3/3)100% (1/1)
     
class MemoryBackingStore$3100% (1/1)50%  (1/2)11%  (3/28)12%  (1/8)
compare (MetaData, MetaData): int 0%   (0/1)0%   (0/25)0%   (0/7)
MemoryBackingStore$3 (): void 100% (1/1)100% (3/3)100% (1/1)
     
class MemoryBackingStore$2100% (1/1)50%  (1/2)12%  (3/26)12%  (1/8)
compare (MetaData, MetaData): int 0%   (0/1)0%   (0/23)0%   (0/7)
MemoryBackingStore$2 (): void 100% (1/1)100% (3/3)100% (1/1)
     
class MemoryBackingStore100% (1/1)82%  (31/38)57%  (837/1468)65%  (187.8/287)
access$000 (): Comparator 0%   (0/1)0%   (0/2)0%   (0/1)
access$100 (): Comparator 0%   (0/1)0%   (0/2)0%   (0/1)
deriveKey (Object): Object 0%   (0/1)0%   (0/40)0%   (0/7)
getEntrySet (): Set 0%   (0/1)0%   (0/20)0%   (0/4)
getName (): String 0%   (0/1)0%   (0/3)0%   (0/1)
selectMatching (Predicate): Map 0%   (0/1)0%   (0/48)0%   (0/8)
start (): void 0%   (0/1)0%   (0/9)0%   (0/2)
evict (): Set 100% (1/1)6%   (16/259)12%  (5/42)
performChanges (Collection): Collection 100% (1/1)22%  (27/122)25%  (7.1/29)
checkReadOnly (): void 100% (1/1)24%  (4/17)59%  (1.2/2)
getAllData (): Collection 100% (1/1)46%  (27/59)84%  (7.5/9)
firstKey (): Object 100% (1/1)55%  (21/38)71%  (3.6/5)
evictCandidate (): double 100% (1/1)65%  (15/23)85%  (2.6/3)
getSize (): int 100% (1/1)74%  (14/19)93%  (3.7/4)
containsKey (Object): boolean 100% (1/1)75%  (15/20)94%  (3.8/4)
getKeySet (): Set 100% (1/1)75%  (15/20)94%  (3.8/4)
getValues (): Collection 100% (1/1)75%  (15/20)94%  (3.8/4)
MemoryBackingStore (String, ClusterComponentBuilder$ClusterCollectionData): void 100% (1/1)75%  (117/155)77%  (26.8/35)
getMetaData (Object): MetaData 100% (1/1)79%  (27/34)92%  (5.5/6)
getAll (Collection): Map 100% (1/1)87%  (34/39)93%  (6.5/7)
getSnapshot (Object []): MetaData [] 100% (1/1)87%  (34/39)93%  (6.5/7)
getRetiredKeys (Collection): Collection 100% (1/1)88%  (35/40)94%  (7.5/8)
getValue (Object): Object 100% (1/1)88%  (35/40)98%  (11.8/12)
expireMetaData (long): int 100% (1/1)92%  (81/88)98%  (17.6/18)
canWrite (): boolean 100% (1/1)93%  (13/14)92%  (0.9/1)
performChanges (String, long, Map): Collection 100% (1/1)96%  (137/142)99%  (27.6/28)
nextTouchTime (): long 100% (1/1)97%  (28/29)88%  (7/8)
<static initializer> 100% (1/1)100% (16/16)100% (4/4)
checkClass (String, DataValueClass, Object): void 100% (1/1)100% (58/58)100% (6/6)
checkKey (Object): void 100% (1/1)100% (24/24)100% (6/6)
checkValue (Object): void 100% (1/1)100% (6/6)100% (2/2)
close (): void 100% (1/1)100% (4/4)100% (2/2)
finalize (): void 100% (1/1)100% (8/8)100% (3/3)
getListenerSet (): Event$ListenerSet 100% (1/1)100% (3/3)100% (1/1)
getLock (): ReadWriteLock 100% (1/1)100% (3/3)100% (1/1)
isClosed (): boolean 100% (1/1)100% (3/3)100% (1/1)
persistChanges (Collection): void 100% (1/1)100% (1/1)100% (1/1)
stop (): void 100% (1/1)100% (1/1)100% (1/1)
     
class MemoryBackingStore$4100% (1/1)100% (1/1)88%  (29/33)87%  (0.9/1)
<static initializer> 100% (1/1)88%  (29/33)87%  (0.9/1)

1package org.jtoolkit.essence.data.impl;
2 
3import org.apache.commons.logging.Log;
4import org.apache.commons.logging.LogFactory;
5import org.jetbrains.annotations.NotNull;
6import org.jetbrains.annotations.Nullable;
7import org.jtoolkit.essence.app.pojo.impl.DataValueClass;
8import org.jtoolkit.essence.app.pojo.impl.PojoContext;
9import org.jtoolkit.essence.concurrency.Concurrency;
10import org.jtoolkit.essence.concurrency.ThreadSafe;
11import org.jtoolkit.essence.data.*;
12import static org.jtoolkit.essence.data.impl.MetaData.isBefore;
13import org.jtoolkit.essence.utils.ImmutableUtils;
14import org.jtoolkit.essence.utils.RWLock;
15 
16import java.util.*;
17import java.util.concurrent.atomic.AtomicLong;
18import java.util.concurrent.locks.Lock;
19import java.util.concurrent.locks.ReadWriteLock;
20 
21/*
22   Copyright 2006 Peter Lawrey
23 
24   Licensed under the Apache License, Version 2.0 (the "License");
25   you may not use this file except in compliance with the License.
26   You may obtain a copy of the License at
27 
28       http://www.apache.org/licenses/LICENSE-2.0
29 
30   Unless required by applicable law or agreed to in writing, software
31   distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
32   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33   See the License for the specific language governing permissions and
34   limitations under the License.
35*/
36/**
37 * @author Peter Lawrey
38 */
39@SuppressWarnings({"unchecked", "ClassWithTooManyMethods"})
40@ThreadSafe(Concurrency.CONCURRENT_READ)
41public class MemoryBackingStore<K, V> implements BackingStore<K, V> {
42    private static final Log LOG = LogFactory.getLog(MemoryBackingStore.class);
43    private static final int DEFAULT_CACHE_SIZE = 1000;
44 
45    private static final Comparator<MetaData> FIFO_COMPARATOR = new Comparator<MetaData>() {
46        public int compare(MetaData o1, MetaData o2) {
47            long creationTime1 = o1.getCreationTime();
48            long creationTime2 = o2.getCreationTime();
49            if (creationTime1 < creationTime2)
50                return -1;
51            if (creationTime2 < creationTime1)
52                return +1;
53            // break ties
54            int hash1 = o1.getKey().hashCode();
55            int hash2 = o2.getKey().hashCode();
56            if (hash1 < hash2)
57                return -1;
58            else
59                return +1;
60        }
61    };
62    private static final Comparator<MetaData> LRU_COMPARATOR = new Comparator<MetaData>() {
63        public int compare(MetaData o1, MetaData o2) {
64            long accessTime1 = o1.getLastAccessTime();
65            long accessTime2 = o2.getLastAccessTime();
66            if (accessTime1 < accessTime2)
67                return -1;
68            if (accessTime1 > accessTime2)
69                return +1;
70            return FIFO_COMPARATOR.compare(o1, o2);
71        }
72    };
73    private static final Comparator<MetaData> LFU_COMPARATOR = new Comparator<MetaData>() {
74        public int compare(MetaData o1, MetaData o2) {
75            long hits1 = o1.getHits();
76            long hits2 = o2.getHits();
77            if (hits1 < hits2)
78                return +1;
79            if (hits1 > hits2)
80                return -1;
81            return LRU_COMPARATOR.compare(o1, o2);
82        }
83    };
84 
85    private final ReadWriteLock lock;
86    private final String name;
87    private final ClusterComponentBuilder.ClusterCollectionData cd;
88    private final boolean recordAccessTimes;
89    private final DataValueClass<K> keyClass;
90    private final DataValueClass<V> valueClass;
91    private final SortedSet<K> queue;
92    private final Event.ListenerSet listenerSet = new ListenerSetImpl();
93    private final boolean readOnly;
94    private final int cacheSize;
95 
96    protected final Map<K, V> backing;
97    protected final Map<K, MetaData<K, V>> metaData;
98    protected final Comparator<MetaData> evictSorter;
99 
100    protected boolean closed = false;
101    // for queue key generation.
102    private long counter = 0;
103    // for creating last Accessed times in us.
104    private final AtomicLong touchTime = new AtomicLong(System.currentTimeMillis() * 1000);
105 
106    // control who does eviction.
107    private int gets = 0;
108    private int puts = 0;
109    private int overSizeCount = 0;
110 
111    public MemoryBackingStore(@NotNull String name, @NotNull ClusterComponentBuilder.ClusterCollectionData cd) {
112        this.name = name;
113        this.cd = cd;
114 
115        lock = RWLock.createLock(name);
116        if (cd.collectionType == Store.CollectionType.MAP) queue = null;
117        else queue = Collections.synchronizedSortedSet(new TreeSet<K>());
118        backing = new HashMap<K, V>(256, 0.7f);
119        metaData = new HashMap<K, MetaData<K, V>>(256, 0.7f);
120        valueClass = DataValueClass.acquire(cd.valueClass);
121        keyClass = valueClass.getInferedKey(false);
122        readOnly = cd.persistMode == Store.PersistMode.READ_ONLY;
123 
124        switch (cd.evictionStrategy) {
125            case FIFO:
126                recordAccessTimes = false;
127                evictSorter = FIFO_COMPARATOR;
128                cacheSize = cd.cacheSize == null ? DEFAULT_CACHE_SIZE : cd.cacheSize;
129                break;
130            case LFU:
131                recordAccessTimes = true;
132                evictSorter = LFU_COMPARATOR;
133                cacheSize = cd.cacheSize == null ? DEFAULT_CACHE_SIZE : cd.cacheSize;
134                break;
135            case LRU:
136                recordAccessTimes = true;
137                evictSorter = LRU_COMPARATOR;
138                cacheSize = cd.cacheSize == null ? DEFAULT_CACHE_SIZE : cd.cacheSize;
139                break;
140            case NONE:
141                //noinspection UnnecessaryDefault
142            default:
143                recordAccessTimes = false;
144                evictSorter = null;
145                cacheSize = Integer.MAX_VALUE;
146                break;
147        }
148    }
149 
150    public long nextTouchTime() {
151        while (true) {
152            long now = System.currentTimeMillis() * 1000;
153            long next = touchTime.incrementAndGet();
154            if (next < now) {
155                if (!touchTime.compareAndSet(next, now))
156                    continue;
157                next = now;
158            }
159            gets++;
160            return next;
161        }
162    }
163 
164    @NotNull public Set<K> evict() {
165        if (getSize() <= cacheSize) {
166            gets = 0;
167            puts = 0;
168            overSizeCount = 0;
169            return Collections.emptySet();
170        }
171 
172        int evictSizeAllowed = Integer.MAX_VALUE;
173        if (cd.evictionStrategy == EvictionStrategy.LFU || cd.evictionStrategy == EvictionStrategy.LRU)
174            switch (++overSizeCount) {
175                // if I didn't do any gets, I haven't update the lastAccessTimes, so wait for a node which has.
176                case 0:
177                case 1:
178                case 2:
179                    if (gets < 1) {
180                        if (LOG.isDebugEnabled()) LOG.debug(Thread.currentThread().getName() + ": Didn't get so waiting.");
181                        return Collections.emptySet();
182                    }
183                    evictSizeAllowed = gets / (overSizeCount == 1 ? 2 : 1);
184                    break;
185                case 3:
186                case 4:
187                    if (gets < 1 && puts < 1) {
188                        if (LOG.isDebugEnabled()) LOG.debug(Thread.currentThread().getName() + ": Didn't get or put so waiting.");
189                        return Collections.emptySet();
190                    }
191                    evictSizeAllowed = (gets + puts) / (overSizeCount == 3 ? 2 : 1);
192                    break;
193                default:
194                    if (gets < 1 && puts < 1)
195                        if (LOG.isDebugEnabled())
196                            LOG.debug(Thread.currentThread().getName() + ": Didn't get or put but evicting anyway!");
197                    break;
198            }
199        Lock exclusiveLock = lock.writeLock();
200        try {
201            exclusiveLock.lock();
202 
203            MetaData<K, V>[] metaDataArr = metaData.values().toArray(new MetaData[metaData.size()]);
204            MetaData<K, V>[] metaDataArr2 = new MetaData[metaDataArr.length];
205            System.arraycopy(metaDataArr, 0, metaDataArr2, 0, metaDataArr.length);
206            Arrays.sort(metaDataArr, evictSorter);
207 
208            int toRemove = getSize() - cacheSize;
209            if (LOG.isDebugEnabled())
210                LOG.debug(Thread.currentThread().getName() + ": Evicting sizeAllowed=" + evictSizeAllowed + " toRemove=" + toRemove);
211            if (toRemove > evictSizeAllowed)
212                toRemove = evictSizeAllowed;
213 
214            Set<K> changes = new HashSet<K>();
215            for (int i = 0; i < toRemove; i++) {
216                K key = metaDataArr[i].getKey();
217                if (!changes.add(key))
218                    LOG.error("The key " + key + " appeared in eviction more than once.");
219            }
220            if (LOG.isDebugEnabled() && !changes.isEmpty()) {
221                LOG.debug(Thread.currentThread().getName() + ": Evicting " + changes.size() + " entries.");
222                LOG.debug(changes);
223            }
224            return changes;
225        } finally {
226            exclusiveLock.unlock();
227        }
228    }
229 
230    public double evictCandidate() {
231        if (evictSorter == null) return 0;
232        int size = backing.size();
233        return size > cacheSize ? size / cacheSize - 1 : 0;
234    }
235 
236    protected boolean canWrite() {
237        return cd.persistMode != Store.PersistMode.NONE && cd.persistMode != Store.PersistMode.READ_ONLY;
238    }
239 
240    public void close() {
241        closed = true;
242    }
243 
244    public void checkKey(@NotNull Object key) throws IllegalArgumentException {
245        checkClass("key", keyClass, key);
246 
247        if (key instanceof Number) {
248            Number num = (Number) key;
249            if (counter <= num.longValue())
250                counter = num.longValue() + 1;
251        }
252    }
253 
254    private static void checkClass(String type, DataValueClass clazz, Object data) {
255        Class clazz2 = data.getClass();
256        if (clazz != null && clazz.isNotAssignableFrom(clazz2))
257            throw new IllegalArgumentException("Cannot cast "+type+' ' + data + ' ' + clazz2 + " to " + clazz);
258        if (DataValueClass.acquire(clazz2).isNotSerializable())
259            throw new IllegalArgumentException("Cannot cluster a "+type+" which is not Serializable, Datable or DataValue '" + data + "' " + clazz2);
260    }
261 
262    public void checkReadOnly() throws IllegalAccessError {
263        if (readOnly) throw new IllegalAccessError(name + ": Is READ_ONLY.");
264    }
265 
266    public void checkValue(@NotNull V value) throws IllegalArgumentException {
267        checkClass("value", valueClass,value);
268    }
269 
270    @SuppressWarnings({"SuspiciousMethodCalls"})
271    public boolean containsKey(Object key) {
272        Lock readLock = lock.readLock();
273        try {
274            readLock.lock();
275            return backing.containsKey(key);
276        } finally {
277            readLock.unlock();
278        }
279    }
280 
281    @NotNull public K deriveKey(@NotNull V value) {
282        K key;
283        try {
284            if (keyClass == null)
285                key = (K) Long.valueOf(counter++);
286            else
287                key = keyClass.build(valueClass.asMap2(value), PojoContext.EMPTY);
288        } catch (InstantiationException e) {
289            throw new IllegalArgumentException("Unable to derive a key from value " + value, e.getCause());
290        }
291        return key;
292    }
293 
294    public int expireMetaData(long version) {
295        Lock exclusiveLock = lock.writeLock();
296        if (!exclusiveLock.tryLock()) return 0;
297        long now = System.currentTimeMillis();
298        try {
299            Set<K> toRemove = new LinkedHashSet<K>();
300            for (Map.Entry<K, MetaData<K, V>> entry : metaData.entrySet()) {
301                V value = backing.get(entry.getKey());
302                if (value != null) continue;
303                MetaData metaValue = entry.getValue();
304                if (metaValue == null) continue;
305                long expirationTime = metaValue.getExpirationTime();
306                long modifiedTime = metaValue.getVersion();
307                if (expirationTime > now && modifiedTime >= version) continue;
308                toRemove.add(entry.getKey());
309            }
310            metaData.keySet().removeAll(toRemove);
311            // shouldn't do anything but is a double check.
312            backing.keySet().removeAll(toRemove);
313            return toRemove.size();
314        } finally {
315            exclusiveLock.unlock();
316        }
317    }
318 
319    @Nullable public K firstKey() {
320        Lock readLock = lock.readLock();
321        try {
322            readLock.lock();
323            if (backing.isEmpty()) return null;
324            return queue == null ? backing.keySet().iterator().next() : queue.first();
325        } finally {
326            readLock.unlock();
327        }
328    }
329 
330    @NotNull public Collection<MetaData<K, V>> getAllData() {
331        Lock readLock = lock.readLock();
332        try {
333            long start = System.nanoTime();
334            readLock.lock();
335            Collection<MetaData<K, V>> ret = ImmutableUtils.immutableCopyList(metaData.values());
336            long end = System.nanoTime();
337            if (end - start > 20L * 1000 * 1000)   // 20 ms
338                LOG.warn(name + ":Took " + (end - start) / 1000 / 1000 + " ms to grab " + metaData.size() + " entries.");
339            return ret;
340        } finally {
341            readLock.unlock();
342        }
343    }
344 
345    @NotNull public Set<Map.Entry<K, V>> getEntrySet() {
346        Lock readLock = lock.readLock();
347        try {
348            readLock.lock();
349            return ImmutableUtils.immutableCopyMap(backing).entrySet();
350        } finally {
351            readLock.unlock();
352        }
353    }
354 
355    @NotNull public Set<K> getKeySet() {
356        Lock readLock = lock.readLock();
357        try {
358            readLock.lock();
359            return ImmutableUtils.immutableCopySet(backing.keySet());
360        } finally {
361            readLock.unlock();
362        }
363    }
364 
365    public Event.ListenerSet getListenerSet() {
366        return listenerSet;
367    }
368 
369    public ReadWriteLock getLock() {
370        return lock;
371    }
372 
373    @NotNull public String getName() {
374        return name;
375    }
376 
377    public int getSize() {
378        Lock readLock = lock.readLock();
379        try {
380            readLock.lock();
381            return backing.size();
382        } finally {
383            readLock.unlock();
384        }
385    }
386 
387    protected Collection<K> getRetiredKeys(Collection<K> ks) {
388        Lock readLock = lock.readLock();
389        try {
390            readLock.lock();
391            List<K> retiredKeys = new ArrayList<K>();
392            for (K key : ks)
393                if (!metaData.containsKey(key))
394                    retiredKeys.add(key);
395            return retiredKeys;
396        } finally {
397            readLock.unlock();
398        }
399    }
400 
401    public MetaData[] getSnapshot(K... keys) {
402        Lock readLock = lock.readLock();
403        try {
404            readLock.lock();
405 
406            MetaData[] metaDatas = new MetaData[keys.length];
407            for (int i = 0; i < keys.length; i++)
408                metaDatas[i] = metaData.get(keys[i]);
409            return metaDatas;
410        } finally {
411            readLock.unlock();
412        }
413    }
414 
415    @Nullable public MetaData<K, V> getMetaData(@NotNull K key) {
416        try {
417            lock.readLock().lock();
418 
419            MetaData<K, V> metaData2 = metaData.get(key);
420            if (recordAccessTimes && metaData2 != null)
421                metaData2.touchRead(nextTouchTime());
422            return metaData2;
423        } finally {
424            lock.readLock().unlock();
425        }
426    }
427 
428    @Nullable public V getValue(@NotNull K key) {
429        Lock readLock = lock.readLock();
430        MetaData<K, V> md = null;
431        try {
432            readLock.lock();
433            md = metaData.get(key);
434        } finally {
435            readLock.unlock();
436        }
437        V value = null;
438        if (md != null) {
439            value = md.getValue();
440            if (recordAccessTimes && value != null)
441                md.touchRead(nextTouchTime());
442        }
443        return value;
444    }
445 
446    @NotNull public Collection<V> getValues() {
447        Lock readLock = lock.readLock();
448        try {
449            readLock.lock();
450            return ImmutableUtils.immutableCopyList(backing.values());
451        } finally {
452            readLock.unlock();
453        }
454    }
455 
456    public boolean isClosed() {
457        return closed;
458    }
459 
460    @NotNull
461    public Collection<MetaData<K, V>> performChanges(@NotNull Collection<MetaData<K, V>> metaDataMap) throws InterruptedException {
462        checkReadOnly();
463        Lock writeLock = lock.writeLock();
464        try {
465            writeLock.lockInterruptibly();
466 
467            Collection<MetaData<K, V>> changes = new ArrayList<MetaData<K, V>>();
468            for (MetaData<K, V> md : metaDataMap) {
469                K key = md.getKey();
470                V value = md.getValue();
471 
472                MetaData md2 = metaData.get(key);
473                if (md2 == null) {
474                    if (value == null) {
475                        backing.remove(key);                // just to be sure.
476                    } else {
477                        puts++;
478                        backing.put(key, value);
479                        metaData.put(key, md);
480                        changes.add(md);
481                    }
482                } else if (md2.isBefore(md)) {
483                    metaData.put(key, md);
484                    if (value == null) {
485                        V value2 = backing.remove(key);
486                        if (value2 != null)
487                            changes.add(md);
488                    } else {
489                        V value2 = backing.put(key, value);
490                        if (value2 != null && !value2.equals(value))
491                            changes.add(md);
492                    }
493                }
494            }
495            persistChanges(changes);
496            return changes;
497        } finally {
498            writeLock.unlock();
499        }
500    }
501 
502    protected void persistChanges(Collection<MetaData<K, V>> changes) {
503 
504    }
505 
506    @NotNull
507    public Collection<MetaData<K, V>> performChanges(@NotNull String source, long timeMS, @NotNull Map<K, V> changes) throws InterruptedException {
508        checkReadOnly();
509        Lock exclusiveLock = lock.writeLock();
510        //noinspection LockAcquiredButNotSafelyReleased
511        exclusiveLock.lockInterruptibly();
512        try {
513            Collection<MetaData<K, V>> changes2 = new ArrayList<MetaData<K, V>>();
514            for (Map.Entry<K, V> entry : changes.entrySet()) {
515                K key = entry.getKey();
516                V value = entry.getValue();
517                MetaData md = metaData.get(key);
518                // if the change does not have precedence, drop change.
519                if (isBefore(source, timeMS, md)) continue;
520 
521                long creationTimeMS = md == null ? timeMS : md.getCreationTime();
522                long expirationTime = md == null ? Long.MAX_VALUE : md.getExpirationTime();
523                int hits = md == null ? 1 : md.getHits() + 1;
524                MetaData newMD = new MetaData<K, V>(creationTimeMS, expirationTime,
525                        hits, key, source, timeMS, value);
526 
527                metaData.put(key, newMD);
528                if (value == null) {
529                    if (queue != null) queue.remove(key);
530                    V prev = backing.remove(key);
531                    // the value wasn't deleted.
532                    if (prev == null) continue;
533                } else {
534                    V prev = backing.put(key, value);
535                    // the value wasn't changed.
536                    if (prev != null && value.equals(prev)) continue;
537 
538                    if (prev == null && queue != null)
539                        queue.add(key);
540                }
541                changes2.add(newMD);
542            }
543            persistChanges(changes2);
544            return changes2;
545        } finally {
546            exclusiveLock.unlock();
547        }
548    }
549 
550    public Map<K, V> getAll(Collection<K> keys) {
551        Map<K, V> ret = new LinkedHashMap<K, V>();
552        Lock readLock = lock.readLock();
553        try {
554            readLock.lock();
555            for (K key : keys)
556                ret.put(key, backing.get(key));
557            return ret;
558        } finally {
559            readLock.unlock();
560        }
561    }
562 
563    public Map<K, V> selectMatching(Predicate<? super MetaData<K, V>> predicate) {
564        Map<K, V> ret = new LinkedHashMap<K, V>();
565        Lock readLock = lock.readLock();
566        try {
567            readLock.lock();
568            for (MetaData<K, V> value : metaData.values()) {
569                if (value.getValue() != null && predicate.isSatisfiedBy(value))
570                    ret.put(value.getKey(), value.getValue());
571            }
572            return ret;
573        } finally {
574            readLock.unlock();
575        }
576    }
577 
578    public void start() throws IllegalStateException, IllegalArgumentException {
579        if (closed) throw new IllegalStateException(CLOSED);
580    }
581 
582    public void stop() {
583    }
584 
585    @Override protected void finalize() throws Throwable {
586        super.finalize();
587        if (!closed) close();
588    }
589}

[all classes][org.jtoolkit.essence.data.impl]
EMMA 2.0.5312 (C) Vladimir Roubtsov