OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 144 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 144 Rev 182
Line 30... Line 30...
30
import java.util.Map;
30
import java.util.Map;
31
import java.util.Set;
31
import java.util.Set;
32
import java.util.concurrent.TimeUnit;
32
import java.util.concurrent.TimeUnit;
33
import java.util.logging.Level;
33
import java.util.logging.Level;
34
 
34
 
-
 
35
import net.jcip.annotations.GuardedBy;
-
 
36
 
35
/**
37
/**
36
 * To keep results computed from some data. The results will be automatically invalidated after some
38
 * To keep results computed from some data. The results will be automatically invalidated after some
37
 * period of time or when the data is modified.
39
 * period of time or when the data is modified.
38
 * 
40
 * 
39
 * @author Sylvain CUAZ
41
 * @author Sylvain CUAZ
Line 50... Line 52...
50
    public static final String ITEM_REMOVED = "itemRemoved";
52
    public static final String ITEM_REMOVED = "itemRemoved";
51
 
53
 
52
    private final ICacheSupport<D> supp;
54
    private final ICacheSupport<D> supp;
53
    // linked to fifo, ATTN the values in this map can be invalid since clear() is called without
55
    // linked to fifo, ATTN the values in this map can be invalid since clear() is called without
54
    // the lock on CacheValue
56
    // the lock on CacheValue
-
 
57
    @GuardedBy("this")
55
    private final LinkedHashMap<K, CacheItem<K, V, D>> cache;
58
    private final LinkedHashMap<K, CacheItem<K, V, D>> cache;
-
 
59
    @GuardedBy("this")
56
    private final Map<K, CacheItem<K, V, D>> running;
60
    private final Map<K, CacheItem<K, V, D>> running;
57
    private final int delay;
61
    private final int delay;
58
    private final int size;
62
    private final int size;
59
    private final String name;
63
    private final String name;
60
 
64
 
Line 222... Line 226...
222
 
226
 
223
    public final synchronized void removeRunning(final CacheResult<V> res) {
227
    public final synchronized void removeRunning(final CacheResult<V> res) {
224
        removeRunning(getRunningValFromRes(res));
228
        removeRunning(getRunningValFromRes(res));
225
    }
229
    }
226
 
230
 
227
    private final synchronized void removeRunning(final CacheItem<K, V, D> val) {
231
    private final synchronized boolean removeRunning(final CacheItem<K, V, D> val) {
228
        if (val == null)
232
        if (val == null)
229
            return;
233
            return false;
230
        final K key = val.getKey();
234
        final K key = val.getKey();
-
 
235
        final boolean removed;
231
        if (this.running.get(key) == val)
236
        if (this.running.get(key) == val) {
232
            this.removeRunning(key);
237
            this.removeRunning(key);
-
 
238
            removed = true;
233
        else
239
        } else {
234
            // either val wasn't created in this cache or another value was already put in this
240
            // either val wasn't created in this cache or another value was already put in this
235
            // cache
241
            // cache
236
            val.setRemovalType(RemovalType.EXPLICIT);
242
            removed = val.setRemovalType(RemovalType.EXPLICIT);
-
 
243
        }
237
        assert val.getRemovalType() != null;
244
        assert val.getRemovalType() != null;
-
 
245
        return removed;
238
    }
246
    }
239
 
247
 
240
    private final synchronized void removeRunning(K key) {
248
    private final synchronized void removeRunning(K key) {
241
        final CacheItem<K, V, D> removed = this.running.remove(key);
249
        final CacheItem<K, V, D> removed = this.running.remove(key);
242
        if (removed != null) {
250
        if (removed != null) {
Line 425... Line 433...
425
    }
433
    }
426
 
434
 
427
    final boolean clear(final CacheItem<K, V, D> val) {
435
    final boolean clear(final CacheItem<K, V, D> val) {
428
        if (val.getRemovalType() == null)
436
        if (val.getRemovalType() == null)
429
            throw new IllegalStateException("Not yet removed : " + val);
437
            throw new IllegalStateException("Not yet removed : " + val);
430
        final boolean toBeRemoved;
438
        final boolean removedFromRunning, toBeRemoved;
431
        synchronized (this) {
439
        synchronized (this) {
432
            log("clear", val);
440
            log("clear", val);
433
            this.removeRunning(val);
441
            removedFromRunning = this.removeRunning(val);
434
            toBeRemoved = this.cache.get(val.getKey()) == val;
442
            toBeRemoved = this.cache.get(val.getKey()) == val;
435
            if (toBeRemoved) {
443
            if (toBeRemoved) {
436
                this.cache.remove(val.getKey());
444
                this.cache.remove(val.getKey());
437
            }
445
            }
438
        }
446
        }
439
        // NOTE these events are often fired with our monitor since this method is called with it
447
        // NOTE these events are often fired with our monitor since this method is called with it
-
 
448
        if (removedFromRunning || toBeRemoved) {
440
        this.propSupp.firePropertyChange(new Event<K, V, D>(this, ITEMS_CHANGED, null, null));
449
            this.propSupp.firePropertyChange(new Event<K, V, D>(this, ITEMS_CHANGED, null, null));
441
        this.propSupp.firePropertyChange(this.createItemEvent(ITEM_REMOVED, val, null));
450
            this.propSupp.firePropertyChange(this.createItemEvent(ITEM_REMOVED, val, null));
-
 
451
        }
442
        return toBeRemoved;
452
        return toBeRemoved;
443
    }
453
    }
444
 
454
 
445
    public final synchronized void clear() {
455
    public final synchronized void clear() {
446
        for (final CacheItem<K, V, D> val : new ArrayList<CacheItem<K, V, D>>(this.cache.values()))
456
        for (final CacheItem<K, V, D> val : new ArrayList<CacheItem<K, V, D>>(this.cache.values())) {
-
 
457
            // We have our monitor so if val is still in us but setRemovalType() was already called,
-
 
458
            // then it means another thread is waiting on our monitor in clear(CacheItem). In that
-
 
459
            // case, just call it now so that this is empty at the end of this method.
447
            val.setRemovalType(RemovalType.EXPLICIT);
460
            if (!val.setRemovalType(RemovalType.EXPLICIT)) {
-
 
461
                final boolean removed = this.clear(val);
448
        assert this.size() == 0;
462
                assert removed;
-
 
463
            }
-
 
464
        }
-
 
465
        assert this.size() == 0 : this + " expected to be empty but contains : " + this.cache.keySet();
-
 
466
 
449
        for (final CacheItem<K, V, D> val : new ArrayList<CacheItem<K, V, D>>(this.running.values()))
467
        for (final CacheItem<K, V, D> val : new ArrayList<CacheItem<K, V, D>>(this.running.values()))
450
            val.setRemovalType(RemovalType.EXPLICIT);
468
            val.setRemovalType(RemovalType.EXPLICIT);
451
        assert this.running.size() == 0;
469
        assert this.running.size() == 0 : this + " expected to have no running but contains : " + this.running.keySet();
452
    }
470
    }
453
 
471
 
454
    private final void log(String msg, Object subject) {
472
    private final void log(String msg, Object subject) {
455
        // do the toString() on subject only if necessary
473
        // do the toString() on subject only if necessary
456
        if (Log.get().isLoggable(LEVEL))
474
        if (Log.get().isLoggable(LEVEL))