Calculator and various ways to deliver changes in its counter to listeners
authorJaroslav Tulach <jtulach@netbeans.org>
Sun, 20 Mar 2011 18:52:47 +0100
changeset 37435da2d439e3d
parent 373 c20d1d8ef2ca
child 375 3abae898011d
Calculator and various ways to deliver changes in its counter to listeners
samples/openfixed/nbproject/project.properties
samples/openfixed/src/org/apidesign/openfixed/AsyncEventSupport.java
samples/openfixed/src/org/apidesign/openfixed/Calculator.java
samples/openfixed/src/org/apidesign/openfixed/EventSupport.java
samples/openfixed/src/org/apidesign/openfixed/Growable.java
samples/openfixed/src/org/apidesign/openfixed/GrowingEvent.java
samples/openfixed/src/org/apidesign/openfixed/GrowingListener.java
samples/openfixed/src/org/apidesign/openfixed/ModificationEvent.java
samples/openfixed/src/org/apidesign/openfixed/ModificationListener.java
samples/openfixed/src/org/apidesign/openfixed/PendingEventSupport.java
samples/openfixed/src/org/apidesign/openfixed/PostEventSupport.java
samples/openfixed/src/org/apidesign/openfixed/PostModificationEvent.java
samples/openfixed/src/org/apidesign/openfixed/PostModificationListener.java
samples/openfixed/src/org/apidesign/openfixed/TrivialEventSupport.java
samples/openfixed/test/org/apidesign/openfixed/AsyncTest.java
samples/openfixed/test/org/apidesign/openfixed/BasicTest.java
samples/openfixed/test/org/apidesign/openfixed/CalculatorBase.java
samples/openfixed/test/org/apidesign/openfixed/PendingTest.java
samples/openfixed/test/org/apidesign/openfixed/PostTest.java
     1.1 --- a/samples/openfixed/nbproject/project.properties	Sun Mar 20 08:12:26 2011 +0100
     1.2 +++ b/samples/openfixed/nbproject/project.properties	Sun Mar 20 18:52:47 2011 +0100
     1.3 @@ -25,6 +25,7 @@
     1.4  dist.jar=${dist.dir}/openfixed.jar
     1.5  dist.javadoc.dir=${dist.dir}/javadoc
     1.6  excludes=
     1.7 +file.reference.junit-4.4.jar=../libs/dist/junit-4.4.jar
     1.8  includes=**
     1.9  jar.compress=false
    1.10  javac.classpath=
    1.11 @@ -37,7 +38,8 @@
    1.12  javac.target=1.6
    1.13  javac.test.classpath=\
    1.14      ${javac.classpath}:\
    1.15 -    ${build.classes.dir}
    1.16 +    ${build.classes.dir}:\
    1.17 +    ${file.reference.junit-4.4.jar}
    1.18  javac.test.processorpath=\
    1.19      ${javac.test.classpath}
    1.20  javadoc.additionalparam=
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/AsyncEventSupport.java	Sun Mar 20 18:52:47 2011 +0100
     2.3 @@ -0,0 +1,50 @@
     2.4 +package org.apidesign.openfixed;
     2.5 +
     2.6 +import java.util.List;
     2.7 +import java.util.concurrent.CopyOnWriteArrayList;
     2.8 +import java.util.concurrent.Executor;
     2.9 +import java.util.concurrent.Executors;
    2.10 +
    2.11 +/**
    2.12 + *
    2.13 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    2.14 + */
    2.15 +final class AsyncEventSupport implements EventSupport {
    2.16 +    private final List<ModificationListener> listeners = new CopyOnWriteArrayList<ModificationListener>();
    2.17 +    private static final Executor EXEC = Executors.newSingleThreadExecutor();
    2.18 +    
    2.19 +    AsyncEventSupport() {
    2.20 +    }
    2.21 +
    2.22 +    @Override
    2.23 +    public void fireModificationEvent(ModificationEvent ev) {
    2.24 +        EXEC.execute(new Deliverable(ev, listeners.toArray(new ModificationListener[0])));
    2.25 +    }
    2.26 +
    2.27 +    @Override
    2.28 +    public void add(ModificationListener l) {
    2.29 +        listeners.add(l);
    2.30 +    }
    2.31 +
    2.32 +    @Override
    2.33 +    public void remove(ModificationListener l) {
    2.34 +        listeners.remove(l);
    2.35 +    }
    2.36 +    
    2.37 +    private static class Deliverable implements Runnable {
    2.38 +        final ModificationEvent ev;
    2.39 +        final ModificationListener[] listeners;
    2.40 +
    2.41 +        public Deliverable(ModificationEvent ev, ModificationListener[] listeners) {
    2.42 +            this.ev = ev;
    2.43 +            this.listeners = listeners;
    2.44 +        }
    2.45 +
    2.46 +        @Override
    2.47 +        public void run() {
    2.48 +            for (ModificationListener l : listeners) {
    2.49 +                l.modification(ev);
    2.50 +            }
    2.51 +        }
    2.52 +    }
    2.53 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/Calculator.java	Sun Mar 20 18:52:47 2011 +0100
     3.3 @@ -0,0 +1,49 @@
     3.4 +package org.apidesign.openfixed;
     3.5 +
     3.6 +/** Sample bean using the {@link ModificationListener}
     3.7 + * to <b>add</b> numbers.
     3.8 + *
     3.9 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.10 + */
    3.11 +public final class Calculator {
    3.12 +    private final EventSupport listeners;
    3.13 +    private int sum;
    3.14 +
    3.15 +    private Calculator(EventSupport listeners) {
    3.16 +        this.listeners = listeners;
    3.17 +    }
    3.18 +    
    3.19 +    public static Calculator create() {
    3.20 +        return new Calculator(new TrivialEventSupport());
    3.21 +    }
    3.22 +
    3.23 +    public static Calculator createAsynch() {
    3.24 +        return new Calculator(new AsyncEventSupport());
    3.25 +    }
    3.26 +
    3.27 +    /** @since 2.0 */
    3.28 +    public static Calculator createPending() {
    3.29 +        return new Calculator(new PendingEventSupport());
    3.30 +    }
    3.31 +
    3.32 +    /** @since 3.0 */
    3.33 +    public static Calculator createBatch() {
    3.34 +        return new Calculator(new PostEventSupport());
    3.35 +    }
    3.36 +
    3.37 +    public synchronized void add(int add) {
    3.38 +        sum += add;
    3.39 +        listeners.fireModificationEvent(new ModificationEvent(this, add));
    3.40 +    }
    3.41 +    
    3.42 +    public synchronized int getSum() {
    3.43 +        return sum;
    3.44 +    }
    3.45 +    
    3.46 +    public void addModificationListener(ModificationListener l) {
    3.47 +        listeners.add(l);
    3.48 +    }
    3.49 +    public void removeModificationListener(ModificationListener l) {
    3.50 +        listeners.remove(l);
    3.51 +    }
    3.52 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/EventSupport.java	Sun Mar 20 18:52:47 2011 +0100
     4.3 @@ -0,0 +1,19 @@
     4.4 +/*
     4.5 + * To change this template, choose Tools | Templates
     4.6 + * and open the template in the editor.
     4.7 + */
     4.8 +package org.apidesign.openfixed;
     4.9 +
    4.10 +/**
    4.11 + *
    4.12 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    4.13 + */
    4.14 +interface EventSupport {
    4.15 +
    4.16 +    public void fireModificationEvent(ModificationEvent ev);
    4.17 +
    4.18 +    public void add(ModificationListener l);
    4.19 +
    4.20 +    public void remove(ModificationListener l);
    4.21 +    
    4.22 +}
     5.1 --- a/samples/openfixed/src/org/apidesign/openfixed/Growable.java	Sun Mar 20 08:12:26 2011 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,19 +0,0 @@
     5.4 -package org.apidesign.openfixed;
     5.5 -
     5.6 -import java.util.List;
     5.7 -import java.util.concurrent.CopyOnWriteArrayList;
     5.8 -
     5.9 -/** Sample bean using the {@link GrowingListener}.
    5.10 - *
    5.11 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.12 - */
    5.13 -public final class Growable {
    5.14 -    private List<GrowingListener> listeners = new CopyOnWriteArrayList<GrowingListener>();
    5.15 -    
    5.16 -    public void addGrowingListener(GrowingListener l) {
    5.17 -        listeners.add(l);
    5.18 -    }
    5.19 -    public void removeGrowingListener(GrowingListener l) {
    5.20 -        listeners.remove(l);
    5.21 -    }
    5.22 -}
     6.1 --- a/samples/openfixed/src/org/apidesign/openfixed/GrowingEvent.java	Sun Mar 20 08:12:26 2011 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,25 +0,0 @@
     6.4 -package org.apidesign.openfixed;
     6.5 -
     6.6 -import java.util.EventObject;
     6.7 -
     6.8 -// BEGIN: openfixed.event
     6.9 -public final class GrowingEvent extends EventObject {
    6.10 -    public GrowingEvent(Object source) {
    6.11 -        super(source);
    6.12 -    }
    6.13 -// FINISH: openfixed.event
    6.14 -    
    6.15 -// BEGIN: openfixed.addgetter    
    6.16 -    private int index;
    6.17 -    /** @since 2.0 */
    6.18 -    public GrowingEvent(Object source, int index) {
    6.19 -        super(source);
    6.20 -        this.index = index;
    6.21 -    }
    6.22 -
    6.23 -    /** @since 2.0 */
    6.24 -    public int getIndex() {
    6.25 -        return index;
    6.26 -    }
    6.27 -// END: openfixed.addgetter    
    6.28 -}
     7.1 --- a/samples/openfixed/src/org/apidesign/openfixed/GrowingListener.java	Sun Mar 20 08:12:26 2011 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,9 +0,0 @@
     7.4 -package org.apidesign.openfixed;
     7.5 -
     7.6 -import java.util.EventListener;
     7.7 -
     7.8 -// BEGIN: openfixed.listener
     7.9 -public interface GrowingListener extends EventListener {
    7.10 -    public void response(GrowingEvent ev);
    7.11 -}
    7.12 -// FINISH: openfixed.listener
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/ModificationEvent.java	Sun Mar 20 18:52:47 2011 +0100
     8.3 @@ -0,0 +1,35 @@
     8.4 +package org.apidesign.openfixed;
     8.5 +
     8.6 +import java.util.Collection;
     8.7 +import java.util.EventObject;
     8.8 +
     8.9 +// BEGIN: openfixed.event
    8.10 +public final class ModificationEvent extends EventObject {
    8.11 +    private final int delta;
    8.12 +    ModificationEvent(Object source, int delta) {
    8.13 +        super(source);
    8.14 +        this.delta = delta;
    8.15 +    }
    8.16 +    
    8.17 +    public int getChange() {
    8.18 +        return delta;
    8.19 +    }
    8.20 +    
    8.21 +// FINISH: openfixed.event
    8.22 +    
    8.23 +// BEGIN: openfixed.addgetter    
    8.24 +    int pending;
    8.25 +    /** @since 2.0 */
    8.26 +    public int getPending() {
    8.27 +        return pending;
    8.28 +    }
    8.29 +// END: openfixed.addgetter    
    8.30 +    
    8.31 +// BEGIN: openfixed.mount
    8.32 +    Collection<PostModificationListener> posts;
    8.33 +    /** @since 3.0 */
    8.34 +    public void postProcess(PostModificationListener p) {
    8.35 +        posts.add(p);
    8.36 +    }
    8.37 +// END: openfixed.mount  
    8.38 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/ModificationListener.java	Sun Mar 20 18:52:47 2011 +0100
     9.3 @@ -0,0 +1,9 @@
     9.4 +package org.apidesign.openfixed;
     9.5 +
     9.6 +import java.util.EventListener;
     9.7 +
     9.8 +// BEGIN: openfixed.listener
     9.9 +public interface ModificationListener extends EventListener {
    9.10 +    public void modification(ModificationEvent ev);
    9.11 +}
    9.12 +// FINISH: openfixed.listener
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/PendingEventSupport.java	Sun Mar 20 18:52:47 2011 +0100
    10.3 @@ -0,0 +1,67 @@
    10.4 +package org.apidesign.openfixed;
    10.5 +
    10.6 +import java.util.List;
    10.7 +import java.util.concurrent.CopyOnWriteArrayList;
    10.8 +import java.util.concurrent.Executor;
    10.9 +import java.util.concurrent.Executors;
   10.10 +
   10.11 +/**
   10.12 + *
   10.13 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   10.14 + */
   10.15 +final class PendingEventSupport implements EventSupport, Runnable {
   10.16 +    private final List<ModificationListener> listeners = new CopyOnWriteArrayList<ModificationListener>();
   10.17 +    private final List<Deliverable> deliverables = new CopyOnWriteArrayList<Deliverable>();
   10.18 +    private static final Executor EXEC = Executors.newSingleThreadExecutor();
   10.19 +    
   10.20 +    PendingEventSupport() {
   10.21 +    }
   10.22 +
   10.23 +    @Override
   10.24 +    public void fireModificationEvent(ModificationEvent ev) {
   10.25 +        synchronized (deliverables) {
   10.26 +            final Deliverable d = new Deliverable(ev, listeners.toArray(new ModificationListener[0]));
   10.27 +            deliverables.add(d);
   10.28 +            EXEC.execute(this);
   10.29 +        }
   10.30 +    }
   10.31 +
   10.32 +    @Override
   10.33 +    public void add(ModificationListener l) {
   10.34 +        listeners.add(l);
   10.35 +    }
   10.36 +
   10.37 +    @Override
   10.38 +    public void remove(ModificationListener l) {
   10.39 +        listeners.remove(l);
   10.40 +    }
   10.41 +
   10.42 +    @Override
   10.43 +    public void run() {
   10.44 +        Deliverable[] pending;
   10.45 +        synchronized (deliverables) {
   10.46 +            if (deliverables.isEmpty()) {
   10.47 +                return;
   10.48 +            }
   10.49 +            pending = deliverables.toArray(new Deliverable[0]);
   10.50 +            deliverables.clear();
   10.51 +        }
   10.52 +        int pendingCount = pending.length;
   10.53 +        for (Deliverable d : pending) {
   10.54 +            d.ev.pending = --pendingCount;
   10.55 +            for (ModificationListener l : d.listeners) {
   10.56 +                l.modification(d.ev);
   10.57 +            }
   10.58 +        }
   10.59 +    }
   10.60 +    
   10.61 +    private static class Deliverable {
   10.62 +        final ModificationEvent ev;
   10.63 +        final ModificationListener[] listeners;
   10.64 +
   10.65 +        public Deliverable(ModificationEvent ev, ModificationListener[] listeners) {
   10.66 +            this.ev = ev;
   10.67 +            this.listeners = listeners;
   10.68 +        }
   10.69 +    }
   10.70 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/PostEventSupport.java	Sun Mar 20 18:52:47 2011 +0100
    11.3 @@ -0,0 +1,78 @@
    11.4 +package org.apidesign.openfixed;
    11.5 +
    11.6 +import java.util.HashSet;
    11.7 +import java.util.List;
    11.8 +import java.util.Set;
    11.9 +import java.util.concurrent.CopyOnWriteArrayList;
   11.10 +import java.util.concurrent.Executor;
   11.11 +import java.util.concurrent.Executors;
   11.12 +
   11.13 +/**
   11.14 + *
   11.15 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   11.16 + */
   11.17 +final class PostEventSupport implements EventSupport, Runnable {
   11.18 +    private final List<ModificationListener> listeners = new CopyOnWriteArrayList<ModificationListener>();
   11.19 +    private final List<Deliverable> deliverables = new CopyOnWriteArrayList<Deliverable>();
   11.20 +    private static final Executor EXEC = Executors.newSingleThreadExecutor();
   11.21 +    
   11.22 +    PostEventSupport() {
   11.23 +    }
   11.24 +
   11.25 +    @Override
   11.26 +    public void fireModificationEvent(ModificationEvent ev) {
   11.27 +        synchronized (deliverables) {
   11.28 +            final Deliverable d = new Deliverable(ev, listeners.toArray(new ModificationListener[0]));
   11.29 +            deliverables.add(d);
   11.30 +            EXEC.execute(this);
   11.31 +        }
   11.32 +    }
   11.33 +
   11.34 +    @Override
   11.35 +    public void add(ModificationListener l) {
   11.36 +        listeners.add(l);
   11.37 +    }
   11.38 +
   11.39 +    @Override
   11.40 +    public void remove(ModificationListener l) {
   11.41 +        listeners.remove(l);
   11.42 +    }
   11.43 +
   11.44 +    @Override
   11.45 +    public void run() {
   11.46 +        Deliverable[] pending;
   11.47 +        synchronized (deliverables) {
   11.48 +            if (deliverables.isEmpty()) {
   11.49 +                return;
   11.50 +            }
   11.51 +            pending = deliverables.toArray(new Deliverable[0]);
   11.52 +            deliverables.clear();
   11.53 +        }
   11.54 +        Calculator calc = null;
   11.55 +        Set<PostModificationListener> notify = new HashSet<PostModificationListener>();
   11.56 +        int pendingCount = pending.length;
   11.57 +        for (Deliverable d : pending) {
   11.58 +            calc = (Calculator)d.ev.getSource();
   11.59 +            d.ev.pending = --pendingCount;
   11.60 +            d.ev.posts = notify;
   11.61 +            for (ModificationListener l : d.listeners) {
   11.62 +                l.modification(d.ev);
   11.63 +            }
   11.64 +            d.ev.posts = null;
   11.65 +        }
   11.66 +        
   11.67 +        for (PostModificationListener pml : notify) {
   11.68 +            pml.postProcess(new PostModificationEvent(calc));
   11.69 +        }
   11.70 +    }
   11.71 +    
   11.72 +    private static class Deliverable {
   11.73 +        final ModificationEvent ev;
   11.74 +        final ModificationListener[] listeners;
   11.75 +
   11.76 +        public Deliverable(ModificationEvent ev, ModificationListener[] listeners) {
   11.77 +            this.ev = ev;
   11.78 +            this.listeners = listeners;
   11.79 +        }
   11.80 +    }
   11.81 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/PostModificationEvent.java	Sun Mar 20 18:52:47 2011 +0100
    12.3 @@ -0,0 +1,14 @@
    12.4 +/*
    12.5 + * To change this template, choose Tools | Templates
    12.6 + * and open the template in the editor.
    12.7 + */
    12.8 +package org.apidesign.openfixed;
    12.9 +
   12.10 +import java.util.EventObject;
   12.11 +// BEGIN: openfixed.postevent
   12.12 +public final class PostModificationEvent extends EventObject {
   12.13 +    PostModificationEvent(Calculator calc) {
   12.14 +        super(calc);
   12.15 +    }
   12.16 +}
   12.17 +// END: openfixed.postevent
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/PostModificationListener.java	Sun Mar 20 18:52:47 2011 +0100
    13.3 @@ -0,0 +1,9 @@
    13.4 +package org.apidesign.openfixed;
    13.5 +
    13.6 +import java.util.EventListener;
    13.7 +
    13.8 +// BEGIN: openfixed.postprocessor
    13.9 +public interface PostModificationListener extends EventListener {
   13.10 +    public void postProcess(PostModificationEvent ev);
   13.11 +}
   13.12 +// END: openfixed.postprocessor
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/samples/openfixed/src/org/apidesign/openfixed/TrivialEventSupport.java	Sun Mar 20 18:52:47 2011 +0100
    14.3 @@ -0,0 +1,37 @@
    14.4 +/*
    14.5 + * To change this template, choose Tools | Templates
    14.6 + * and open the template in the editor.
    14.7 + */
    14.8 +package org.apidesign.openfixed;
    14.9 +
   14.10 +import java.util.List;
   14.11 +import java.util.concurrent.CopyOnWriteArrayList;
   14.12 +
   14.13 +/**
   14.14 + *
   14.15 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   14.16 + */
   14.17 +final class TrivialEventSupport implements EventSupport {
   14.18 +    List<ModificationListener> listener = new CopyOnWriteArrayList<ModificationListener>();
   14.19 +    
   14.20 +    TrivialEventSupport() {
   14.21 +    }
   14.22 +
   14.23 +    @Override
   14.24 +    public void fireModificationEvent(ModificationEvent ev) {
   14.25 +        for (ModificationListener l : listener) {
   14.26 +            l.modification(ev);
   14.27 +        }
   14.28 +    }
   14.29 +
   14.30 +    @Override
   14.31 +    public void add(ModificationListener l) {
   14.32 +        listener.add(l);
   14.33 +    }
   14.34 +
   14.35 +    @Override
   14.36 +    public void remove(ModificationListener l) {
   14.37 +        listener.remove(l);
   14.38 +    }
   14.39 +    
   14.40 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/samples/openfixed/test/org/apidesign/openfixed/AsyncTest.java	Sun Mar 20 18:52:47 2011 +0100
    15.3 @@ -0,0 +1,18 @@
    15.4 +package org.apidesign.openfixed;
    15.5 +
    15.6 +/** Test the Calculator.createAsynch() behavior.
    15.7 + *
    15.8 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    15.9 + */
   15.10 +public final class AsyncTest extends CalculatorBase {
   15.11 +    
   15.12 +    public AsyncTest(String testName) {
   15.13 +        super(testName);
   15.14 +    }
   15.15 +
   15.16 +    @Override
   15.17 +    protected Calculator create() {
   15.18 +        return Calculator.createAsynch();
   15.19 +    }
   15.20 +
   15.21 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/samples/openfixed/test/org/apidesign/openfixed/BasicTest.java	Sun Mar 20 18:52:47 2011 +0100
    16.3 @@ -0,0 +1,16 @@
    16.4 +package org.apidesign.openfixed;
    16.5 +
    16.6 +/** Test the Calculator.create() behavior.
    16.7 + *
    16.8 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    16.9 + */
   16.10 +public final class BasicTest extends CalculatorBase {
   16.11 +    public BasicTest(String testName) {
   16.12 +        super(testName);
   16.13 +    }
   16.14 +
   16.15 +    @Override
   16.16 +    protected Calculator create() {
   16.17 +        return Calculator.create();
   16.18 +    }
   16.19 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/samples/openfixed/test/org/apidesign/openfixed/CalculatorBase.java	Sun Mar 20 18:52:47 2011 +0100
    17.3 @@ -0,0 +1,64 @@
    17.4 +package org.apidesign.openfixed;
    17.5 +
    17.6 +import java.util.ArrayList;
    17.7 +import java.util.List;
    17.8 +import junit.framework.TestCase;
    17.9 +
   17.10 +public abstract class CalculatorBase extends TestCase {
   17.11 +    
   17.12 +    public CalculatorBase(String testName) {
   17.13 +        super(testName);
   17.14 +    }
   17.15 +    
   17.16 +    protected abstract Calculator create();
   17.17 +
   17.18 +    public void testSumAndListeners() throws Exception {
   17.19 +        Calculator a = create();
   17.20 +        MockListener l = new MockListener();
   17.21 +        a.addModificationListener(l);
   17.22 +        a.add(5);
   17.23 +        a.add(10);
   17.24 +        a.add(20);
   17.25 +        int ch = allChanges(l.assertEvents("Three changes", 3));
   17.26 +        assertEquals("35 was the change", 35, ch);
   17.27 +        assertEquals("Current value", 35, a.getSum());
   17.28 +        a.add(-5);
   17.29 +        int ch2 = allChanges(l.assertEvents("One change", 1));
   17.30 +        assertEquals("minus five was the change", -5, ch2);
   17.31 +        assertEquals("Final value", 30, a.getSum());
   17.32 +    }
   17.33 +    
   17.34 +    private static int allChanges(List<ModificationEvent> events) {
   17.35 +        int changes = 0;
   17.36 +        for (ModificationEvent me : events) {
   17.37 +            changes += me.getChange();
   17.38 +        }
   17.39 +        return changes;
   17.40 +    }
   17.41 +    
   17.42 +    public static class MockListener implements ModificationListener {
   17.43 +        private List<ModificationEvent> events;
   17.44 +        
   17.45 +        @Override
   17.46 +        public synchronized void modification(ModificationEvent ev) {
   17.47 +            if (events == null) {
   17.48 +                events = new ArrayList<ModificationEvent>();
   17.49 +            }
   17.50 +            events.add(ev);
   17.51 +        }
   17.52 +        
   17.53 +        public synchronized List<ModificationEvent> assertEvents(String msg, int cnt) 
   17.54 +        throws InterruptedException {
   17.55 +            for (int i = 0; i < 10; i++) {
   17.56 +                if (events != null && events.size() >= cnt) {
   17.57 +                    break;
   17.58 +                }
   17.59 +                wait(1000);
   17.60 +            }
   17.61 +            assertEquals(msg + ":\n" + events, cnt, events.size());
   17.62 +            List<ModificationEvent> res = events;
   17.63 +            events = null;
   17.64 +            return res;
   17.65 +        }
   17.66 +    } // end of ModificationListener
   17.67 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/samples/openfixed/test/org/apidesign/openfixed/PendingTest.java	Sun Mar 20 18:52:47 2011 +0100
    18.3 @@ -0,0 +1,60 @@
    18.4 +package org.apidesign.openfixed;
    18.5 +
    18.6 +import java.util.List;
    18.7 +import java.util.concurrent.CountDownLatch;
    18.8 +
    18.9 +/** Test the Calculator.createPending() behavior.
   18.10 + *
   18.11 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   18.12 + */
   18.13 +public class PendingTest extends CalculatorBase {
   18.14 +    
   18.15 +    public PendingTest(String testName) {
   18.16 +        super(testName);
   18.17 +    }
   18.18 +
   18.19 +    @Override
   18.20 +    protected Calculator create() {
   18.21 +        return Calculator.createPending();
   18.22 +    }
   18.23 +
   18.24 +    public void testPendingEvents() throws Exception {
   18.25 +        BlockingListener bl = new BlockingListener();
   18.26 +        
   18.27 +        Calculator calc = create();
   18.28 +        calc.addModificationListener(bl);
   18.29 +        
   18.30 +        calc.add(10);
   18.31 +        bl.first.await();
   18.32 +        
   18.33 +        calc.add(1);
   18.34 +        calc.add(2);
   18.35 +        calc.add(3);
   18.36 +        
   18.37 +        bl.cdl.countDown();
   18.38 +        
   18.39 +        List<ModificationEvent> events = bl.assertEvents("Four changes together", 4);
   18.40 +        
   18.41 +        assertEquals("No pending events for first event", 0, events.get(0).getPending());
   18.42 +        assertEquals("Group of three, two remaining", 2, events.get(1).getPending());
   18.43 +        assertEquals("Group of three, one remaining", 1, events.get(2).getPending());
   18.44 +        assertEquals("Group of three, last one", 0, events.get(3).getPending());
   18.45 +    }
   18.46 +    
   18.47 +    static class BlockingListener extends MockListener {
   18.48 +        CountDownLatch first = new CountDownLatch(1);
   18.49 +        CountDownLatch cdl = new CountDownLatch(1);
   18.50 +
   18.51 +        @Override
   18.52 +        public synchronized void modification(ModificationEvent ev) {
   18.53 +            try {
   18.54 +                first.countDown();
   18.55 +                cdl.await();
   18.56 +            } catch (InterruptedException ex) {
   18.57 +                throw new IllegalStateException(ex);
   18.58 +            }
   18.59 +            super.modification(ev);
   18.60 +        }
   18.61 +    }
   18.62 +    
   18.63 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/samples/openfixed/test/org/apidesign/openfixed/PostTest.java	Sun Mar 20 18:52:47 2011 +0100
    19.3 @@ -0,0 +1,62 @@
    19.4 +package org.apidesign.openfixed;
    19.5 +
    19.6 +import java.util.concurrent.CountDownLatch;
    19.7 +
    19.8 +/** Test the Calculator.createPending() behavior.
    19.9 + *
   19.10 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   19.11 + */
   19.12 +public final class PostTest extends PendingTest {
   19.13 +    
   19.14 +    public PostTest(String testName) {
   19.15 +        super(testName);
   19.16 +    }
   19.17 +
   19.18 +    @Override
   19.19 +    protected Calculator create() {
   19.20 +        return Calculator.createBatch();
   19.21 +    }
   19.22 +
   19.23 +    public void testPostModificationEvents() throws Exception {
   19.24 +        class PostListener extends BlockingListener implements PostModificationListener {
   19.25 +            int cnt;
   19.26 +
   19.27 +            @Override
   19.28 +            public synchronized void modification(ModificationEvent ev) {
   19.29 +                // registers for callback when batch processing is over:
   19.30 +                ev.postProcess(this);
   19.31 +                super.modification(ev);
   19.32 +            }
   19.33 +
   19.34 +            @Override
   19.35 +            public synchronized void postProcess(PostModificationEvent ev) {
   19.36 +                cnt++;
   19.37 +            }
   19.38 +            
   19.39 +            public synchronized void assertPostProcess(String msg, int expected) throws InterruptedException {
   19.40 +                for (int i = 0; i < 10; i++) {
   19.41 +                    if (cnt >= expected) {
   19.42 +                        break;
   19.43 +                    }
   19.44 +                    wait(1000);
   19.45 +                }
   19.46 +                assertEquals(msg, expected, cnt);
   19.47 +                cnt = 0;
   19.48 +            }
   19.49 +        }
   19.50 +        PostListener bl = new PostListener();
   19.51 +        
   19.52 +        Calculator calc = create();
   19.53 +        calc.addModificationListener(bl);
   19.54 +        
   19.55 +        calc.add(10);
   19.56 +        bl.first.await();
   19.57 +        
   19.58 +        calc.add(1);
   19.59 +        calc.add(2);
   19.60 +        calc.add(3);
   19.61 +        
   19.62 +        bl.cdl.countDown();
   19.63 +        bl.assertPostProcess("Two postprocessings (one for 10), then for the rest", 2);
   19.64 +    }
   19.65 +}