Using classical java.util classes minimizes the chance I will do mistake when coding linked list myself DeepWatch
authorJaroslav Tulach <jtulach@netbeans.org>
Sat, 02 Aug 2014 06:25:53 +0200
branchDeepWatch
changeset 782f4c0dced6c48
parent 781 9b959ca6ef6d
child 783 991345150b99
Using classical java.util classes minimizes the chance I will do mistake when coding linked list myself
json/src/main/java/org/apidesign/html/json/spi/Proto.java
json/src/main/java/org/apidesign/html/json/spi/Watcher.java
     1.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java	Fri Aug 01 17:13:23 2014 +0200
     1.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Proto.java	Sat Aug 02 06:25:53 2014 +0200
     1.3 @@ -47,6 +47,8 @@
     1.4  import net.java.html.BrwsrCtx;
     1.5  import net.java.html.json.ComputedProperty;
     1.6  import net.java.html.json.Model;
     1.7 +import org.apidesign.html.json.spi.Watcher.Observers;
     1.8 +import org.apidesign.html.json.spi.Watcher.Watchers;
     1.9  import org.netbeans.html.json.impl.Bindings;
    1.10  import org.netbeans.html.json.impl.JSON;
    1.11  import org.netbeans.html.json.impl.JSONList;
    1.12 @@ -69,8 +71,8 @@
    1.13      private final Type type;
    1.14      private final net.java.html.BrwsrCtx context;
    1.15      private org.netbeans.html.json.impl.Bindings ko;
    1.16 -    private Watcher mine;
    1.17 -    private Watcher.Ref observers;
    1.18 +    private Watchers mine;
    1.19 +    private Observers observers;
    1.20  
    1.21      Proto(Object obj, Type type, BrwsrCtx context) {
    1.22          this.obj = obj;
    1.23 @@ -132,7 +134,7 @@
    1.24                      ko.valueHasMutated(propName, null, null);
    1.25                  }
    1.26                  if (observers != null) {
    1.27 -                    observers = Watcher.Ref.valueHasMutated(observers, propName);
    1.28 +                    observers.valueHasMutated(propName);
    1.29                  }
    1.30              }
    1.31          });
    1.32 @@ -162,7 +164,7 @@
    1.33                      ko.valueHasMutated(propName, oldValue, newValue);
    1.34                  }
    1.35                  if (observers != null) {
    1.36 -                    observers = Watcher.Ref.valueHasMutated(observers, propName);
    1.37 +                    observers.valueHasMutated(propName);
    1.38                  }
    1.39              }
    1.40          });
    1.41 @@ -456,7 +458,7 @@
    1.42      }
    1.43  
    1.44      final Watcher watcher(String prop) {
    1.45 -        return Watcher.find(mine, null, prop);
    1.46 +        return mine == null ? null : mine.find(prop);
    1.47      }
    1.48  
    1.49      /** Functionality used by the code generated by annotation
     2.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Watcher.java	Fri Aug 01 17:13:23 2014 +0200
     2.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Watcher.java	Sat Aug 02 06:25:53 2014 +0200
     2.3 @@ -43,18 +43,20 @@
     2.4  package org.apidesign.html.json.spi;
     2.5  
     2.6  import java.lang.ref.WeakReference;
     2.7 +import java.util.ArrayList;
     2.8 +import java.util.Iterator;
     2.9 +import java.util.LinkedList;
    2.10 +import java.util.List;
    2.11  
    2.12  /**
    2.13   *
    2.14   * @author Jaroslav Tulach
    2.15   */
    2.16  final class Watcher {
    2.17 -    private static final Object LOCK = new Object();
    2.18 -    private static Watcher global;
    2.19 +    private static final LinkedList<Watcher> GLOBAL = new LinkedList<Watcher>();
    2.20  
    2.21      private final Proto proto;
    2.22      private final String prop;
    2.23 -    private Watcher next;
    2.24  
    2.25      private Watcher(Proto proto, String prop) {
    2.26          this.proto = proto;
    2.27 @@ -62,97 +64,48 @@
    2.28      }
    2.29      
    2.30      static void beginComputing(Proto p, String name) {
    2.31 -        synchronized (LOCK) {
    2.32 -            Watcher alreadyThere = find(global, p, null);
    2.33 -            if (alreadyThere != null) {
    2.34 -                throw new IllegalStateException("Re-entrant attempt to access " + p);
    2.35 -            }
    2.36 +        synchronized (GLOBAL) {
    2.37 +            verifyUnlocked(p);
    2.38              final Watcher nw = new Watcher(p, name);
    2.39 -            nw.next = global;
    2.40 -            global = nw;
    2.41 +            GLOBAL.push(nw);
    2.42          }
    2.43      }
    2.44      
    2.45      static void verifyUnlocked(Proto p) {
    2.46 -        synchronized (LOCK) {
    2.47 -            Watcher alreadyThere = find(global, p, null);
    2.48 -            if (alreadyThere != null) {
    2.49 -                throw new IllegalStateException("Re-entrant attempt to access " + p);
    2.50 +        synchronized (GLOBAL) {
    2.51 +            for (Watcher w : GLOBAL) {
    2.52 +                if (w.proto == p) {
    2.53 +                    throw new IllegalStateException("Re-entrant attempt to access " + p);
    2.54 +                }
    2.55              }
    2.56          }        
    2.57      }
    2.58  
    2.59 -    static Ref accessingValue(Proto p, Ref observers, String propName) {
    2.60 -        synchronized (LOCK) {
    2.61 -            Watcher alreadyThere = find(global, p, null);
    2.62 -            if (alreadyThere != null) {
    2.63 -                throw new IllegalStateException("Re-entrant attempt to access " + p);
    2.64 +    static Observers accessingValue(Proto p, Observers observers, String propName) {
    2.65 +        synchronized (GLOBAL) {
    2.66 +            verifyUnlocked(p);
    2.67 +            for (Watcher w : GLOBAL) {
    2.68 +                if (observers == null) {
    2.69 +                    observers = new Observers();
    2.70 +                }
    2.71 +                observers.add(w, new Ref(w, propName));
    2.72              }
    2.73 -            Watcher w = global;
    2.74 -            for (;;) {
    2.75 -                if (w == null) {
    2.76 -                    return observers;
    2.77 -                }
    2.78 -                observers = w.observe(observers, propName);
    2.79 -                w = w.next;
    2.80 -            }
    2.81 +            return observers;
    2.82          }
    2.83      }
    2.84      
    2.85 -    static Watcher finishComputing(Proto p, Watcher mine) {
    2.86 -        synchronized (LOCK) {
    2.87 -            Watcher w = global;
    2.88 -            global = w.next;
    2.89 -            w.next = null;
    2.90 +    static Watchers finishComputing(Proto p, Watchers mine) {
    2.91 +        synchronized (GLOBAL) {
    2.92 +            Watcher w = GLOBAL.pop();
    2.93              if (w.proto != p) {
    2.94                  throw new IllegalStateException("Inconsistency: " + w.proto + " != " + p);
    2.95              }
    2.96 -            return register(mine, w);
    2.97 -        }
    2.98 -    }
    2.99 -    
   2.100 -    static Watcher find(Watcher first, Proto proto, String prop) {
   2.101 -    //    assert Thread.holdsLock(LOCK);
   2.102 -        for (;;) {
   2.103 -            if (first == null) {
   2.104 -                return null;
   2.105 +            if (mine == null) {
   2.106 +                mine = new Watchers();
   2.107              }
   2.108 -            if (prop != null && prop.equals(first.prop)) {
   2.109 -                return first;
   2.110 -            }
   2.111 -            if (proto != null && proto == first.proto) {
   2.112 -                return first;
   2.113 -            }
   2.114 -            first = first.next;
   2.115 -        }
   2.116 -    }
   2.117 -
   2.118 -    private static Watcher register(Watcher mine, Watcher locked) {
   2.119 -        assert Thread.holdsLock(LOCK);
   2.120 -        if (locked.prop == null) {
   2.121 +            mine.add(w);
   2.122              return mine;
   2.123          }
   2.124 -        if (mine == null) {
   2.125 -            return locked;
   2.126 -        }
   2.127 -        if (locked.prop.equals(mine.prop)) {
   2.128 -            locked.next = mine.next;
   2.129 -            return locked;
   2.130 -        }
   2.131 -        Watcher current = mine;
   2.132 -        for (;;) {
   2.133 -            Watcher next = current.next;
   2.134 -            if (next == null) {
   2.135 -                current.next = locked;
   2.136 -                return mine;
   2.137 -            }
   2.138 -            if (locked.prop.equals(next.prop)) {
   2.139 -                locked.next = next.next;
   2.140 -                current.next = locked;
   2.141 -                return mine;
   2.142 -            }
   2.143 -            current = next;
   2.144 -        }
   2.145      }
   2.146      
   2.147      static Watcher computing(Proto proto, String prop) {
   2.148 @@ -161,71 +114,107 @@
   2.149          return new Watcher(proto, prop);
   2.150      }
   2.151      
   2.152 -    Ref observe(Ref prev, String prop) {
   2.153 -        if (prop == null) {
   2.154 -            return prev;
   2.155 -        }
   2.156 -        return new Ref(this, prop).chain(prev);
   2.157 +    @Override
   2.158 +    public String toString() {
   2.159 +        return "Watcher: " + proto + ", " + prop;
   2.160      }
   2.161  
   2.162 -    @Override
   2.163 -    public String toString() {
   2.164 -        return "Watcher: " + proto + ", " + prop + "\n -> " + next;
   2.165 -    }
   2.166 -
   2.167 -    static final class Ref extends WeakReference<Watcher> {
   2.168 +    private static final class Ref extends WeakReference<Watcher> {
   2.169          private final String prop;
   2.170 -        private Ref next;
   2.171          
   2.172          public Ref(Watcher ref, String prop) {
   2.173              super(ref);
   2.174              this.prop = prop;
   2.175          }
   2.176          
   2.177 -        Ref chain(Ref prev) {
   2.178 -            this.next = dropDead(prev, null);
   2.179 -            return this;
   2.180 -        }
   2.181 -        
   2.182 -        private Watcher watcher() {
   2.183 +        final Watcher watcher() {
   2.184              Watcher w = get();
   2.185              if (w != null && w.proto.watcher(w.prop) == w) {
   2.186                  return w;
   2.187              }
   2.188              return null;
   2.189          }
   2.190 -        
   2.191 -        private static Ref dropDead(Ref self, String fireProp) {
   2.192 -            while (self != null && self.watcher() == null) {
   2.193 -                self = self.next;
   2.194 -            }
   2.195 -            if (self == null) {
   2.196 +    }
   2.197 +    
   2.198 +    static final class Watchers {
   2.199 +        private final List<Watcher> watchers = new ArrayList<Watcher>();
   2.200 +
   2.201 +        Watcher find(String prop) {
   2.202 +            if (prop == null) {
   2.203                  return null;
   2.204              }
   2.205 -            Ref current = self;
   2.206 -            for (;;) {
   2.207 -                Watcher w = current.watcher();
   2.208 -                if (w != null && fireProp != null && fireProp.equals(current.prop)) {
   2.209 -                    w.proto.valueHasMutated(w.prop);
   2.210 +            for (Watcher w : watchers) {
   2.211 +                if (prop.equals(w.prop)) {
   2.212 +                    return w;
   2.213                  }
   2.214 -                for (;;) {
   2.215 -                    Ref next = current.next;
   2.216 -                    if (next == null) {
   2.217 -                        return self;
   2.218 +            }
   2.219 +            return null;
   2.220 +        }
   2.221 +
   2.222 +        final void add(Watcher w) {
   2.223 +            for (int i = 0; i < watchers.size(); i++) {
   2.224 +                Watcher ith = watchers.get(i);
   2.225 +                if (w.prop == null) {
   2.226 +                    if (ith.prop == null) {
   2.227 +                        watchers.set(i, w);
   2.228 +                        return;
   2.229                      }
   2.230 -                    if (next.watcher() != null) {
   2.231 -                        current = next;
   2.232 -                        break;
   2.233 -                    } else {
   2.234 -                        current.next = next.next;
   2.235 +                } else if (w.prop.equals(ith.prop)) {
   2.236 +                    watchers.set(i, w);
   2.237 +                    return;
   2.238 +                }
   2.239 +            }
   2.240 +            watchers.add(w);
   2.241 +        }
   2.242 +    }
   2.243 +    
   2.244 +    static final class Observers {
   2.245 +        private final List<Ref> observers = new ArrayList<Ref>();
   2.246 +
   2.247 +        void valueHasMutated(String propName) {
   2.248 +            List<Watcher> mutated = new LinkedList<Watcher>();
   2.249 +            synchronized (GLOBAL) {
   2.250 +                Iterator<Ref> it = observers.iterator();
   2.251 +                while (it.hasNext()) {
   2.252 +                    Ref ref = it.next();
   2.253 +                    if (ref.get() == null) {
   2.254 +                        it.remove();
   2.255 +                        continue;
   2.256 +                    }
   2.257 +                    if (ref.prop.equals(propName)) {
   2.258 +                        Watcher w = ref.watcher();
   2.259 +                        if (w != null) {
   2.260 +                            mutated.add(w);
   2.261 +                        }
   2.262                      }
   2.263                  }
   2.264              }
   2.265 -            
   2.266 +            for (Watcher w : mutated) {
   2.267 +                w.proto.valueHasMutated(w.prop);
   2.268 +            }
   2.269          }
   2.270  
   2.271 -        static Ref valueHasMutated(Ref self, String propName) {
   2.272 -            return dropDead(self, propName);
   2.273 +        void add(Watcher w, Ref r) {
   2.274 +            Thread.holdsLock(GLOBAL);
   2.275 +            if (w == null) {
   2.276 +                return;
   2.277 +            }
   2.278 +            Iterator<Ref> it = observers.iterator();
   2.279 +            while (it.hasNext()) {
   2.280 +                Ref ref = it.next();
   2.281 +                if (r == ref) {
   2.282 +                    return;
   2.283 +                }
   2.284 +                final Watcher rw = ref.get();
   2.285 +                if (rw == null) {
   2.286 +                    it.remove();
   2.287 +                    continue;
   2.288 +                }
   2.289 +                if (rw == w && r.prop.equals(r.prop)) {
   2.290 +                    return;
   2.291 +                }
   2.292 +            }
   2.293 +            observers.add(r);
   2.294          }
   2.295      }
   2.296  }