jtulach@319: package org.apidesign.javamonitorflaws;
jtulach@319:
jtulach@319: import java.util.HashMap;
jtulach@319: import java.util.Map;
jtulach@319:
jtulach@319: /** Classical caching support class that makes sure there is
jtulach@319: * always one "To" value for each "From" one returned from the {@link #get}
jtulach@319: * method. However it does not prevent multiple threads to call
jtulach@319: * {@link #createItem} multiple times for the same "From" value.
jtulach@319: *
jtulach@319: * In contrast to {@link Cache}, this is correctly synchronized.
jtulach@319: *
jtulach@319: * @author Jaroslav Tulach
jtulach@319: */
jtulach@319: // BEGIN: monitor.pitfalls.CacheOK
jtulach@319: public abstract class CacheOK {
jtulach@319: private Object LOCK = new Object();
jtulach@319:
jtulach@319: private Map cache;
jtulach@319:
jtulach@319: protected abstract To createItem(From f);
jtulach@319:
jtulach@319: public final To get(From f) {
jtulach@319: To t = inspectValue(f);
jtulach@319: if (t != null) {
jtulach@319: return t;
jtulach@319: }
jtulach@319: To newT = createItem(f);
jtulach@319: return registerValue(f, newT);
jtulach@319: }
jtulach@319:
jtulach@319:
jtulach@319: private To inspectValue(From f) {
jtulach@319: synchronized (LOCK) {
jtulach@319: if (cache == null) {
jtulach@319: cache = new HashMap();
jtulach@319: }
jtulach@319: return cache.get(f);
jtulach@319: }
jtulach@319: }
jtulach@319:
jtulach@319: private To registerValue(From f, To newT) {
jtulach@319: synchronized (LOCK) {
jtulach@319: To t = cache.get(f);
jtulach@319: if (t == null) {
jtulach@319: cache.put(f, newT);
jtulach@319: return newT;
jtulach@319: } else {
jtulach@319: return t;
jtulach@319: }
jtulach@319: }
jtulach@319: }
jtulach@319: }
jtulach@319: // END: monitor.pitfalls.CacheOK