Changing the test to run with both version, the bad Cache as well as CacheOK. Making sure the same test passes for CacheOK
authorJaroslav Tulach <jtulach@netbeans.org>
Thu, 12 Feb 2009 10:55:02 +0100
changeset 3196c1d8b5553d8
parent 318 38ebce3000fd
child 320 9ad0cc253aa9
Changing the test to run with both version, the bad Cache as well as CacheOK. Making sure the same test passes for CacheOK
samples/deadlock/src/org/apidesign/javamonitorflaws/CacheOK.java
samples/deadlock/test/org/apidesign/javamonitorflaws/CacheTest.java
samples/deadlock/test/org/apidesign/javamonitorflaws/MultiplyCache.java
samples/deadlock/test/org/apidesign/javamonitorflaws/MultiplyCacheOK.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/samples/deadlock/src/org/apidesign/javamonitorflaws/CacheOK.java	Thu Feb 12 10:55:02 2009 +0100
     1.3 @@ -0,0 +1,54 @@
     1.4 +package org.apidesign.javamonitorflaws;
     1.5 +
     1.6 +import java.util.HashMap;
     1.7 +import java.util.Map;
     1.8 +
     1.9 +/** Classical caching support class that makes sure there is
    1.10 + * always one "To" value for each "From" one returned from the {@link #get}
    1.11 + * method. However it does not prevent multiple threads to call
    1.12 + * {@link #createItem} multiple times for the same "From" value.
    1.13 + * <p>
    1.14 + * In contrast to {@link Cache}, this is correctly synchronized.
    1.15 + *
    1.16 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    1.17 + */
    1.18 +// BEGIN: monitor.pitfalls.CacheOK
    1.19 +public abstract class CacheOK<From,To> {
    1.20 +    private Object LOCK = new Object();
    1.21 +
    1.22 +    private Map<From,To> cache;
    1.23 +
    1.24 +    protected abstract To createItem(From f);
    1.25 +
    1.26 +    public final To get(From f) {
    1.27 +        To t = inspectValue(f);
    1.28 +        if (t != null) {
    1.29 +            return t;
    1.30 +        }
    1.31 +        To newT = createItem(f);
    1.32 +        return registerValue(f, newT);
    1.33 +    }
    1.34 +
    1.35 +
    1.36 +    private To inspectValue(From f) {
    1.37 +        synchronized (LOCK) {
    1.38 +            if (cache == null) {
    1.39 +                cache = new HashMap<From, To>();
    1.40 +            }
    1.41 +            return cache.get(f);
    1.42 +        }
    1.43 +    }
    1.44 +
    1.45 +    private To registerValue(From f, To newT) {
    1.46 +        synchronized (LOCK) {
    1.47 +            To t = cache.get(f);
    1.48 +            if (t == null) {
    1.49 +                cache.put(f, newT);
    1.50 +                return newT;
    1.51 +            } else {
    1.52 +                return t;
    1.53 +            }
    1.54 +        }
    1.55 +    }
    1.56 +}
    1.57 +// END: monitor.pitfalls.CacheOK
     2.1 --- a/samples/deadlock/test/org/apidesign/javamonitorflaws/CacheTest.java	Wed Feb 11 10:16:43 2009 +0100
     2.2 +++ b/samples/deadlock/test/org/apidesign/javamonitorflaws/CacheTest.java	Thu Feb 12 10:55:02 2009 +0100
     2.3 @@ -5,8 +5,6 @@
     2.4  import org.netbeans.junit.NbTestCase;
     2.5  
     2.6  public class CacheTest extends NbTestCase {
     2.7 -    private MultiplyCache cache = new MultiplyCache();
     2.8 -
     2.9      public CacheTest(String n) {
    2.10          super(n);
    2.11      }
    2.12 @@ -48,6 +46,8 @@
    2.13      public void testDeadlockWithSetter() throws Exception {
    2.14          if (Boolean.getBoolean("no.failures")) return;
    2.15          
    2.16 +        final CacheToTest cache = new MultiplyCache();
    2.17 +
    2.18          class ToDeadlock implements Runnable, PropertyChangeListener {
    2.19              int value;
    2.20  
    2.21 @@ -98,10 +98,14 @@
    2.22    org.apidesign.javamonitorflaws.CacheTest$2ToDeadlock.run:90
    2.23    java.lang.Thread.run:619
    2.24       */
    2.25 -    // BEGIN: monitor.pitfalls.block.propertychange
    2.26      public void testDeadlockViaAPI() throws Exception {
    2.27          if (Boolean.getBoolean("no.failures")) return;
    2.28 -        
    2.29 +        testDeadlockViaAPI(new MultiplyCache());
    2.30 +    }
    2.31 +
    2.32 +    // BEGIN: monitor.pitfalls.block.propertychange
    2.33 +    private static void testDeadlockViaAPI(final CacheToTest cache)
    2.34 +    throws Exception {
    2.35          class ToDeadlock implements Runnable, PropertyChangeListener {
    2.36              int lastMultiply;
    2.37  
    2.38 @@ -139,4 +143,17 @@
    2.39          // END: monitor.pitfalls.brokencall
    2.40      }
    2.41      // END: monitor.pitfalls.block.propertychange
    2.42 +
    2.43 +    public void testDeadlockViaAPIWithCacheOK() throws Exception {
    2.44 +        testDeadlockViaAPI(new MultiplyCacheOK());
    2.45 +    }
    2.46 +
    2.47 +    static interface CacheToTest {
    2.48 +        public Integer get(String key);
    2.49 +
    2.50 +        public void setMultiply(int m);
    2.51 +        public int getMultiply();
    2.52 +        public void addPropertyChangeListener(PropertyChangeListener l);
    2.53 +        public void removePropertyChangeListener(PropertyChangeListener l);
    2.54 +    }
    2.55  }
    2.56 \ No newline at end of file
     3.1 --- a/samples/deadlock/test/org/apidesign/javamonitorflaws/MultiplyCache.java	Wed Feb 11 10:16:43 2009 +0100
     3.2 +++ b/samples/deadlock/test/org/apidesign/javamonitorflaws/MultiplyCache.java	Thu Feb 12 10:55:02 2009 +0100
     3.3 @@ -1,6 +1,5 @@
     3.4  package org.apidesign.javamonitorflaws;
     3.5  
     3.6 -import org.apidesign.javamonitorflaws.Cache;
     3.7  import java.beans.PropertyChangeListener;
     3.8  import java.beans.PropertyChangeSupport;
     3.9  
    3.10 @@ -9,7 +8,8 @@
    3.11   * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.12   */
    3.13  // BEGIN: monitor.pitfalls.subclass
    3.14 -public class MultiplyCache extends Cache<String,Integer> {
    3.15 +public class MultiplyCache extends Cache<String,Integer>
    3.16 +implements CacheTest.CacheToTest {
    3.17      private PropertyChangeSupport pcs;
    3.18      private int multiply;
    3.19      public static final String PROP_MULTIPLY = "multiply";
    3.20 @@ -41,7 +41,7 @@
    3.21  
    3.22      @Override
    3.23      protected Integer createItem(String f) {
    3.24 -        return f.length() * getMultiply();
    3.25 +        return f.length() * multiply;
    3.26      }
    3.27  }
    3.28  // END: monitor.pitfalls.subclass
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/samples/deadlock/test/org/apidesign/javamonitorflaws/MultiplyCacheOK.java	Thu Feb 12 10:55:02 2009 +0100
     4.3 @@ -0,0 +1,49 @@
     4.4 +package org.apidesign.javamonitorflaws;
     4.5 +
     4.6 +import java.beans.PropertyChangeListener;
     4.7 +import java.beans.PropertyChangeSupport;
     4.8 +
     4.9 +/**
    4.10 + *
    4.11 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    4.12 + */
    4.13 +// BEGIN: monitor.pitfalls.subclassok
    4.14 +public class MultiplyCacheOK extends CacheOK<String,Integer>
    4.15 +implements CacheTest.CacheToTest {
    4.16 +    private PropertyChangeSupport pcs;
    4.17 +    private int multiply;
    4.18 +    public static final String PROP_MULTIPLY = "multiply";
    4.19 +
    4.20 +    public synchronized int getMultiply() {
    4.21 +        return multiply;
    4.22 +    }
    4.23 +    public synchronized void setMultiply(int multiply) {
    4.24 +        int oldMultiply = this.multiply;
    4.25 +        this.multiply = multiply;
    4.26 +        pcs.firePropertyChange(PROP_MULTIPLY, oldMultiply, multiply);
    4.27 +    }
    4.28 +
    4.29 +    public synchronized void addPropertyChangeListener(
    4.30 +        PropertyChangeListener listener
    4.31 +    ) {
    4.32 +        if (pcs == null) {
    4.33 +            pcs = new PropertyChangeSupport(this);
    4.34 +        }
    4.35 +        pcs.addPropertyChangeListener(listener);
    4.36 +    }
    4.37 +    public synchronized void removePropertyChangeListener(
    4.38 +        PropertyChangeListener listener
    4.39 +    ) {
    4.40 +        if (pcs != null) {
    4.41 +            pcs.removePropertyChangeListener(listener);
    4.42 +        }
    4.43 +    }
    4.44 +
    4.45 +    @Override
    4.46 +    protected Integer createItem(String f) {
    4.47 +        return f.length() * multiply;
    4.48 +    }
    4.49 +}
    4.50 +// END: monitor.pitfalls.subclassok
    4.51 +
    4.52 +