json/src/main/java/org/netbeans/html/json/spi/Observers.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 785 json/src/main/java/org/apidesign/html/json/spi/Observers.java@929f1192819c
child 1092 9329156bb5d4
permissions -rw-r--r--
During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
jtulach@774
     1
/**
jtulach@774
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jtulach@774
     3
 *
jtulach@774
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jtulach@774
     5
 *
jtulach@774
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jtulach@774
     7
 * Other names may be trademarks of their respective owners.
jtulach@774
     8
 *
jtulach@774
     9
 * The contents of this file are subject to the terms of either the GNU
jtulach@774
    10
 * General Public License Version 2 only ("GPL") or the Common
jtulach@774
    11
 * Development and Distribution License("CDDL") (collectively, the
jtulach@774
    12
 * "License"). You may not use this file except in compliance with the
jtulach@774
    13
 * License. You can obtain a copy of the License at
jtulach@774
    14
 * http://www.netbeans.org/cddl-gplv2.html
jtulach@774
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jtulach@774
    16
 * specific language governing permissions and limitations under the
jtulach@774
    17
 * License.  When distributing the software, include this License Header
jtulach@774
    18
 * Notice in each file and include the License file at
jtulach@774
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jtulach@774
    20
 * particular file as subject to the "Classpath" exception as provided
jtulach@774
    21
 * by Oracle in the GPL Version 2 section of the License file that
jtulach@774
    22
 * accompanied this code. If applicable, add the following below the
jtulach@774
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jtulach@774
    24
 * your own identifying information:
jtulach@774
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jtulach@774
    26
 *
jtulach@774
    27
 * Contributor(s):
jtulach@774
    28
 *
jtulach@774
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jtulach@774
    30
 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
jtulach@774
    31
 *
jtulach@774
    32
 * If you wish your version of this file to be governed by only the CDDL
jtulach@774
    33
 * or only the GPL Version 2, indicate your decision by adding
jtulach@774
    34
 * "[Contributor] elects to include this software in this distribution
jtulach@774
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jtulach@774
    36
 * single choice of license, a recipient has the option to distribute
jtulach@774
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jtulach@774
    38
 * to extend the choice of license to its licensees as provided above.
jtulach@774
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jtulach@774
    40
 * Version 2 license, then the option applies only if the new code is
jtulach@774
    41
 * made subject to such option by the copyright holder.
jtulach@774
    42
 */
jtulach@838
    43
package org.netbeans.html.json.spi;
jtulach@774
    44
jtulach@774
    45
import java.lang.ref.WeakReference;
jtulach@782
    46
import java.util.ArrayList;
jtulach@782
    47
import java.util.Iterator;
jtulach@782
    48
import java.util.LinkedList;
jtulach@782
    49
import java.util.List;
jtulach@774
    50
jtulach@774
    51
/**
jtulach@774
    52
 *
jtulach@774
    53
 * @author Jaroslav Tulach
jtulach@774
    54
 */
jtulach@783
    55
final class Observers {
jtulach@782
    56
    private static final LinkedList<Watcher> GLOBAL = new LinkedList<Watcher>();
jtulach@783
    57
    private final List<Watcher> watchers = new ArrayList<Watcher>();
jtulach@783
    58
    private final List<Ref> observers = new ArrayList<Ref>();
jtulach@775
    59
jtulach@785
    60
    Observers() {
jtulach@785
    61
        assert Thread.holdsLock(GLOBAL);
jtulach@774
    62
    }
jtulach@774
    63
    
jtulach@778
    64
    static void beginComputing(Proto p, String name) {
jtulach@782
    65
        synchronized (GLOBAL) {
jtulach@782
    66
            verifyUnlocked(p);
jtulach@778
    67
            final Watcher nw = new Watcher(p, name);
jtulach@782
    68
            GLOBAL.push(nw);
jtulach@778
    69
        }
jtulach@778
    70
    }
jtulach@778
    71
    
jtulach@778
    72
    static void verifyUnlocked(Proto p) {
jtulach@782
    73
        synchronized (GLOBAL) {
jtulach@782
    74
            for (Watcher w : GLOBAL) {
jtulach@782
    75
                if (w.proto == p) {
jtulach@782
    76
                    throw new IllegalStateException("Re-entrant attempt to access " + p);
jtulach@782
    77
                }
jtulach@778
    78
            }
jtulach@778
    79
        }        
jtulach@778
    80
    }
jtulach@778
    81
jtulach@785
    82
    static void accessingValue(Proto p, String propName) {
jtulach@782
    83
        synchronized (GLOBAL) {
jtulach@782
    84
            verifyUnlocked(p);
jtulach@782
    85
            for (Watcher w : GLOBAL) {
jtulach@785
    86
                Observers mine = p.observers(true);
jtulach@785
    87
                mine.add(w, new Ref(w, propName));
jtulach@778
    88
            }
jtulach@778
    89
        }
jtulach@778
    90
    }
jtulach@778
    91
    
jtulach@785
    92
    static void finishComputing(Proto p) {
jtulach@782
    93
        synchronized (GLOBAL) {
jtulach@782
    94
            Watcher w = GLOBAL.pop();
jtulach@778
    95
            if (w.proto != p) {
jtulach@778
    96
                throw new IllegalStateException("Inconsistency: " + w.proto + " != " + p);
jtulach@778
    97
            }
jtulach@784
    98
            if (w.prop != null) {
jtulach@785
    99
                Observers mine = p.observers(true);
jtulach@784
   100
                mine.add(w);
jtulach@778
   101
            }
jtulach@776
   102
        }
jtulach@775
   103
    }
jtulach@774
   104
    
jtulach@782
   105
    private static final class Ref extends WeakReference<Watcher> {
jtulach@774
   106
        private final String prop;
jtulach@774
   107
        
jtulach@774
   108
        public Ref(Watcher ref, String prop) {
jtulach@774
   109
            super(ref);
jtulach@774
   110
            this.prop = prop;
jtulach@774
   111
        }
jtulach@774
   112
        
jtulach@782
   113
        final Watcher watcher() {
jtulach@774
   114
            Watcher w = get();
jtulach@783
   115
            if (w == null) {
jtulach@783
   116
                return null;
jtulach@783
   117
            }
jtulach@785
   118
            final Observers o = w.proto.observers(false);
jtulach@783
   119
            if (o == null) {
jtulach@783
   120
                return null;
jtulach@783
   121
            }
jtulach@783
   122
            if (o.find(w.prop) == w) {
jtulach@774
   123
                return w;
jtulach@774
   124
            }
jtulach@774
   125
            return null;
jtulach@774
   126
        }
jtulach@782
   127
    }
jtulach@782
   128
    
jtulach@783
   129
    private Watcher find(String prop) {
jtulach@783
   130
        if (prop == null) {
jtulach@782
   131
            return null;
jtulach@782
   132
        }
jtulach@783
   133
        for (Watcher w : watchers) {
jtulach@783
   134
            if (prop.equals(w.prop)) {
jtulach@783
   135
                return w;
jtulach@783
   136
            }
jtulach@783
   137
        }
jtulach@783
   138
        return null;
jtulach@783
   139
    }
jtulach@782
   140
jtulach@782
   141
        final void add(Watcher w) {
jtulach@783
   142
        for (int i = 0; i < watchers.size(); i++) {
jtulach@783
   143
            Watcher ith = watchers.get(i);
jtulach@783
   144
            if (w.prop == null) {
jtulach@783
   145
                if (ith.prop == null) {
jtulach@782
   146
                    watchers.set(i, w);
jtulach@782
   147
                    return;
jtulach@782
   148
                }
jtulach@783
   149
            } else if (w.prop.equals(ith.prop)) {
jtulach@783
   150
                watchers.set(i, w);
jtulach@783
   151
                return;
jtulach@782
   152
            }
jtulach@782
   153
        }
jtulach@783
   154
        watchers.add(w);
jtulach@782
   155
    }
jtulach@782
   156
jtulach@785
   157
    static final void valueHasMutated(Proto p, String propName) {
jtulach@783
   158
        List<Watcher> mutated = new LinkedList<Watcher>();
jtulach@783
   159
        synchronized (GLOBAL) {
jtulach@785
   160
            Observers mine = p.observers(false);
jtulach@785
   161
            if (mine == null) {
jtulach@785
   162
                return;
jtulach@785
   163
            }
jtulach@785
   164
            Iterator<Ref> it = mine.observers.iterator();
jtulach@783
   165
            while (it.hasNext()) {
jtulach@783
   166
                Ref ref = it.next();
jtulach@783
   167
                if (ref.get() == null) {
jtulach@783
   168
                    it.remove();
jtulach@783
   169
                    continue;
jtulach@783
   170
                }
jtulach@783
   171
                if (ref.prop.equals(propName)) {
jtulach@783
   172
                    Watcher w = ref.watcher();
jtulach@783
   173
                    if (w != null) {
jtulach@783
   174
                        mutated.add(w);
jtulach@774
   175
                    }
jtulach@774
   176
                }
jtulach@774
   177
            }
jtulach@783
   178
        }
jtulach@785
   179
        for (Watcher w : mutated) {
jtulach@783
   180
            w.proto.valueHasMutated(w.prop);
jtulach@783
   181
        }
jtulach@783
   182
    }
jtulach@783
   183
jtulach@785
   184
    void add(Watcher w, Ref r) {
jtulach@783
   185
        Thread.holdsLock(GLOBAL);
jtulach@783
   186
        if (w == null) {
jtulach@783
   187
            return;
jtulach@783
   188
        }
jtulach@783
   189
        Iterator<Ref> it = observers.iterator();
jtulach@783
   190
        while (it.hasNext()) {
jtulach@783
   191
            Ref ref = it.next();
jtulach@783
   192
            if (r == ref) {
jtulach@783
   193
                return;
jtulach@783
   194
            }
jtulach@783
   195
            final Watcher rw = ref.get();
jtulach@783
   196
            if (rw == null) {
jtulach@783
   197
                it.remove();
jtulach@783
   198
                continue;
jtulach@783
   199
            }
jtulach@783
   200
            if (rw == w && r.prop.equals(r.prop)) {
jtulach@783
   201
                return;
jtulach@782
   202
            }
jtulach@774
   203
        }
jtulach@783
   204
        observers.add(r);
jtulach@783
   205
    }
jtulach@783
   206
    
jtulach@783
   207
    private static final class Watcher {
jtulach@783
   208
        final Proto proto;
jtulach@783
   209
        final String prop;
jtulach@774
   210
jtulach@783
   211
        Watcher(Proto proto, String prop) {
jtulach@783
   212
            this.proto = proto;
jtulach@783
   213
            this.prop = prop;
jtulach@783
   214
        }
jtulach@783
   215
        
jtulach@783
   216
        @Override
jtulach@783
   217
        public String toString() {
jtulach@783
   218
            return "Watcher: " + proto + ", " + prop;
jtulach@774
   219
        }
jtulach@774
   220
    }
jtulach@774
   221
}