This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 56726
Collapse All | Expand All

(-)threaddemo/apps/index/Index.java (-1 / +1 lines)
Lines 46-52 Link Here
46
     * Values are occurrence counts.
46
     * Values are occurrence counts.
47
     * <p>Must be called with lock held, and result may only be accessed with it held.
47
     * <p>Must be called with lock held, and result may only be accessed with it held.
48
     */
48
     */
49
    Map/*<String,int>*/ getData();
49
    Map<String,Integer> getData();
50
    
50
    
51
    /**
51
    /**
52
     * Add a listener to changes in the data.
52
     * Add a listener to changes in the data.
(-)threaddemo/apps/index/IndexApp.java (-6 / +4 lines)
Lines 60-68 Link Here
60
    }
68
    }
61
    
69
    
62
    private void refreshTable() {
70
    private void refreshTable() {
63
        final SortedMap/*<String,int>*/ data = (SortedMap)index.getLock().read(new LockAction() {
71
        final SortedMap<String,Integer> data = index.getLock().read(new LockAction<SortedMap<String,Integer>>() {
64
            public Object run() {
72
            public SortedMap<String,Integer> run() {
65
                return new TreeMap(index.getData());
73
                return new TreeMap<String,Integer>(index.getData());
66
            }
74
            }
67
        });
75
        });
68
        SwingUtilities.invokeLater(new Runnable() {
76
        SwingUtilities.invokeLater(new Runnable() {
Lines 72-80 Link Here
72
                for (int i = 0; i < rows; i++) {
80
                for (int i = 0; i < rows; i++) {
73
                    tableModel.removeRow(0);
81
                    tableModel.removeRow(0);
74
                }
82
                }
75
                Iterator it = data.entrySet().iterator();
83
                for (Map.Entry<String, Integer> entry : data.entrySet()) {
76
                while (it.hasNext()) {
77
                    Map.Entry entry = (Map.Entry)it.next();
78
                    tableModel.addRow(new Object[] {
84
                    tableModel.addRow(new Object[] {
79
                        entry.getKey(),
85
                        entry.getKey(),
80
                        entry.getValue(),
86
                        entry.getValue(),
(-)threaddemo/apps/index/IndexImpl.java (-49 / +35 lines)
Lines 37-48 Link Here
37
    private static final Logger logger = Logger.getLogger(IndexImpl.class.getName());
48
    private static final Logger logger = Logger.getLogger(IndexImpl.class.getName());
38
    
49
    
39
    private final Phadhail root;
50
    private final Phadhail root;
40
    private final List/*<ChangeListener>*/ listeners = new ArrayList();
51
    private final List<ChangeListener> listeners = new ArrayList<ChangeListener>();
41
    private boolean running = false;
52
    private boolean running = false;
42
    private final LinkedList/*<Phadhail>*/ toProcess = new LinkedList();
53
    private final LinkedList<Phadhail> toProcess = new LinkedList<Phadhail>();
43
    private final Map/*<Phadhail,Map<String,int>>*/ processed = new /*Weak*/HashMap();
54
    private final Map<Phadhail, Map<String, Integer>> processed = new /*Weak*/HashMap<Phadhail,Map<String,Integer>>();
44
    private final Map/*<DomProvider,Phadhail>*/ domProviders2Phadhails = new WeakHashMap();
55
    private final Map<DomProvider, Phadhail> domProviders2Phadhails = new WeakHashMap<DomProvider,Phadhail>();
45
    private final Map/*<Phadhail,Phadhail>*/ phadhails2Parents = new WeakHashMap();
56
    private final Map<Phadhail, Phadhail> phadhails2Parents = new WeakHashMap<Phadhail,Phadhail>();
46
    
57
    
47
    public IndexImpl(Phadhail root) {
58
    public IndexImpl(Phadhail root) {
48
        this.root = root;
59
        this.root = root;
Lines 52-64 Link Here
52
        return root.lock();
63
        return root.lock();
53
    }
64
    }
54
    
65
    
55
    public Map getData() {
66
    public Map<String,Integer> getData() {
56
        assert getLock().canRead();
67
        assert getLock().canRead();
57
        Map/*<String,int>*/ data = (Map)processed.get(root);
68
        Map<String,Integer> data = processed.get(root);
58
        if (data != null) {
69
        if (data != null) {
59
            return Collections.unmodifiableMap(data);
70
            return Collections.unmodifiableMap(data);
60
        } else {
71
        } else {
61
            return Collections.EMPTY_MAP;
72
            return Collections.emptyMap();
62
        }
73
        }
63
    }
74
    }
64
    
75
    
Lines 79-94 Link Here
79
    }
90
    }
80
    
91
    
81
    private void fireChange() {
92
    private void fireChange() {
82
        ChangeListener[] ls;
93
        List<ChangeListener> ls;
83
        synchronized (listeners) {
94
        synchronized (listeners) {
84
            if (listeners.isEmpty()) {
95
            if (listeners.isEmpty()) {
85
                return;
96
                return;
86
            }
97
            }
87
            ls = (ChangeListener[])listeners.toArray(new ChangeListener[listeners.size()]);
98
            ls = new ArrayList<ChangeListener>(listeners);
88
        }
99
        }
89
        ChangeEvent ev = new ChangeEvent(this);
100
        ChangeEvent ev = new ChangeEvent(this);
90
        for (int i = 0; i < ls.length; i++) {
101
        for (ChangeListener l : ls) {
91
            ls[i].stateChanged(ev);
102
            l.stateChanged(ev);
92
        }
103
        }
93
    }
104
    }
94
    
105
    
Lines 124-130 Link Here
124
                        assert false : e;
135
                        assert false : e;
125
                    }
136
                    }
126
                }
137
                }
127
                next = (Phadhail)toProcess.removeFirst();
138
                next = toProcess.removeFirst();
128
            }
139
            }
129
            process(next);
140
            process(next);
130
        }
141
        }
Lines 141-147 Link Here
141
                    processChildren(ph);
152
                    processChildren(ph);
142
                } else {
153
                } else {
143
                    // Data, maybe.
154
                    // Data, maybe.
144
                    final Map computed = compute(ph);
155
                    final Map<String,Integer> computed = compute(ph);
145
                    getLock().writeLater(new Runnable() {
156
                    getLock().writeLater(new Runnable() {
146
                        public void run() {
157
                        public void run() {
147
                            processed.put(ph, computed);
158
                            processed.put(ph, computed);
Lines 156-165 Link Here
156
    }
167
    }
157
    
168
    
158
    private void processChildren(Phadhail ph) {
169
    private void processChildren(Phadhail ph) {
159
        Iterator/*<Phadhail>*/ kids = ph.getChildren().iterator();
160
        synchronized (toProcess) {
170
        synchronized (toProcess) {
161
            while (kids.hasNext()) {
171
            for (Phadhail kid : ph.getChildren()) {
162
                Phadhail kid = (Phadhail)kids.next();
163
                phadhails2Parents.put(kid, ph);
172
                phadhails2Parents.put(kid, ph);
164
                if (!toProcess.contains(kid)) {
173
                if (!toProcess.contains(kid)) {
165
                    toProcess.add(kid);
174
                    toProcess.add(kid);
Lines 173-212 Link Here
173
    }
182
    }
174
    
183
    
175
    private int count;
184
    private int count;
176
    private Map compute(Phadhail ph) {
185
    private Map<String,Integer> compute(Phadhail ph) {
177
        assert getLock().canRead();
186
        assert getLock().canRead();
178
        assert !ph.hasChildren();
187
        assert !ph.hasChildren();
179
        logger.log(Level.FINER, "Computing index for {0} [#{1}]", new Object[] {ph, new Integer(++count)});
188
        logger.log(Level.FINER, "Computing index for {0} [#{1}]", new Object[] {ph, ++count});
180
        DomProvider p = (DomProvider)domProviders2Phadhails.get(ph);
189
        // XXX technically should listen to lookup changes...
190
        DomProvider p = (DomProvider) PhadhailLookups.getLookup(ph).lookup(DomProvider.class);
181
        if (p == null) {
191
        if (p == null) {
182
            // XXX technically should listen to lookup changes...
192
            logger.finer("no DomProvider here");
183
            p = (DomProvider)PhadhailLookups.getLookup(ph).lookup(DomProvider.class);
193
            return Collections.emptyMap();
184
            if (p == null) {
185
                logger.finer("no DomProvider here");
186
                return Collections.EMPTY_MAP;
187
            }
188
            domProviders2Phadhails.put(p, ph);
189
        }
194
        }
195
        domProviders2Phadhails.put(p, ph);
190
        Document d;
196
        Document d;
191
        try {
197
        try {
192
            d = p.getDocument();
198
            d = p.getDocument();
193
        } catch (IOException e) {
199
        } catch (IOException e) {
194
            logger.log(Level.FINE, "Parsing failed for {0}: {1}", new Object[] {ph.getName(), e.getMessage()});
200
            logger.log(Level.FINE, "Parsing failed for {0}: {1}", new Object[] {ph.getName(), e.getMessage()});
195
            return Collections.EMPTY_MAP;
201
            return Collections.emptyMap();
196
        }
202
        }
197
        // Wait till after p.getDocument(), since that will fire stateChanged
203
        // Wait till after p.getDocument(), since that will fire stateChanged
198
        // the first time it is called (not ready -> ready)
204
        // the first time it is called (not ready -> ready)
199
        p.addChangeListener(WeakListeners.change(this, p));
205
        p.addChangeListener(WeakListeners.change(this, p));
200
        Map/*<String,int>*/ m = new HashMap();
206
        Map<String,Integer> m = new HashMap<String,Integer>();
201
        NodeList l = d.getElementsByTagName("*");
207
        NodeList l = d.getElementsByTagName("*");
202
        for (int i = 0; i < l.getLength(); i++) {
208
        for (int i = 0; i < l.getLength(); i++) {
203
            String name = ((Element)l.item(i)).getTagName();
209
            String name = ((Element)l.item(i)).getTagName();
204
            Integer x = (Integer)m.get(name);
210
            Integer old = m.get(name);
205
            if (x == null) {
211
            m.put(name, old != null ? old + 1 : 1);
206
                m.put(name, new Integer(1));
207
            } else {
208
                m.put(name, new Integer(x.intValue() + 1));
209
            }
210
        }
212
        }
211
        logger.log(Level.FINER, "Parse succeeded for {0}", ph);
213
        logger.log(Level.FINER, "Parse succeeded for {0}", ph);
212
        logger.log(Level.FINEST, "Parse results: {0}", m);
214
        logger.log(Level.FINEST, "Parse results: {0}", m);
Lines 215-221 Link Here
215
    
217
    
216
    private void bubble(Phadhail ph) {
218
    private void bubble(Phadhail ph) {
217
        assert getLock().canWrite();
219
        assert getLock().canWrite();
218
        logger.log(Level.FINER, "bubble: {0} data size: {1}", new Object[] {ph, new Integer(processed.size())});
220
        logger.log(Level.FINER, "bubble: {0} data size: {1}", new Object[] {ph, processed.size()});
219
        logger.log(Level.FINEST, "bubble: {0} data: {1}", new Object[] {ph, processed});
221
        logger.log(Level.FINEST, "bubble: {0} data: {1}", new Object[] {ph, processed});
220
        if (ph == root) {
222
        if (ph == root) {
221
            getLock().read(new Runnable() {
223
            getLock().read(new Runnable() {
Lines 227-249 Link Here
227
            Phadhail parent = (Phadhail)phadhails2Parents.get(ph);
229
            Phadhail parent = (Phadhail)phadhails2Parents.get(ph);
228
            assert parent != null : ph;
230
            assert parent != null : ph;
229
            assert parent.hasChildren();
231
            assert parent.hasChildren();
230
            Iterator/*<Phadhail>*/ kids = parent.getChildren().iterator();
232
            Map<String,Integer> recalc = new HashMap<String,Integer>();
231
            Map/*<String,int>*/ recalc = new HashMap();
233
            for (Phadhail kid : parent.getChildren()) {
232
            while (kids.hasNext()) {
234
                Map<String,Integer> subdata = processed.get(kid);
233
                Phadhail kid = (Phadhail)kids.next();
234
                Map/*<String,int>*/ subdata = (Map)processed.get(kid);
235
                if (subdata == null) {
235
                if (subdata == null) {
236
                    // OK, kid is simply not yet calculated, will bubble changes later.
236
                    // OK, kid is simply not yet calculated, will bubble changes later.
237
                    continue;
237
                    continue;
238
                }
238
                }
239
                Iterator it = subdata.entrySet().iterator();
239
                for (Map.Entry<String, Integer> e : subdata.entrySet()) {
240
                while (it.hasNext()) {
240
                    String name = e.getKey();
241
                    Map.Entry e = (Map.Entry)it.next();
241
                    int x1 = e.getValue();
242
                    String name = (String)e.getKey();
243
                    Integer x1 = (Integer)e.getValue();
244
                    if (recalc.containsKey(name)) {
242
                    if (recalc.containsKey(name)) {
245
                        Integer x2 = (Integer)recalc.get(name);
243
                        recalc.put(name, x1 + recalc.get(name));
246
                        recalc.put(name, new Integer(x1.intValue() + x2.intValue()));
247
                    } else {
244
                    } else {
248
                        recalc.put(name, x1);
245
                        recalc.put(name, x1);
249
                    }
246
                    }
Lines 280-286 Link Here
280
    
277
    
281
    public void stateChanged(ChangeEvent e) {
278
    public void stateChanged(ChangeEvent e) {
282
        DomProvider p = (DomProvider)e.getSource();
279
        DomProvider p = (DomProvider)e.getSource();
283
        Phadhail ph = (Phadhail)domProviders2Phadhails.get(p);
280
        Phadhail ph = domProviders2Phadhails.get(p);
284
        assert ph != null;
281
        assert ph != null;
285
        logger.log(Level.FINER, "stateChanged: {0}", ph);
282
        logger.log(Level.FINER, "stateChanged: {0}", ph);
286
        invalidate(ph);
283
        invalidate(ph);
(-)threaddemo/apps/refactor/Refactor.java (-19 / +19 lines)
Lines 49-55 Link Here
49
     * @param app owner app, or null
63
     * @param app owner app, or null
50
     */
64
     */
51
    public static void run(final Phadhail root, Frame app) {
65
    public static void run(final Phadhail root, Frame app) {
52
        final Map/*<Phadhail,DomProvider>*/ data = collectData(root);
66
        final Map<Phadhail,DomProvider> data = collectData(root);
53
        final BoundedRangeModel progress = new DefaultBoundedRangeModel();
67
        final BoundedRangeModel progress = new DefaultBoundedRangeModel();
54
        progress.setMinimum(0);
68
        progress.setMinimum(0);
55
        progress.setMaximum(data.size());
69
        progress.setMaximum(data.size());
Lines 75-92 Link Here
75
        dialog.getContentPane().add(cancel);
89
        dialog.getContentPane().add(cancel);
76
        dialog.pack();
90
        dialog.pack();
77
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
91
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
78
        dialog.show();
92
        dialog.setVisible(true);
79
        new Thread(new Runnable() {
93
        new Thread(new Runnable() {
80
            public void run() {
94
            public void run() {
81
                final Iterator/*<Map.Entry<Phadhail,DomProvider>>*/ it = data.entrySet().iterator();
95
                Iterator<Map.Entry<Phadhail, DomProvider>> it = data.entrySet().iterator();
82
                while (it.hasNext() && !cancelled[0]) {
96
                while (it.hasNext()) {
83
                    Map.Entry e = (Map.Entry)it.next();
97
                    Map.Entry<Phadhail, DomProvider> e = it.next();
98
                    if (cancelled[0]) {
99
                        break;
100
                    }
84
                    // Avoid keeping a reference to the old data, since we have
101
                    // Avoid keeping a reference to the old data, since we have
85
                    // cached DomProvider's and such heavyweight stuff open on them:
102
                    // cached DomProvider's and such heavyweight stuff open on them:
86
                    it.remove();
103
                    it.remove();
87
                    final Phadhail ph = (Phadhail)e.getKey();
104
                    final Phadhail ph = e.getKey();
88
                    logger.log(Level.FINER, "Refactoring {0}", ph);
105
                    logger.log(Level.FINER, "Refactoring {0}", ph);
89
                    final DomProvider p = (DomProvider)e.getValue();
106
                    final DomProvider p = e.getValue();
90
                    ph.lock().read(new Runnable() {
107
                    ph.lock().read(new Runnable() {
91
                        public void run() {
108
                        public void run() {
92
                            final String path = ph.getPath();
109
                            final String path = ph.getPath();
Lines 125-142 Link Here
125
        }, "Refactoring").start();
142
        }, "Refactoring").start();
126
    }
143
    }
127
    
144
    
128
    private static Map/*<Phadhail,DomProvider>*/ collectData(final Phadhail root) {
145
    private static Map<Phadhail, DomProvider> collectData(final Phadhail root) {
129
        return (Map)root.lock().read(new LockAction() {
146
        return root.lock().read(new LockAction<Map<Phadhail,DomProvider>>() {
130
            private final Map data = new HashMap(); 
147
            private final Map<Phadhail, DomProvider> data = new HashMap<Phadhail,DomProvider>(); 
131
            public Object run() {
148
            public Map<Phadhail, DomProvider> run() {
132
                collect(root);
149
                collect(root);
133
                return data;
150
                return data;
134
            }
151
            }
135
            private void collect(Phadhail ph) {
152
            private void collect(Phadhail ph) {
136
                if (ph.hasChildren()) {
153
                if (ph.hasChildren()) {
137
                    Iterator/*<Phadhail>*/ it = ph.getChildren().iterator();
154
                    for (Phadhail child : ph.getChildren()) {
138
                    while (it.hasNext()) {
155
                        collect(child);
139
                        collect((Phadhail)it.next());
140
                    }
156
                    }
141
                } else {
157
                } else {
142
                    DomProvider p = (DomProvider)PhadhailLookups.getLookup(ph).lookup(DomProvider.class);
158
                    DomProvider p = (DomProvider)PhadhailLookups.getLookup(ph).lookup(DomProvider.class);
Lines 157-171 Link Here
157
            return;
173
            return;
158
        }
174
        }
159
        NodeList nl = doc.getElementsByTagName("*");
175
        NodeList nl = doc.getElementsByTagName("*");
160
        List/*<Element>*/ l = new ArrayList();
176
        final List<Element> l = new ArrayList<Element>();
161
        for (int i = 0; i < nl.getLength(); i++) {
177
        for (int i = 0; i < nl.getLength(); i++) {
162
            l.add(nl.item(i));
178
            l.add((Element) nl.item(i));
163
        }
179
        }
164
        final Iterator it = l.iterator();
165
        p.isolatingChange(new Runnable() {
180
        p.isolatingChange(new Runnable() {
166
            public void run() {
181
            public void run() {
167
                while (it.hasNext()) {
182
                for (Element el : l) {
168
                    Element el = (Element)it.next();
169
                    String tagname = el.getTagName();
183
                    String tagname = el.getTagName();
170
                    if (tagname.startsWith("tag-")) {
184
                    if (tagname.startsWith("tag-")) {
171
                        int n = Integer.parseInt(tagname.substring(4));
185
                        int n = Integer.parseInt(tagname.substring(4));
(-)threaddemo/data/DomSupport.java (-50 / +42 lines)
Lines 45-61 Link Here
45
 * using the {@link TwoWaySupport} semantics.
60
 * using the {@link TwoWaySupport} semantics.
46
 * @author Jesse Glick
61
 * @author Jesse Glick
47
 */
62
 */
48
public final class DomSupport extends DocumentParseSupport implements DomProvider, ErrorHandler, TwoWayListener, EntityResolver, EventListener {
63
public final class DomSupport extends DocumentParseSupport<Document,Document> implements DomProvider, ErrorHandler, TwoWayListener<Document,DocumentParseSupportDelta,Document>, EntityResolver, EventListener {
49
    
64
    
50
    private static final Logger logger = Logger.getLogger(DomSupport.class.getName());
65
    private static final Logger logger = Logger.getLogger(DomSupport.class.getName());
51
    
66
    
52
    private final Phadhail ph;
67
    private final Phadhail ph;
53
    private final Set listeners = new HashSet();
68
    private final Set<ChangeListener> listeners = new HashSet<ChangeListener>();
54
    private boolean inIsolatingChange = false;
69
    private boolean inIsolatingChange = false;
55
    private boolean madeIsolatedChanges;
70
    private boolean madeIsolatedChanges;
56
    
71
    
Lines 66-122 Link Here
66
    }
76
    }
67
    
77
    
68
    public Document getDocument() throws IOException {
78
    public Document getDocument() throws IOException {
69
        try {
79
        return getLock().read(new LockExceptionAction<Document,IOException>() {
70
            return (Document)getLock().read(new LockExceptionAction() {
80
            public Document run() throws IOException {
71
                public Object run() throws IOException {
81
                assert !inIsolatingChange;
72
                    assert !inIsolatingChange;
82
                try {
73
                    try {
83
                    Document v = getValueBlocking();
74
                        Object v = getValueBlocking();
84
                    logger.log(Level.FINER, "getDocument: {0}", v);
75
                        logger.log(Level.FINER, "getDocument: {0}", v);
85
                    return v;
76
                        return (Document)v;
86
                } catch (InvocationTargetException e) {
77
                    } catch (InvocationTargetException e) {
87
                    throw (IOException) e.getCause();
78
                        throw (IOException)e.getCause();
79
                    }
80
                }
88
                }
81
            });
89
            }
82
        } catch (InvocationTargetException e) {
90
        });
83
            throw (IOException)e.getCause();
84
        }
85
    }
91
    }
86
    
92
    
87
    public void setDocument(final Document d) throws IOException {
93
    public void setDocument(final Document d) throws IOException {
88
        if (d == null) throw new NullPointerException();
94
        if (d == null) throw new NullPointerException();
89
        try {
95
        getLock().write(new LockExceptionAction<Void,IOException>() {
90
            getLock().write(new LockExceptionAction() {
96
            public Void run() throws IOException {
91
                public Object run() throws IOException {
97
                assert !inIsolatingChange;
92
                    assert !inIsolatingChange;
98
                Document old = (Document)getStaleValueNonBlocking();
93
                    Document old = (Document)getStaleValueNonBlocking();
99
                if (old != null && old != d) {
94
                    if (old != null && old != d) {
100
                    ((EventTarget)old).removeEventListener("DOMSubtreeModified", DomSupport.this, false);
95
                        ((EventTarget)old).removeEventListener("DOMSubtreeModified", DomSupport.this, false);
101
                    ((EventTarget)d).addEventListener("DOMSubtreeModified", DomSupport.this, false);
96
                        ((EventTarget)d).addEventListener("DOMSubtreeModified", DomSupport.this, false);
97
                    }
98
                    try {
99
                        mutate(d);
100
                        return null;
101
                    } catch (InvocationTargetException e) {
102
                        throw (IOException)e.getCause();
103
                    } catch (ClobberException e) {
104
                        throw (IOException)new IOException(e.toString()).initCause(e);
105
                    }
106
                }
102
                }
107
            });
103
                try {
108
        } catch (InvocationTargetException e) {
104
                    mutate(d);
109
            throw (IOException)e.getCause();
105
                    return null;
110
        }
106
                } catch (InvocationTargetException e) {
107
                    throw (IOException) e.getCause();
108
                } catch (ClobberException e) {
109
                    throw (IOException) new IOException(e.toString()).initCause(e);
110
                }
111
            }
112
        });
111
    }
113
    }
112
    
114
    
113
    public boolean isReady() {
115
    public boolean isReady() {
114
        return ((Boolean)getLock().read(new LockAction() {
116
        return getLock().read(new LockAction<Boolean>() {
115
            public Object run() {
117
            public Boolean run() {
116
                assert !inIsolatingChange;
118
                assert !inIsolatingChange;
117
                return getValueNonBlocking() != null ? Boolean.TRUE : Boolean.FALSE;
119
                return getValueNonBlocking() != null;
118
            }
120
            }
119
        })).booleanValue();
121
        });
120
    }
122
    }
121
    
123
    
122
    public void start() {
124
    public void start() {
Lines 140-160 Link Here
140
    }
142
    }
141
    
143
    
142
    private void fireChange() {
144
    private void fireChange() {
143
        final ChangeListener[] ls;
145
        final List<ChangeListener> ls;
144
        synchronized (listeners) {
146
        synchronized (listeners) {
145
            if (listeners.isEmpty()) {
147
            if (listeners.isEmpty()) {
146
                logger.log(Level.FINER, "DomSupport change with no listeners: {0}", ph);
148
                logger.log(Level.FINER, "DomSupport change with no listeners: {0}", ph);
147
                return;
149
                return;
148
            }
150
            }
149
            ls = (ChangeListener[])listeners.toArray(new ChangeListener[listeners.size()]);
151
            ls = new ArrayList<ChangeListener>(listeners);
150
        }
152
        }
151
        final ChangeEvent ev = new ChangeEvent(this);
153
        final ChangeEvent ev = new ChangeEvent(this);
152
        getLock().read(new Runnable() {
154
        getLock().read(new Runnable() {
153
            public void run() {
155
            public void run() {
154
                assert !inIsolatingChange;
156
                assert !inIsolatingChange;
155
                logger.log(Level.FINER, "DomSupport change: {0}", ph);
157
                logger.log(Level.FINER, "DomSupport change: {0}", ph);
156
                for (int i = 0; i < ls.length; i++) {
158
                for (ChangeListener l : ls) {
157
                    ls[i].stateChanged(ev);
159
                    l.stateChanged(ev);
158
                }
160
                }
159
            }
161
            }
160
        });
162
        });
Lines 164-170 Link Here
164
        return false;
166
        return false;
165
    }
167
    }
166
    
168
    
167
    protected final DerivationResult doDerive(StyledDocument document, List documentEvents, Object oldValue) throws IOException {
169
    protected final DerivationResult<Document,Document> doDerive(StyledDocument document, List<DocumentEvent> documentEvents, Document oldValue) throws IOException {
168
        assert !inIsolatingChange;
170
        assert !inIsolatingChange;
169
        // ignoring documentEvents
171
        // ignoring documentEvents
170
        logger.log(Level.FINER, "DomSupport doDerive: {0}", ph);
172
        logger.log(Level.FINER, "DomSupport doDerive: {0}", ph);
Lines 193-205 Link Here
193
        }
195
        }
194
        ((EventTarget)newValue).addEventListener("DOMSubtreeModified", this, false);
196
        ((EventTarget)newValue).addEventListener("DOMSubtreeModified", this, false);
195
        // This impl does not compute structural diffs, so newValue == derivedDelta when modified:
197
        // This impl does not compute structural diffs, so newValue == derivedDelta when modified:
196
        return new DerivationResult(newValue, oldValue != null ? newValue : null);
198
        return new DerivationResult<Document,Document>(newValue, oldValue != null ? newValue : null);
197
    }
199
    }
198
    
200
    
199
    protected final Object doRecreate(StyledDocument document, Object oldValue, Object derivedDelta) throws IOException {
201
    protected final Document doRecreate(StyledDocument document, Document oldValue, Document newDom) throws IOException {
200
        assert !inIsolatingChange;
202
        assert !inIsolatingChange;
201
        logger.log(Level.FINER, "DomSupport doRecreate: {0}", ph);
203
        logger.log(Level.FINER, "DomSupport doRecreate: {0}", ph);
202
        // ignoring oldValue, returning same newDom
204
        // ignoring oldValue, returning same newDom
203
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
205
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
204
        try {
206
        try {
Lines 316-322 Link Here
316
            inIsolatingChange = false;
317
            inIsolatingChange = false;
317
            logger.log(Level.FINER, "Finished isolatingChange on {0}; madeIsolatedChanges={1}", new Object[] {ph, madeIsolatedChanges ? Boolean.TRUE : Boolean.FALSE});
318
            logger.log(Level.FINER, "Finished isolatingChange on {0}; madeIsolatedChanges={1}", new Object[] {ph, madeIsolatedChanges ? Boolean.TRUE : Boolean.FALSE});
318
            if (madeIsolatedChanges) {
319
            if (madeIsolatedChanges) {
319
                Document d = (Document)getValueNonBlocking();
320
                Document d = getValueNonBlocking();
320
                if (d != null) {
321
                if (d != null) {
321
                    try {
322
                    try {
322
                        setDocument(d);
323
                        setDocument(d);
(-)threaddemo/data/PhadhailLookups.java (-5 / +6 lines)
Lines 13-23 Link Here
13
13
14
package threaddemo.data;
14
package threaddemo.data;
15
15
16
import java.lang.ref.*;
16
import java.util.Map;
17
import java.util.*;
17
import java.util.WeakHashMap;
18
import org.openide.cookies.SaveCookie;
18
import org.openide.cookies.SaveCookie;
19
import org.openide.util.Lookup;
19
import org.openide.util.Lookup;
20
import org.openide.util.lookup.*;
20
import org.openide.util.lookup.AbstractLookup;
21
import org.openide.util.lookup.InstanceContent;
21
import threaddemo.locking.Lock;
22
import threaddemo.locking.Lock;
22
import threaddemo.model.Phadhail;
23
import threaddemo.model.Phadhail;
23
24
Lines 35-45 Link Here
35
    /** no instances */
36
    /** no instances */
36
    private PhadhailLookups() {}
37
    private PhadhailLookups() {}
37
    
38
    
38
    private static final Map lookups = new WeakHashMap(); // Map<Phadhail,PhadhailLookup>
39
    private static final Map<Phadhail,PhadhailLookup> lookups = new WeakHashMap<Phadhail,PhadhailLookup>();
39
    
40
    
40
    // XXX rather than being synch, should be readAccess, and modified/saved should be writeAccess
41
    // XXX rather than being synch, should be readAccess, and modified/saved should be writeAccess
41
    public static synchronized Lookup getLookup(Phadhail ph) {
42
    public static synchronized Lookup getLookup(Phadhail ph) {
42
        Lookup l = (Lookup)lookups.get(ph);
43
        PhadhailLookup l = lookups.get(ph);
43
        if (l == null) {
44
        if (l == null) {
44
            l = new PhadhailLookup(ph);
45
            l = new PhadhailLookup(ph);
45
            lookups.put(ph, l);
46
            lookups.put(ph, l);
(-)threaddemo/locking/EventHybridLock.java (-20 / +34 lines)
Lines 33-39 Link Here
33
    
36
    
34
    private EventHybridLock() {}
37
    private EventHybridLock() {}
35
    
38
    
36
    public Object read(LockAction action) {
39
    public <T> T read(LockAction<T> action) {
37
        if (EventLock.isDispatchThread()) {
40
        if (EventLock.isDispatchThread()) {
38
            // Fine, go ahead.
41
            // Fine, go ahead.
39
            if (semaphore == -1) {
42
            if (semaphore == -1) {
Lines 85-113 Link Here
85
        }
88
        }
86
    }
89
    }
87
    
90
    
88
    private static LockAction convertExceptionAction(final LockExceptionAction action) {
91
    private static final class Holder<T, E extends Exception> {
89
        return new LockAction() {
92
        public final T object;
90
            public Object run() {
93
        public final E exception;
94
        public Holder(T object) {
95
            this.object = object;
96
            this.exception = null;
97
        }
98
        public Holder(E exception) {
99
            this.object = null;
100
            this.exception = exception;
101
        }
102
    }
103
    
104
    @SuppressWarnings("unchecked")
105
    private static <T, E extends Exception> LockAction<Holder<T,E>> convertExceptionAction(final LockExceptionAction<T,E> action) {
106
        return new LockAction<Holder<T,E>>() {
107
            public Holder<T,E> run() {
91
                try {
108
                try {
92
                    return new Object[] {action.run()};
109
                    return new Holder<T,E>(action.run());
93
                } catch (RuntimeException e) {
110
                } catch (RuntimeException e) {
94
                    throw e;
111
                    throw e;
95
                } catch (Exception e) {
112
                } catch (Exception e) {
96
                    return e;
113
                    return new Holder<T,E>((E) e);
97
                }
114
                }
98
            }
115
            }
99
        };
116
        };
100
    }
117
    }
101
    
118
    
102
    private static Object finishExceptionAction(Object result) throws InvocationTargetException {
119
    private static <T, E extends Exception> T finishExceptionAction(Holder<T,E> result) throws E {
103
        if (result instanceof Object[]) {
120
        if (result.exception != null) {
104
            return ((Object[])result)[0];
121
            throw result.exception;
105
        } else {
122
        } else {
106
            throw new InvocationTargetException((Exception)result);
123
            return result.object;
107
        }
124
        }
108
    }
125
    }
109
    
126
    
110
    public Object read(LockExceptionAction action) throws InvocationTargetException {
127
    public <T, E extends Exception> T read(LockExceptionAction<T,E> action) throws E {
111
        return finishExceptionAction(read(convertExceptionAction(action)));
128
        return finishExceptionAction(read(convertExceptionAction(action)));
112
    }
129
    }
113
    
130
    
Lines 115-133 Link Here
115
        read(convertRunnable(action));
132
        read(convertRunnable(action));
116
    }
133
    }
117
    
134
    
118
    public Object write(final LockAction action) {
135
    public <T> T write(final LockAction<T> action) {
119
        if (!EventLock.isDispatchThread()) {
136
        if (!EventLock.isDispatchThread()) {
120
            // Try again in AWT.
137
            // Try again in AWT.
121
            if (canRead()) {
138
            if (canRead()) {
122
                throw new IllegalStateException("Cannot go R -> W"); // NOI18N
139
                throw new IllegalStateException("Cannot go R -> W"); // NOI18N
123
            }
140
            }
124
            try {
141
            try {
125
                final Object[] o = new Object[1];
142
                final List<T> o = new ArrayList<T>(1);
126
                final Error[] err = new Error[1];
143
                final Error[] err = new Error[1];
127
                EventLock.invokeAndWaitLowPriority(this, new Runnable() {
144
                EventLock.invokeAndWaitLowPriority(this, new Runnable() {
128
                    public void run() {
145
                    public void run() {
129
                        try {
146
                        try {
130
                            o[0] = write(action);
147
                            o.add(write(action));
131
                        } catch (Error e) {
148
                        } catch (Error e) {
132
                            err[0] = e;
149
                            err[0] = e;
133
                        }
150
                        }
Lines 136-142 Link Here
136
                if (err[0] != null) {
153
                if (err[0] != null) {
137
                    throw err[0];
154
                    throw err[0];
138
                }
155
                }
139
                return o[0];
156
                return o.get(0);
140
            } catch (InterruptedException e) {
157
            } catch (InterruptedException e) {
141
                throw new IllegalStateException(e.toString());
158
                throw new IllegalStateException(e.toString());
142
            } catch (InvocationTargetException e) {
159
            } catch (InvocationTargetException e) {
Lines 187-193 Link Here
187
        }
204
        }
188
    }
205
    }
189
    
206
    
190
    public Object write(LockExceptionAction action) throws InvocationTargetException {
207
    public <T, E extends Exception> T write(LockExceptionAction<T,E> action) throws E {
191
        return finishExceptionAction(write(convertExceptionAction(action)));
208
        return finishExceptionAction(write(convertExceptionAction(action)));
192
    }
209
    }
193
    
210
    
Lines 195-203 Link Here
195
        write(convertRunnable(action));
212
        write(convertRunnable(action));
196
    }
213
    }
197
    
214
    
198
    private static LockAction convertRunnable(final Runnable action) {
215
    private static <T> LockAction<T> convertRunnable(final Runnable action) {
199
        return new LockAction() {
216
        return new LockAction<T>() {
200
            public Object run() {
217
            public T run() {
201
                action.run();
218
                action.run();
202
                return null;
219
                return null;
203
            }
220
            }
Lines 260-265 Link Here
260
    /**
277
    /**
261
     * Set of readers which are running.
278
     * Set of readers which are running.
262
     */
279
     */
263
    private final Set readers = new HashSet(); // Set<Thread>
280
    private final Set<Thread> readers = new HashSet<Thread>();
264
    
281
    
265
}
282
}
(-)threaddemo/locking/EventLock.java (-18 / +14 lines)
Lines 33-48 Link Here
33
    
34
    
34
    private EventLock() {}
35
    private EventLock() {}
35
    
36
    
36
    public Object read(final LockAction action) {
37
    public <T> T read(final LockAction<T> action) {
37
        if (isDispatchThread()) {
38
        if (isDispatchThread()) {
38
            return action.run();
39
            return action.run();
39
        } else {
40
        } else {
40
            ReadWriteLock.enteringOther(this);
41
            ReadWriteLock.enteringOther(this);
41
            final Object[] result = new Object[1];
42
            final List<T> result = new ArrayList<T>(1);
42
            try {
43
            try {
43
                invokeAndWaitLowPriority(this, new Runnable() {
44
                invokeAndWaitLowPriority(this, new Runnable() {
44
                    public void run() {
45
                    public void run() {
45
                        result[0] = action.run();
46
                        result.add(action.run());
46
                    }
47
                    }
47
                });
48
                });
48
            } catch (InterruptedException e) {
49
            } catch (InterruptedException e) {
Lines 57-84 Link Here
57
                    throw new IllegalStateException(t.toString());
58
                    throw new IllegalStateException(t.toString());
58
                }
59
                }
59
            }
60
            }
60
            return result[0];
61
            return result.get(0);
61
        }
62
        }
62
    }
63
    }
63
    
64
    
64
    public Object read(final LockExceptionAction action) throws InvocationTargetException {
65
    public <T, E extends Exception> T read(final LockExceptionAction<T,E> action) throws E {
65
        if (isDispatchThread()) {
66
        if (isDispatchThread()) {
66
            try {
67
            return action.run();
67
                return action.run();
68
            } catch (RuntimeException e) {
69
                throw e;
70
            } catch (Exception e) {
71
                throw new InvocationTargetException(e);
72
            }
73
        } else {
68
        } else {
74
            ReadWriteLock.enteringOther(this);
69
            ReadWriteLock.enteringOther(this);
75
            final Throwable[] exc = new Throwable[1];
70
            final Throwable[] exc = new Throwable[1];
76
            final Object[] result = new Object[1];
71
            final List<T> result = new ArrayList<T>(1);
77
            try {
72
            try {
78
                invokeAndWaitLowPriority(this, new Runnable() {
73
                invokeAndWaitLowPriority(this, new Runnable() {
79
                    public void run() {
74
                    public void run() {
80
                        try {
75
                        try {
81
                            result[0] = action.run();
76
                            result.add(action.run());
82
                        } catch (Throwable t) {
77
                        } catch (Throwable t) {
83
                            exc[0] = t;
78
                            exc[0] = t;
84
                        }
79
                        }
Lines 95-103 Link Here
95
            } else if (exc[0] instanceof Error) {
90
            } else if (exc[0] instanceof Error) {
96
                throw (Error)exc[0];
91
                throw (Error)exc[0];
97
            } else if (exc[0] != null) {
92
            } else if (exc[0] != null) {
98
                throw new InvocationTargetException((Exception)exc[0]);
93
                @SuppressWarnings("unchecked")
94
                E e = (E) exc[0];
95
                throw e;
99
            } else {
96
            } else {
100
                return result[0];
97
                return result.get(0);
101
            }
98
            }
102
        }
99
        }
103
    }
100
    }
Lines 106-116 Link Here
106
        invokeLaterLowPriority(this, action);
103
        invokeLaterLowPriority(this, action);
107
    }
104
    }
108
    
105
    
109
    public Object write(LockAction action) {
106
    public <T> T write(LockAction<T> action) {
110
        return read(action);
107
        return read(action);
111
    }
108
    }
112
    
109
    
113
    public Object write(LockExceptionAction action) throws InvocationTargetException {
110
    public <T, E extends Exception> T write(LockExceptionAction<T,E> action) throws E {
114
        return read(action);
111
        return read(action);
115
    }
112
    }
116
    
113
    
(-)threaddemo/locking/Lock.java (-2 / +2 lines)
Lines 110-140 Link Here
110
     * @param action the action to perform
89
     * @param action the action to perform
111
     * @return the result of {@link LockAction#run}
90
     * @return the result of {@link LockAction#run}
112
     */
91
     */
113
    Object write(LockAction action);
92
    <T> T write(LockAction<T> action);
114
93
115
    Object write(LockExceptionAction action) throws InvocationTargetException;
94
    <T, E extends Exception> T write(LockExceptionAction<T, E> action) throws E;
116
95
117
    /**
96
    /**
118
     * Run an action with write access and return no result.
97
     * Run an action with write access and return no result.
(-)threaddemo/locking/LockAction.java (-2 / +2 lines)
Lines 17-29 Link Here
17
 * Unchecked exceptions will be propagated to calling code.
17
 * Unchecked exceptions will be propagated to calling code.
18
 *
18
 *
19
 */
19
 */
20
public interface LockAction {
20
public interface LockAction<T> {
21
    
21
    
22
    /**
22
    /**
23
     * Execute the action.
23
     * Execute the action.
24
     * @return any object, then returned from {@link Lock#read(LockAction)} or {@link Lock#write(LockAction)}
24
     * @return any object, then returned from {@link Lock#read(LockAction)} or {@link Lock#write(LockAction)}
25
     */
25
     */
26
    public Object run();
26
    public T run();
27
    
27
    
28
}
28
}
29
29
(-)threaddemo/locking/LockExceptionAction.java (-2 / +2 lines)
Lines 14-34 Link Here
14
package threaddemo.locking;
14
package threaddemo.locking;
15
15
16
public interface LockExceptionAction {
16
public interface LockExceptionAction<T, E extends Exception> {
17
    
17
    
18
    public Object run() throws Exception;
18
    public T run() throws E;
19
    
19
    
20
}
20
}
21
21
(-)threaddemo/locking/MonitorLock.java (-11 / +5 lines)
Lines 34-52 Link Here
34
        return Thread.holdsLock(monitor);
32
        return Thread.holdsLock(monitor);
35
    }
33
    }
36
    
34
    
37
    public Object read(LockExceptionAction action) throws InvocationTargetException {
35
    public <T, E extends Exception> T read(LockExceptionAction<T,E> action) throws E {
38
        synchronized (monitor) {
36
        synchronized (monitor) {
39
            try {
37
            return action.run();
40
                return action.run();
41
            } catch (RuntimeException e) {
42
                throw e;
43
            } catch (Exception e) {
44
                throw new InvocationTargetException(e);
45
            }
46
        }
38
        }
47
    }
39
    }
48
    
40
    
49
    public Object read(LockAction action) {
41
    public <T> T read(LockAction<T> action) {
50
        synchronized (monitor) {
42
        synchronized (monitor) {
51
            return action.run();
43
            return action.run();
52
        }
44
        }
Lines 74-84 Link Here
74
        return canRead();
66
        return canRead();
75
    }
67
    }
76
    
68
    
77
    public Object write(LockAction action) {
69
    public <T> T write(LockAction<T> action) {
78
        return read(action);
70
        return read(action);
79
    }
71
    }
80
    
72
    
81
    public Object write(LockExceptionAction action) throws InvocationTargetException {
73
    public <T, E extends Exception> T write(LockExceptionAction<T,E> action) throws E {
82
        return read(action);
74
        return read(action);
83
    }
75
    }
84
    
76
    
(-)threaddemo/locking/ReadWriteLock.java (-24 / +16 lines)
Lines 54-60 Link Here
54
        return name;
60
        return name;
55
    }
61
    }
56
62
57
    public Object read(LockAction action) {
63
    public <T> T read(LockAction<T> action) {
58
        enterRead();
64
        enterRead();
59
        try {
65
        try {
60
            return action.run();
66
            return action.run();
Lines 63-76 Link Here
63
        }
69
        }
64
    }
70
    }
65
    
71
    
66
    public Object read(LockExceptionAction action) throws InvocationTargetException {
72
    public <T, E extends Exception> T read(LockExceptionAction<T, E> action) throws E {
67
        enterRead();
73
        enterRead();
68
        try {
74
        try {
69
            return action.run();
75
            return action.run();
70
        } catch (RuntimeException e) {
71
            throw (RuntimeException)e;
72
        } catch (Exception e) {
73
            throw new InvocationTargetException(e);
74
        } finally {
76
        } finally {
75
            exitRead();
77
            exitRead();
76
        }
78
        }
Lines 84-90 Link Here
84
        });
86
        });
85
    }
87
    }
86
    
88
    
87
    public Object write(LockAction action) {
89
    public <T> T write(LockAction<T> action) {
88
        enterWrite();
90
        enterWrite();
89
        try {
91
        try {
90
            return action.run();
92
            return action.run();
Lines 93-106 Link Here
93
        }
95
        }
94
    }
96
    }
95
    
97
    
96
    public Object write(LockExceptionAction action) throws InvocationTargetException {
98
    public <T, E extends Exception> T write(LockExceptionAction<T, E> action) throws E {
97
        enterWrite();
99
        enterWrite();
98
        try {
100
        try {
99
            return action.run();
101
            return action.run();
100
        } catch (RuntimeException e) {
101
            throw (RuntimeException)e;
102
        } catch (Exception e) {
103
            throw new InvocationTargetException(e);
104
        } finally {
102
        } finally {
105
            exitWrite();
103
            exitWrite();
106
        }
104
        }
Lines 268-276 Link Here
268
        synchronized (lock()) {
266
        synchronized (lock()) {
269
            StringBuffer b = new StringBuffer("ReadWriteLock<name=").append(name).append(",level=").append(level).append(",semaphore=").append(semaphore).append(",threads=["); // NOI18N
267
            StringBuffer b = new StringBuffer("ReadWriteLock<name=").append(name).append(",level=").append(level).append(",semaphore=").append(semaphore).append(",threads=["); // NOI18N
270
            boolean first = true;
268
            boolean first = true;
271
            Iterator it = threads.values().iterator();
269
            for (ThreadInfo ti : threads.values()) {
272
            while (it.hasNext()) {
273
                ThreadInfo ti = (ThreadInfo)it.next();
274
                if (ti.live) {
270
                if (ti.live) {
275
                    if (first) {
271
                    if (first) {
276
                        first = false;
272
                        first = false;
Lines 292-298 Link Here
292
    /**
288
    /**
293
     * Map from threads to associated information.
289
     * Map from threads to associated information.
294
     */
290
     */
295
    private final Map threads = new WeakHashMap(); // Map<Thread,ThreadInfo>
291
    private final Map<Thread,ThreadInfo> threads = new WeakHashMap<Thread,ThreadInfo>();
296
292
297
    /**
293
    /**
298
     * Get information about the current thread.
294
     * Get information about the current thread.
Lines 304-310 Link Here
304
        if (ti == null) {
300
        if (ti == null) {
305
            ti = new ThreadInfo(t);
301
            ti = new ThreadInfo(t);
306
            threads.put(t, ti);
302
            threads.put(t, ti);
307
            ((Set)relevantLocks.get()).add(this);
303
            relevantLocks.get().add(this);
308
        }
304
        }
309
        return ti;
305
        return ti;
310
    }
306
    }
Lines 416-424 Link Here
416
     * lock, of course, but this information is represented by extraReaders and
412
     * lock, of course, but this information is represented by extraReaders and
417
     * extraWriters.
413
     * extraWriters.
418
     */
414
     */
419
    private static final ThreadLocal orderedLocksHeld = new ThreadLocal() { // ThreadLocal<List<ThreadInfo>>
415
    private static final ThreadLocal<List<ThreadInfo>> orderedLocksHeld = new ThreadLocal<List<ThreadInfo>>() {
420
        protected Object initialValue() {
416
        protected List<ThreadInfo> initialValue() {
421
            return new ArrayList();
417
            return new ArrayList<ThreadInfo>();
422
        }
418
        }
423
    };
419
    };
424
420
Lines 427-435 Link Here
427
     * with or without definite order (not counting EVENT) which have ever been
423
     * with or without definite order (not counting EVENT) which have ever been
428
     * held or might have been held and which still exist.
424
     * held or might have been held and which still exist.
429
     */
425
     */
430
    private static final ThreadLocal relevantLocks = new ThreadLocal() { // ThreadLocal<Set<Lock>>
426
    private static final ThreadLocal<Set<Lock>> relevantLocks = new ThreadLocal<Set<Lock>>() {
431
        protected Object initialValue() {
427
        protected Set<Lock> initialValue() {
432
            return new WeakSet();
428
            @SuppressWarnings("unchecked")
429
            Set<Lock> s = new WeakSet();
430
            return s;
433
        }
431
        }
434
    };
432
    };
435
433
Lines 440-446 Link Here
440
     * First checks that it is legal to enter.
438
     * First checks that it is legal to enter.
441
     */
439
     */
442
    private static void entering(ThreadInfo ti) throws IllegalStateException {
440
    private static void entering(ThreadInfo ti) throws IllegalStateException {
443
        List l = (List)orderedLocksHeld.get();
441
        List<ThreadInfo> l = orderedLocksHeld.get();
444
        // It is ordered, check it.
442
        // It is ordered, check it.
445
        ThreadInfo last;
443
        ThreadInfo last;
446
        if (!l.isEmpty()) {
444
        if (!l.isEmpty()) {
(-)threaddemo/model/AbstractPhadhail.java (-34 / +32 lines)
Lines 28-44 Link Here
28
 */
40
 */
29
public abstract class AbstractPhadhail implements Phadhail {
41
public abstract class AbstractPhadhail implements Phadhail {
30
    
42
    
31
    private static final Map instances = new WeakHashMap(); // Map<Factory,Map<File,Reference<AbstractPhadhail>>>
43
    private static final Map<Factory, Map<File, Reference<AbstractPhadhail>>> instances = new WeakHashMap<Factory,Map<File,Reference<AbstractPhadhail>>>();
32
    
44
    
33
    protected interface Factory {
45
    protected interface Factory {
34
        AbstractPhadhail create(File f);
46
        AbstractPhadhail create(File f);
35
    }
47
    }
36
    
48
    
37
    private static Map instancesForFactory(Factory y) { // Map<File,Reference<AbstractPhadhail>>
49
    private static Map<File, Reference<AbstractPhadhail>> instancesForFactory(Factory y) {
38
        assert Thread.holdsLock(AbstractPhadhail.class);
50
        assert Thread.holdsLock(AbstractPhadhail.class);
39
        Map instances2 = (Map)instances.get(y);
51
        Map<File,Reference<AbstractPhadhail>> instances2 = instances.get(y);
40
        if (instances2 == null) {
52
        if (instances2 == null) {
41
            instances2 = new WeakHashMap();
53
            instances2 = new WeakHashMap<File,Reference<AbstractPhadhail>>();
42
            instances.put(y, instances2);
54
            instances.put(y, instances2);
43
        }
55
        }
44
        return instances2;
56
        return instances2;
Lines 46-65 Link Here
46
    
58
    
47
    /** factory */
59
    /** factory */
48
    protected static synchronized AbstractPhadhail forFile(File f, Factory y) {
60
    protected static synchronized AbstractPhadhail forFile(File f, Factory y) {
49
        Map instances2 = instancesForFactory(y);
61
        Map<File,Reference<AbstractPhadhail>> instances2 = instancesForFactory(y);
50
        Reference r = (Reference)instances2.get(f);
62
        Reference<AbstractPhadhail> r = instances2.get(f);
51
        AbstractPhadhail ph = (r != null) ? (AbstractPhadhail)r.get() : null;
63
        AbstractPhadhail ph = (r != null) ? r.get() : null;
52
        if (ph == null) {
64
        if (ph == null) {
53
            // XXX could also yield lock while calling create, but don't bother
65
            // XXX could also yield lock while calling create, but don't bother
54
            ph = y.create(f);
66
            ph = y.create(f);
55
            instances2.put(f, new WeakReference(ph));
67
            instances2.put(f, new WeakReference<AbstractPhadhail>(ph));
56
        }
68
        }
57
        return ph;
69
        return ph;
58
    }
70
    }
59
    
71
    
60
    private File f;
72
    private File f;
61
    private List listeners = null; // List<PhadhailListener>
73
    private List<PhadhailListener> listeners = null;
62
    private Reference kids; // Reference<List<Phadhail>>
74
    private Reference<List<Phadhail>> kids;
63
    private static boolean firing = false;
75
    private static boolean firing = false;
64
    
76
    
65
    protected AbstractPhadhail(File f) {
77
    protected AbstractPhadhail(File f) {
Lines 69-79 Link Here
69
    /** factory to create new instances of this class; should be a constant */
81
    /** factory to create new instances of this class; should be a constant */
70
    protected abstract Factory factory();
82
    protected abstract Factory factory();
71
    
83
    
72
    public List getChildren() {
84
    public List<Phadhail> getChildren() {
73
        assert lock().canRead();
85
        assert lock().canRead();
74
        List phs = null; // List<Phadhail>
86
        List<Phadhail> phs = null;
75
        if (kids != null) {
87
        if (kids != null) {
76
            phs = (List)kids.get();
88
            phs = kids.get();
77
        }
89
        }
78
        if (phs == null) {
90
        if (phs == null) {
79
            // Need to (re)calculate the children.
91
            // Need to (re)calculate the children.
Lines 82-95 Link Here
82
                Arrays.sort(fs);
94
                Arrays.sort(fs);
83
                phs = new ChildrenList(fs);
95
                phs = new ChildrenList(fs);
84
            } else {
96
            } else {
85
                phs =  Collections.EMPTY_LIST;
97
                phs = Collections.emptyList();
86
            }
98
            }
87
            kids = new WeakReference(phs);
99
            kids = new WeakReference<List<Phadhail>>(phs);
88
        }
100
        }
89
        return phs;
101
        return phs;
90
    }
102
    }
91
    
103
    
92
    private final class ChildrenList extends AbstractList {
104
    private final class ChildrenList extends AbstractList<Phadhail> {
93
        private final File[] files;
105
        private final File[] files;
94
        private final Phadhail[] kids;
106
        private final Phadhail[] kids;
95
        public ChildrenList(File[] files) {
107
        public ChildrenList(File[] files) {
Lines 98-104 Link Here
98
        }
110
        }
99
        // These methods need not be called with the read lock held
111
        // These methods need not be called with the read lock held
100
        // (see Phadhail.getChildren Javadoc).
112
        // (see Phadhail.getChildren Javadoc).
101
        public Object get(int i) {
113
        public Phadhail get(int i) {
102
            Phadhail ph = kids[i];
114
            Phadhail ph = kids[i];
103
            if (ph == null) {
115
            if (ph == null) {
104
                ph = forFile(files[i], factory());
116
                ph = forFile(files[i], factory());
Lines 133-139 Link Here
133
    public final void addPhadhailListener(PhadhailListener l) {
145
    public final void addPhadhailListener(PhadhailListener l) {
134
        synchronized (LISTENER_LOCK) {
146
        synchronized (LISTENER_LOCK) {
135
            if (listeners == null) {
147
            if (listeners == null) {
136
                listeners = new ArrayList();
148
                listeners = new ArrayList<PhadhailListener>();
137
            }
149
            }
138
            listeners.add(l);
150
            listeners.add(l);
139
        }
151
        }
Lines 153-159 Link Here
153
    private final PhadhailListener[] listeners() {
165
    private final PhadhailListener[] listeners() {
154
        synchronized (LISTENER_LOCK) {
166
        synchronized (LISTENER_LOCK) {
155
            if (listeners != null) {
167
            if (listeners != null) {
156
                return (PhadhailListener[])listeners.toArray(new PhadhailListener[listeners.size()]);
168
                return listeners.toArray(new PhadhailListener[listeners.size()]);
157
            } else {
169
            } else {
158
                return null;
170
                return null;
159
            }
171
            }
Lines 168-175 Link Here
168
                    firing = true;
180
                    firing = true;
169
                    try {
181
                    try {
170
                        PhadhailEvent ev = PhadhailEvent.create(AbstractPhadhail.this);
182
                        PhadhailEvent ev = PhadhailEvent.create(AbstractPhadhail.this);
171
                        for (int i = 0; i < l.length; i++) {
183
                        for (PhadhailListener listener : l) {
172
                            l[i].childrenChanged(ev);
184
                            listener.childrenChanged(ev);
173
                        }
185
                        }
174
                    } finally {
186
                    } finally {
175
                        firing = false;
187
                        firing = false;
Lines 187-194 Link Here
187
                    firing = true;
199
                    firing = true;
188
                    try {
200
                    try {
189
                        PhadhailNameEvent ev = PhadhailNameEvent.create(AbstractPhadhail.this, oldName, newName);
201
                        PhadhailNameEvent ev = PhadhailNameEvent.create(AbstractPhadhail.this, oldName, newName);
190
                        for (int i = 0; i < l.length; i++) {
202
                        for (PhadhailListener listener : l) {
191
                            l[i].nameChanged(ev);
203
                            listener.nameChanged(ev);
192
                        }
204
                        }
193
                    } finally {
205
                    } finally {
194
                        firing = false;
206
                        firing = false;
Lines 212-230 Link Here
212
        File oldFile = f;
224
        File oldFile = f;
213
        f = newFile;
225
        f = newFile;
214
        synchronized (AbstractPhadhail.class) {
226
        synchronized (AbstractPhadhail.class) {
215
            Map instances2 = instancesForFactory(factory());
227
            Map<File,Reference<AbstractPhadhail>> instances2 = instancesForFactory(factory());
216
            instances2.remove(oldFile);
228
            instances2.remove(oldFile);
217
            instances2.put(newFile, new WeakReference(this));
229
            instances2.put(newFile, new WeakReference<AbstractPhadhail>(this));
218
        }
230
        }
219
        fireNameChanged(oldName, nue);
231
        fireNameChanged(oldName, nue);
220
        if (hasChildren()) {
232
        if (hasChildren()) {
221
            // Fire changes in path of children too.
233
            // Fire changes in path of children too.
222
            List recChildren = new ArrayList(100); // List<AbstractPhadhail>
234
            List<AbstractPhadhail> recChildren = new ArrayList<AbstractPhadhail>(100);
223
            String prefix = oldFile.getAbsolutePath() + File.separatorChar;
235
            String prefix = oldFile.getAbsolutePath() + File.separatorChar;
224
            synchronized (AbstractPhadhail.class) {
236
            synchronized (AbstractPhadhail.class) {
225
                Iterator it = instancesForFactory(factory()).values().iterator();
237
                for (Reference<AbstractPhadhail> r : instancesForFactory(factory()).values()) {
226
                while (it.hasNext()) {
238
                    AbstractPhadhail ph = r.get();
227
                    AbstractPhadhail ph = (AbstractPhadhail)((Reference)it.next()).get();
228
                    if (ph != null && ph != this && ph.getPath().startsWith(prefix)) {
239
                    if (ph != null && ph != this && ph.getPath().startsWith(prefix)) {
229
                        recChildren.add(ph);
240
                        recChildren.add(ph);
230
                    }
241
                    }
Lines 232-240 Link Here
232
            }
243
            }
233
            // Do the notification after traversing the instances map, since
244
            // Do the notification after traversing the instances map, since
234
            // we cannot mutate the map while an iterator is active.
245
            // we cannot mutate the map while an iterator is active.
235
            Iterator it = recChildren.iterator();
246
            for (AbstractPhadhail ph : recChildren) {
236
            while (it.hasNext()) {
247
                ph.parentRenamed(oldFile, newFile);
237
                ((AbstractPhadhail)it.next()).parentRenamed(oldFile, newFile);
238
            }
248
            }
239
        }
249
        }
240
    }
250
    }
Lines 249-257 Link Here
249
        File oldFile = f;
259
        File oldFile = f;
250
        f = new File(prefix + suffix);
260
        f = new File(prefix + suffix);
251
        synchronized (AbstractPhadhail.class) {
261
        synchronized (AbstractPhadhail.class) {
252
            Map instances2 = instancesForFactory(factory());
262
            Map<File,Reference<AbstractPhadhail>> instances2 = instancesForFactory(factory());
253
            instances2.remove(oldFile);
263
            instances2.remove(oldFile);
254
            instances2.put(f, new WeakReference(this));
264
            instances2.put(f, new WeakReference<AbstractPhadhail>(this));
255
        }
265
        }
256
        fireNameChanged(null, null);
266
        fireNameChanged(null, null);
257
    }
267
    }
(-)threaddemo/model/BufferedPhadhail.java (-22 / +20 lines)
Lines 24-38 Link Here
24
 */
31
 */
25
final class BufferedPhadhail implements Phadhail, PhadhailListener {
32
final class BufferedPhadhail implements Phadhail, PhadhailListener {
26
    
33
    
27
    private static final Map instances = new WeakHashMap(); // Map<Phadhail,Reference<BufferedPhadhail>>
34
    private static final Map<Phadhail, Reference<BufferedPhadhail>> instances = new WeakHashMap<Phadhail,Reference<BufferedPhadhail>>();
28
    
35
    
29
    public static Phadhail forPhadhail(Phadhail ph) {
36
    public static Phadhail forPhadhail(Phadhail ph) {
30
        if (ph.hasChildren() && !(ph instanceof BufferedPhadhail)) {
37
        if (ph.hasChildren() && !(ph instanceof BufferedPhadhail)) {
31
            Reference r = (Reference)instances.get(ph);
38
            Reference<BufferedPhadhail> r = instances.get(ph);
32
            BufferedPhadhail bph = (r != null) ? (BufferedPhadhail)r.get() : null;
39
            BufferedPhadhail bph = (r != null) ? r.get() : null;
33
            if (bph == null) {
40
            if (bph == null) {
34
                bph = new BufferedPhadhail(ph);
41
                bph = new BufferedPhadhail(ph);
35
                instances.put(ph, new WeakReference(bph));
42
                instances.put(ph, new WeakReference<BufferedPhadhail>(bph));
36
            }
43
            }
37
            return bph;
44
            return bph;
38
        } else {
45
        } else {
Lines 41-76 Link Here
41
    }
48
    }
42
    
49
    
43
    private final Phadhail ph;
50
    private final Phadhail ph;
44
    private Reference kids; // Reference<List<Phadhail>>
51
    private Reference<List<Phadhail>> kids;
45
    private List listeners = null; // List<PhadhailListener>
52
    private List<PhadhailListener> listeners = null;
46
    
53
    
47
    private BufferedPhadhail(Phadhail ph) {
54
    private BufferedPhadhail(Phadhail ph) {
48
        this.ph = ph;
55
        this.ph = ph;
49
    }
56
    }
50
    
57
    
51
    public List getChildren() {
58
    public List<Phadhail> getChildren() {
52
        List phs = null; // List<Phadhail>
59
        List<Phadhail> phs = null;
53
        if (kids != null) {
60
        if (kids != null) {
54
            phs = (List)kids.get();
61
            phs = kids.get();
55
        }
62
        }
56
        if (phs == null) {
63
        if (phs == null) {
57
            // Need to (re)calculate the children.
64
            // Need to (re)calculate the children.
58
            phs = new BufferedChildrenList(ph.getChildren());
65
            phs = new BufferedChildrenList(ph.getChildren());
59
            kids = new WeakReference(phs);
66
            kids = new WeakReference<List<Phadhail>>(phs);
60
        }
67
        }
61
        return phs;
68
        return phs;
62
    }
69
    }
63
    
70
    
64
    private static final class BufferedChildrenList extends AbstractList {
71
    private static final class BufferedChildrenList extends AbstractList<Phadhail> {
65
        private final List orig; // List<Phadhail>
72
        private final List<Phadhail> orig;
66
        private final Phadhail[] kids;
73
        private final Phadhail[] kids;
67
        public BufferedChildrenList(List orig) {
74
        public BufferedChildrenList(List<Phadhail> orig) {
68
            this.orig = orig;
75
            this.orig = orig;
69
            kids = new Phadhail[orig.size()];
76
            kids = new Phadhail[orig.size()];
70
        }
77
        }
71
        public Object get(int i) {
78
        public Phadhail get(int i) {
72
            if (kids[i] == null) {
79
            if (kids[i] == null) {
73
                kids[i] = forPhadhail((Phadhail)orig.get(i));
80
                kids[i] = forPhadhail(orig.get(i));
74
            }
81
            }
75
             return kids[i];
82
             return kids[i];
76
        }
83
        }
Lines 94-100 Link Here
94
    public void addPhadhailListener(PhadhailListener l) {
101
    public void addPhadhailListener(PhadhailListener l) {
95
        if (listeners == null) {
102
        if (listeners == null) {
96
            ph.addPhadhailListener(this);
103
            ph.addPhadhailListener(this);
97
            listeners = new ArrayList();
104
            listeners = new ArrayList<PhadhailListener>();
98
        }
105
        }
99
        listeners.add(l);
106
        listeners.add(l);
100
    }
107
    }
Lines 138-146 Link Here
138
        kids = null;
145
        kids = null;
139
        if (listeners != null) {
146
        if (listeners != null) {
140
            PhadhailEvent ev2 = PhadhailEvent.create(this);
147
            PhadhailEvent ev2 = PhadhailEvent.create(this);
141
            Iterator it = listeners.iterator();
148
            for (PhadhailListener l : listeners) {
142
            while (it.hasNext()) {
149
                l.childrenChanged(ev2);
143
                ((PhadhailListener)it.next()).childrenChanged(ev2);
144
            }
150
            }
145
        }
151
        }
146
    }
152
    }
Lines 148-156 Link Here
148
    public void nameChanged(PhadhailNameEvent ev) {
154
    public void nameChanged(PhadhailNameEvent ev) {
149
        if (listeners != null) {
155
        if (listeners != null) {
150
            PhadhailNameEvent ev2 = PhadhailNameEvent.create(this, ev.getOldName(), ev.getNewName());
156
            PhadhailNameEvent ev2 = PhadhailNameEvent.create(this, ev.getOldName(), ev.getNewName());
151
            Iterator it = listeners.iterator();
157
            for (PhadhailListener l : listeners) {
152
            while (it.hasNext()) {
158
                l.nameChanged(ev2);
153
                ((PhadhailListener)it.next()).nameChanged(ev2);
154
            }
159
            }
155
        }
160
        }
156
    }
161
    }
(-)threaddemo/model/EventHybridLockedPhadhail.java (-68 / +44 lines)
Lines 28-34 Link Here
28
 */
29
 */
29
final class EventHybridLockedPhadhail extends AbstractPhadhail {
30
final class EventHybridLockedPhadhail extends AbstractPhadhail {
30
    
31
    
31
    private static final Factory FACTORY = new Factory() {
32
    private static final AbstractPhadhail.Factory FACTORY = new AbstractPhadhail.Factory() {
32
        public AbstractPhadhail create(File f) {
33
        public AbstractPhadhail create(File f) {
33
            return new EventHybridLockedPhadhail(f);
34
            return new EventHybridLockedPhadhail(f);
34
        }
35
        }
Lines 46-156 Link Here
46
        return FACTORY;
47
        return FACTORY;
47
    }
48
    }
48
    
49
    
49
    public List getChildren() {
50
    public List<Phadhail> getChildren() {
50
        return (List)Locks.eventHybrid().read(new LockAction() {
51
        return Locks.eventHybrid().read(new LockAction<List<Phadhail>>() {
51
            public Object run() {
52
            public List<Phadhail> run() {
52
                return EventHybridLockedPhadhail.super.getChildren();
53
                return EventHybridLockedPhadhail.super.getChildren();
53
            }
54
            }
54
        });
55
        });
55
    }
56
    }
56
    
57
    
57
    public String getName() {
58
    public String getName() {
58
        return (String)Locks.eventHybrid().read(new LockAction() {
59
        return Locks.eventHybrid().read(new LockAction<String>() {
59
            public Object run() {
60
            public String run() {
60
                return EventHybridLockedPhadhail.super.getName();
61
                return EventHybridLockedPhadhail.super.getName();
61
            }
62
            }
62
        });
63
        });
63
    }
64
    }
64
    
65
    
65
    public String getPath() {
66
    public String getPath() {
66
        return (String)Locks.eventHybrid().read(new LockAction() {
67
        return Locks.eventHybrid().read(new LockAction<String>() {
67
            public Object run() {
68
            public String run() {
68
                return EventHybridLockedPhadhail.super.getPath();
69
                return EventHybridLockedPhadhail.super.getPath();
69
            }
70
            }
70
        });
71
        });
71
    }
72
    }
72
    
73
    
73
    public boolean hasChildren() {
74
    public boolean hasChildren() {
74
        return ((Boolean)Locks.eventHybrid().read(new LockAction() {
75
        return Locks.eventHybrid().read(new LockAction<Boolean>() {
75
            public Object run() {
76
            public Boolean run() {
76
                return EventHybridLockedPhadhail.super.hasChildren() ? Boolean.TRUE : Boolean.FALSE;
77
                return EventHybridLockedPhadhail.super.hasChildren();
77
            }
78
            }
78
        })).booleanValue();
79
        });
79
    }
80
    }
80
    
81
    
81
    public void rename(final String nue) throws IOException {
82
    public void rename(final String nue) throws IOException {
82
        try {
83
        Locks.eventHybrid().write(new LockExceptionAction<Void,IOException>() {
83
            Locks.eventHybrid().write(new LockExceptionAction() {
84
            public Void run() throws IOException {
84
                public Object run() throws IOException {
85
                EventHybridLockedPhadhail.super.rename(nue);
85
                    EventHybridLockedPhadhail.super.rename(nue);
86
                return null;
86
                    return null;
87
            }
87
                }
88
        });
88
            });
89
        } catch (InvocationTargetException e) {
90
            throw (IOException)e.getCause();
91
        }
92
    }
89
    }
93
    
90
    
94
    public Phadhail createContainerPhadhail(final String name) throws IOException {
91
    public Phadhail createContainerPhadhail(final String name) throws IOException {
95
        try {
92
        return Locks.eventHybrid().write(new LockExceptionAction<Phadhail,IOException>() {
96
            return (Phadhail)Locks.eventHybrid().write(new LockExceptionAction() {
93
            public Phadhail run() throws IOException {
97
                public Object run() throws IOException {
94
                return EventHybridLockedPhadhail.super.createContainerPhadhail(name);
98
                    return EventHybridLockedPhadhail.super.createContainerPhadhail(name);
95
            }
99
                }
96
        });
100
            });
101
        } catch (InvocationTargetException e) {
102
            throw (IOException)e.getCause();
103
        }
104
    }
97
    }
105
    
98
    
106
    public Phadhail createLeafPhadhail(final String name) throws IOException {
99
    public Phadhail createLeafPhadhail(final String name) throws IOException {
107
        try {
100
        return Locks.eventHybrid().write(new LockExceptionAction<Phadhail,IOException>() {
108
            return (Phadhail)Locks.eventHybrid().write(new LockExceptionAction() {
101
            public Phadhail run() throws IOException {
109
                public Object run() throws IOException {
102
                return EventHybridLockedPhadhail.super.createLeafPhadhail(name);
110
                    return EventHybridLockedPhadhail.super.createLeafPhadhail(name);
103
            }
111
                }
104
        });
112
            });
113
        } catch (InvocationTargetException e) {
114
            throw (IOException)e.getCause();
115
        }
116
    }
105
    }
117
    
106
    
118
    public void delete() throws IOException {
107
    public void delete() throws IOException {
119
        try {
108
        Locks.eventHybrid().write(new LockExceptionAction<Void,IOException>() {
120
            Locks.eventHybrid().write(new LockExceptionAction() {
109
            public Void run() throws IOException {
121
                public Object run() throws IOException {
110
                EventHybridLockedPhadhail.super.delete();
122
                    EventHybridLockedPhadhail.super.delete();
111
                return null;
123
                    return null;
112
            }
124
                }
113
        });
125
            });
126
        } catch (InvocationTargetException e) {
127
            throw (IOException)e.getCause();
128
        }
129
    }
114
    }
130
    
115
    
131
    public InputStream getInputStream() throws IOException {
116
    public InputStream getInputStream() throws IOException {
132
        try {
117
        return Locks.eventHybrid().read(new LockExceptionAction<InputStream,IOException>() {
133
            return (InputStream)Locks.eventHybrid().read(new LockExceptionAction() {
118
            public InputStream run() throws IOException {
134
                public Object run() throws IOException {
119
                return EventHybridLockedPhadhail.super.getInputStream();
135
                    return EventHybridLockedPhadhail.super.getInputStream();
120
            }
136
                }
121
        });
137
            });
138
        } catch (InvocationTargetException e) {
139
            throw (IOException)e.getCause();
140
        }
141
    }
122
    }
142
    
123
    
143
    public OutputStream getOutputStream() throws IOException {
124
    public OutputStream getOutputStream() throws IOException {
144
        // See comments in AbstractPhadhail.getOutputStream.
125
        // See comments in AbstractPhadhail.getOutputStream.
145
        try {
126
        return Locks.eventHybrid().read(new LockExceptionAction<OutputStream,IOException>() {
146
            return (OutputStream)Locks.eventHybrid().read(new LockExceptionAction() {
127
            public OutputStream run() throws IOException {
147
                public Object run() throws IOException {
128
                return EventHybridLockedPhadhail.super.getOutputStream();
148
                    return EventHybridLockedPhadhail.super.getOutputStream();
129
            }
149
                }
130
        });
150
            });
151
        } catch (InvocationTargetException e) {
152
            throw (IOException)e.getCause();
153
        }
154
    }
131
    }
155
    
132
    
156
    public Lock lock() {
133
    public Lock lock() {
(-)threaddemo/model/LockedPhadhail.java (-2 / +2 lines)
Lines 33-39 Link Here
33
        Locks.readWrite("LP", PLOCK, 0);
35
        Locks.readWrite("LP", PLOCK, 0);
34
    }
36
    }
35
    
37
    
36
    private static final Factory FACTORY = new Factory() {
38
    private static final AbstractPhadhail.Factory FACTORY = new AbstractPhadhail.Factory() {
37
        public AbstractPhadhail create(File f) {
39
        public AbstractPhadhail create(File f) {
38
            return new LockedPhadhail(f);
40
            return new LockedPhadhail(f);
39
        }
41
        }
Lines 51-57 Link Here
51
        return FACTORY;
53
        return FACTORY;
52
    }
54
    }
53
    
55
    
54
    public List getChildren() {
56
    public List<Phadhail> getChildren() {
55
        PLOCK.enterRead();
57
        PLOCK.enterRead();
56
        try {
58
        try {
57
            return super.getChildren();
59
            return super.getChildren();
(-)threaddemo/model/MonitoredPhadhail.java (-2 / +2 lines)
Lines 31-37 Link Here
31
    private static final Object LOCK = new LOCK();
33
    private static final Object LOCK = new LOCK();
32
    private static final Lock MLOCK = Locks.monitor(LOCK, 0);
34
    private static final Lock MLOCK = Locks.monitor(LOCK, 0);
33
    
35
    
34
    private static final Factory FACTORY = new Factory() {
36
    private static final AbstractPhadhail.Factory FACTORY = new AbstractPhadhail.Factory() {
35
        public AbstractPhadhail create(File f) {
37
        public AbstractPhadhail create(File f) {
36
            return new MonitoredPhadhail(f);
38
            return new MonitoredPhadhail(f);
37
        }
39
        }
Lines 49-55 Link Here
49
        return FACTORY;
51
        return FACTORY;
50
    }
52
    }
51
    
53
    
52
    public List getChildren() {
54
    public List<Phadhail> getChildren() {
53
        synchronized (LOCK) {
55
        synchronized (LOCK) {
54
            return super.getChildren();
56
            return super.getChildren();
55
        }
57
        }
(-)threaddemo/model/Phadhail.java (-1 / +1 lines)
Lines 44-56 Link Here
44
    
44
    
45
    List getChildren();
45
    List<Phadhail> getChildren();
46
    
46
    
47
    /** delete this phadhail (must not have children) */
47
    /** delete this phadhail (must not have children) */
48
    void delete() throws IOException;
48
    void delete() throws IOException;
(-)threaddemo/model/SpunPhadhail.java (-11 / +12 lines)
Lines 35-51 Link Here
35
        }
40
        }
36
    };
41
    };
37
    
42
    
38
    private static final Map instances = new WeakHashMap(); // Map<Phadhail,Reference<Phadhail>>
43
    private static final Map<Phadhail, Reference<Phadhail>> instances = new WeakHashMap<Phadhail,Reference<Phadhail>>();
39
    
44
    
40
    /** factory */
45
    /** factory */
41
    public static Phadhail forPhadhail(Phadhail _ph) {
46
    public static Phadhail forPhadhail(Phadhail _ph) {
42
        assert EventQueue.isDispatchThread();
47
        assert EventQueue.isDispatchThread();
43
        Reference r = (Reference)instances.get(_ph);
48
        Reference<Phadhail> r = instances.get(_ph);
44
        Phadhail ph = (r != null) ? (Phadhail)r.get() : null;
49
        Phadhail ph = (r != null) ? r.get() : null;
45
        if (ph == null) {
50
        if (ph == null) {
46
            Spin spin = new SpunPhadhail(_ph);
51
            Spin spin = new SpunPhadhail(_ph);
47
            ph = BufferedPhadhail.forPhadhail((Phadhail)spin.getProxy());
52
            ph = BufferedPhadhail.forPhadhail((Phadhail)spin.getProxy());
48
            instances.put(_ph, new WeakReference(ph));
53
            instances.put(_ph, new WeakReference<Phadhail>(ph));
49
        }
54
        }
50
        return ph;
55
        return ph;
51
    }
56
    }
Lines 89-96 Link Here
89
                return forPhadhail((Phadhail)result);
94
                return forPhadhail((Phadhail)result);
90
            } else if (result instanceof List) {
95
            } else if (result instanceof List) {
91
                // I.e. from getChildren(). Need to wrap result phadhails.
96
                // I.e. from getChildren(). Need to wrap result phadhails.
92
                List phs = (List)result; // List<Phadhail>
97
                @SuppressWarnings("unchecked")
93
                return new SpunChildrenList(phs);
98
                List<Phadhail> l = (List<Phadhail>) result;
99
                return new SpunChildrenList(l);
94
            } else {
100
            } else {
95
                // Just pass on the call.
101
                // Just pass on the call.
96
                return result;
102
                return result;
Lines 98-114 Link Here
98
        }
104
        }
99
    }
105
    }
100
    
106
    
101
    private static final class SpunChildrenList extends AbstractList {
107
    private static final class SpunChildrenList extends AbstractList<Phadhail> {
102
        private final List orig; // List<Phadhail>
108
        private final List<Phadhail> orig;
103
        private final Phadhail[] kids;
109
        private final Phadhail[] kids;
104
        public SpunChildrenList(List orig) {
110
        public SpunChildrenList(List<Phadhail> orig) {
105
            this.orig = orig;
111
            this.orig = orig;
106
            kids = new Phadhail[orig.size()];
112
            kids = new Phadhail[orig.size()];
107
        }
113
        }
108
        public Object get(int i) {
114
        public Phadhail get(int i) {
109
            assert EventQueue.isDispatchThread();
115
            assert EventQueue.isDispatchThread();
110
            if (kids[i] == null) {
116
            if (kids[i] == null) {
111
                kids[i] = forPhadhail((Phadhail)orig.get(i));
117
                kids[i] = forPhadhail(orig.get(i));
112
            }
118
            }
113
            return kids[i];
119
            return kids[i];
114
        }
120
        }
(-)threaddemo/model/SwungPhadhail.java (-86 / +51 lines)
Lines 42-57 Link Here
42
    
50
    
43
    private static final Logger logger = Logger.getLogger(SwungPhadhail.class.getName());
51
    private static final Logger logger = Logger.getLogger(SwungPhadhail.class.getName());
44
    
52
    
45
    private static final Map instances = new WeakHashMap(); // Map<Phadhail,Reference<Phadhail>>
53
    private static final Map<Phadhail, Reference<Phadhail>> instances = new WeakHashMap<Phadhail,Reference<Phadhail>>();
46
    
54
    
47
    /** factory */
55
    /** factory */
48
    public static Phadhail forPhadhail(Phadhail _ph) {
56
    public static Phadhail forPhadhail(Phadhail _ph) {
49
        assert EventQueue.isDispatchThread();
57
        assert EventQueue.isDispatchThread();
50
        Reference r = (Reference)instances.get(_ph);
58
        Reference<Phadhail> r = instances.get(_ph);
51
        Phadhail ph = (r != null) ? (Phadhail)r.get() : null;
59
        Phadhail ph = (r != null) ? r.get() : null;
52
        if (ph == null) {
60
        if (ph == null) {
53
            ph = new SwungPhadhail(_ph);
61
            ph = new SwungPhadhail(_ph);
54
            instances.put(_ph, new WeakReference(ph));
62
            instances.put(_ph, new WeakReference<Phadhail>(ph));
55
        }
63
        }
56
        return ph;
64
        return ph;
57
    }
65
    }
Lines 60-69 Link Here
60
    private String name = null;
68
    private String name = null;
61
    private String path = null;
69
    private String path = null;
62
    private boolean computingName = false;
70
    private boolean computingName = false;
63
    private List children = null; // List<Phadhail>
71
    private List<Phadhail> children = null;
64
    private boolean computingChildren = false;
72
    private boolean computingChildren = false;
65
    private Boolean leaf = null;
73
    private Boolean leaf = null;
66
    private List listeners = null; // List<PhadhailListener>
74
    private List<PhadhailListener> listeners = null;
67
    
75
    
68
    private SwungPhadhail(Phadhail ph) {
76
    private SwungPhadhail(Phadhail ph) {
69
        this.ph = ph;
77
        this.ph = ph;
Lines 74-82 Link Here
74
        // XXX synch on listeners to get them, then release
82
        // XXX synch on listeners to get them, then release
75
        if (listeners != null) {
83
        if (listeners != null) {
76
            PhadhailNameEvent ev = PhadhailNameEvent.create(this, null, null);
84
            PhadhailNameEvent ev = PhadhailNameEvent.create(this, null, null);
77
            Iterator it = listeners.iterator();
85
            for (PhadhailListener l : listeners) {
78
            while (it.hasNext()) {
79
                PhadhailListener l = (PhadhailListener)it.next();
80
                logger.log(Level.FINER, "fireNameChanged for {0} to {1}", new Object[] {this, l});
86
                logger.log(Level.FINER, "fireNameChanged for {0} to {1}", new Object[] {this, l});
81
                l.nameChanged(ev);
87
                l.nameChanged(ev);
82
            }
88
            }
Lines 123-145 Link Here
123
    
129
    
124
    private Phadhail createPhadhail(final String name, final boolean container) throws IOException {
130
    private Phadhail createPhadhail(final String name, final boolean container) throws IOException {
125
        assert EventQueue.isDispatchThread();
131
        assert EventQueue.isDispatchThread();
126
        Phadhail orig;
132
        return forPhadhail(Worker.block(new LockExceptionAction<Phadhail,IOException>() {
127
        try {
133
            public Phadhail run() throws IOException {
128
            orig = (Phadhail)Worker.block(new LockExceptionAction() {
134
                if (container) {
129
                public Object run() throws IOException {
135
                    return ph.createContainerPhadhail(name);
130
                    if (container) {
136
                } else {
131
                        return ph.createContainerPhadhail(name);
137
                    return ph.createLeafPhadhail(name);
132
                    } else {
133
                        return ph.createLeafPhadhail(name);
134
                    }
135
                }
138
                }
136
            });
139
            }
137
        } catch (IOException e) {
140
        }));
138
            throw e;
139
        } catch (Exception e) {
140
            throw new Error(e);
141
        }
142
        return forPhadhail(orig);
143
    }
141
    }
144
    
142
    
145
    public Phadhail createContainerPhadhail(String name) throws IOException {
143
    public Phadhail createContainerPhadhail(String name) throws IOException {
Lines 152-185 Link Here
152
    
150
    
153
    public void rename(final String nue) throws IOException {
151
    public void rename(final String nue) throws IOException {
154
        assert EventQueue.isDispatchThread();
152
        assert EventQueue.isDispatchThread();
155
        try {
153
        Worker.block(new LockExceptionAction<Void,IOException>() {
156
            Worker.block(new LockExceptionAction() {
154
            public Void run() throws IOException {
157
                public Object run() throws IOException {
155
                ph.rename(nue);
158
                    ph.rename(nue);
156
                return null;
159
                    return null;
157
            }
160
                }
158
        });
161
            });
162
        } catch (IOException e) {
163
            throw e;
164
        } catch (Exception e) {
165
            assert false : e;
166
        }
167
    }
159
    }
168
    
160
    
169
    public void delete() throws IOException {
161
    public void delete() throws IOException {
170
        assert EventQueue.isDispatchThread();
162
        assert EventQueue.isDispatchThread();
171
        try {
163
        Worker.block(new LockExceptionAction<Void,IOException>() {
172
            Worker.block(new LockExceptionAction() {
164
            public Void run() throws IOException {
173
                public Object run() throws IOException {
165
                ph.delete();
174
                    ph.delete();
166
                return null;
175
                    return null;
167
            }
176
                }
168
        });
177
            });
178
        } catch (IOException e) {
179
            throw e;
180
        } catch (Exception e) {
181
            assert false : e;
182
        }
183
    }
169
    }
184
    
170
    
185
    private void fireChildrenChanged() {
171
    private void fireChildrenChanged() {
Lines 188-201 Link Here
188
        if (listeners != null) {
174
        if (listeners != null) {
189
            logger.finer("fireChildrenChanged");
175
            logger.finer("fireChildrenChanged");
190
            PhadhailEvent ev = PhadhailEvent.create(this);
176
            PhadhailEvent ev = PhadhailEvent.create(this);
191
            Iterator it = listeners.iterator();
177
            for (PhadhailListener l : listeners) {
192
            while (it.hasNext()) {
178
                l.childrenChanged(ev);
193
                ((PhadhailListener)it.next()).childrenChanged(ev);
194
            }
179
            }
195
        }
180
        }
196
    }
181
    }
197
    
182
    
198
    public List getChildren() {
183
    public List<Phadhail> getChildren() {
199
        assert EventQueue.isDispatchThread();
184
        assert EventQueue.isDispatchThread();
200
        if (children != null) {
185
        if (children != null) {
201
            return children;
186
            return children;
Lines 204-210 Link Here
204
                computingChildren = true;
189
                computingChildren = true;
205
                Worker.start(new Runnable() {
190
                Worker.start(new Runnable() {
206
                    public void run() {
191
                    public void run() {
207
                        final List ch = ph.getChildren();
192
                        final List<Phadhail> ch = ph.getChildren();
208
                        SwingUtilities.invokeLater(new Runnable() {
193
                        SwingUtilities.invokeLater(new Runnable() {
209
                            public void run() {
194
                            public void run() {
210
                                children = new SwungChildrenList(ch);
195
                                children = new SwungChildrenList(ch);
Lines 215-235 Link Here
215
                    }
200
                    }
216
                });
201
                });
217
            }
202
            }
218
            return Collections.EMPTY_LIST;
203
            return Collections.emptyList();
219
        }
204
        }
220
    }
205
    }
221
    
206
    
222
    private static final class SwungChildrenList extends AbstractList {
207
    private static final class SwungChildrenList extends AbstractList<Phadhail> {
223
        private final List orig; // List<Phadhail>
208
        private final List<Phadhail> orig;
224
        private final Phadhail[] kids;
209
        private final Phadhail[] kids;
225
        public SwungChildrenList(List orig) {
210
        public SwungChildrenList(List<Phadhail> orig) {
226
            this.orig = orig;
211
            this.orig = orig;
227
            kids = new Phadhail[orig.size()];
212
            kids = new Phadhail[orig.size()];
228
        }
213
        }
229
        public Object get(int i) {
214
        public Phadhail get(int i) {
230
            assert EventQueue.isDispatchThread();
215
            assert EventQueue.isDispatchThread();
231
            if (kids[i] == null) {
216
            if (kids[i] == null) {
232
                kids[i] = forPhadhail((Phadhail)orig.get(i));
217
                kids[i] = forPhadhail(orig.get(i));
233
            }
218
            }
234
             return kids[i];
219
             return kids[i];
235
        }
220
        }
Lines 241-272 Link Here
241
    
226
    
242
    public InputStream getInputStream() throws IOException {
227
    public InputStream getInputStream() throws IOException {
243
        assert EventQueue.isDispatchThread();
228
        assert EventQueue.isDispatchThread();
244
        try {
229
        return Worker.block(new LockExceptionAction<InputStream,IOException>() {
245
            return (InputStream)Worker.block(new LockExceptionAction() {
230
            public InputStream run() throws IOException {
246
                public Object run() throws IOException {
231
                return ph.getInputStream();
247
                    return ph.getInputStream();
232
            }
248
                }
233
        });
249
            });
250
        } catch (IOException e) {
251
            throw e;
252
        } catch (Exception e) {
253
            throw new Error(e);
254
        }
255
    }
234
    }
256
    
235
    
257
    public OutputStream getOutputStream() throws IOException {
236
    public OutputStream getOutputStream() throws IOException {
258
        assert EventQueue.isDispatchThread();
237
        assert EventQueue.isDispatchThread();
259
        try {
238
        return Worker.block(new LockExceptionAction<OutputStream,IOException>() {
260
            return (OutputStream)Worker.block(new LockExceptionAction() {
239
            public OutputStream run() throws IOException {
261
                public Object run() throws IOException {
240
                return ph.getOutputStream();
262
                    return ph.getOutputStream();
241
            }
263
                }
242
        });
264
            });
265
        } catch (IOException e) {
266
            throw e;
267
        } catch (Exception e) {
268
            throw new Error(e);
269
        }
270
    }
243
    }
271
    
244
    
272
    public boolean hasChildren() {
245
    public boolean hasChildren() {
Lines 274-283 Link Here
274
        logger.log(Level.FINER, "hasChildren on {0}", this);
247
        logger.log(Level.FINER, "hasChildren on {0}", this);
275
        if (leaf == null) {
248
        if (leaf == null) {
276
            logger.finer("not cached");
249
            logger.finer("not cached");
277
            leaf = (Boolean)Worker.block(new LockAction() {
250
            leaf = Worker.block(new LockAction<Boolean>() {
278
                public Object run() {
251
                public Boolean run() {
279
                    logger.finer("hasChildren: working...");
252
                    logger.finer("hasChildren: working...");
280
                    return ph.hasChildren() ? Boolean.FALSE : Boolean.TRUE;
253
                    return ph.hasChildren();
281
                }
254
                }
282
            });
255
            });
283
            logger.log(Level.FINER, "leaf={0}", leaf);
256
            logger.log(Level.FINER, "leaf={0}", leaf);
Lines 287-293 Link Here
287
    
260
    
288
    public synchronized void addPhadhailListener(PhadhailListener l) {
261
    public synchronized void addPhadhailListener(PhadhailListener l) {
289
        if (listeners == null) {
262
        if (listeners == null) {
290
            listeners = new ArrayList();
263
            listeners = new ArrayList<PhadhailListener>();
291
            ph.addPhadhailListener(SwungPhadhail.this);
264
            ph.addPhadhailListener(SwungPhadhail.this);
292
        }
265
        }
293
        listeners.add(l);
266
        listeners.add(l);
(-)threaddemo/model/Worker.java (-25 / +34 lines)
Lines 31-37 Link Here
31
    
33
    
32
    private static final Worker DEFAULT = new Worker();
34
    private static final Worker DEFAULT = new Worker();
33
    
35
    
34
    private final LinkedList tasks = new LinkedList(); // List<Runnable>
36
    private final LinkedList<Runnable> tasks = new LinkedList<Runnable>();
35
    
37
    
36
    private Worker() {
38
    private Worker() {
37
        super("threaddemo.model.Worker");
39
        super("threaddemo.model.Worker");
Lines 51-57 Link Here
51
                        ie.printStackTrace();
53
                        ie.printStackTrace();
52
                    }
54
                    }
53
                }
55
                }
54
                next = (Runnable)tasks.removeFirst();
56
                next = tasks.removeFirst();
55
                logger.log(Level.FINER, "fetching {0}", next);
57
                logger.log(Level.FINER, "fetching {0}", next);
56
            }
58
            }
57
            try {
59
            try {
Lines 82-95 Link Here
82
    /**
84
    /**
83
     * Do something and wait for it to finish.
85
     * Do something and wait for it to finish.
84
     */
86
     */
85
    public static Object block(final LockAction act) {
87
    public static <T> T block(final LockAction<T> act) {
86
        final Object[] result = new Object[2];
88
        final List<T> result = new ArrayList<T>(1);
87
        start(new Runnable() {
89
        start(new Runnable() {
88
            public void run() {
90
            public void run() {
89
                Object val = act.run();
91
                T val = act.run();
90
                synchronized (result) {
92
                synchronized (result) {
91
                    result[0] = val;
93
                    result.add(val);
92
                    result[1] = Boolean.TRUE;
93
                    result.notify();
94
                    result.notify();
94
                }
95
                }
95
            }
96
            }
Lines 98-111 Link Here
98
            }
99
            }
99
        });
100
        });
100
        synchronized (result) {
101
        synchronized (result) {
101
            while (result[1] == null) {
102
            while (result.isEmpty()) {
102
                try {
103
                try {
103
                    result.wait();
104
                    result.wait();
104
                } catch (InterruptedException ie) {
105
                } catch (InterruptedException ie) {
105
                    ie.printStackTrace();
106
                    ie.printStackTrace();
106
                }
107
                }
107
            }
108
            }
108
            return result[0];
109
            return result.get(0);
110
        }
111
    }
112
    
113
    private static final class Holder<T, E extends Exception> {
114
        public final T object;
115
        public final E exception;
116
        public Holder(T object) {
117
            this.object = object;
118
            this.exception = null;
119
        }
120
        public Holder(E exception) {
121
            this.object = null;
122
            this.exception = exception;
109
        }
123
        }
110
    }
124
    }
111
    
125
    
Lines 113-135 Link Here
113
     * Do something and wait for it to finish.
127
     * Do something and wait for it to finish.
114
     * May throw exceptions.
128
     * May throw exceptions.
115
     */
129
     */
116
    public static Object block(final LockExceptionAction act) throws Exception {
130
    public static <T, E extends Exception> T block(final LockExceptionAction<T,E> act) throws E {
117
        final Object[] result = new Object[3];
131
        final List<Holder<T,E>> result = new ArrayList<Holder<T,E>>(1);
118
        start(new Runnable() {
132
        start(new Runnable() {
119
            public void run() {
133
            public void run() {
120
                Object val;
134
                Holder<T,E> h;
121
                Exception ex;
122
                try {
135
                try {
123
                    val = act.run();
136
                    h = new Holder<T,E>(act.run());
124
                    ex = null;
125
                } catch (Exception e) {
137
                } catch (Exception e) {
126
                    val = null;
138
                    @SuppressWarnings("unchecked")
127
                    ex = e;
139
                    E _e = (E) e;
140
                    h = new Holder<T,E>(_e);
128
                }
141
                }
129
                synchronized (result) {
142
                synchronized (result) {
130
                    result[0] = val;
143
                    result.add(h);
131
                    result[1] = ex;
132
                    result[2] = Boolean.TRUE;
133
                    result.notify();
144
                    result.notify();
134
                }
145
                }
135
            }
146
            }
Lines 138-157 Link Here
138
            }
149
            }
139
        });
150
        });
140
        synchronized (result) {
151
        synchronized (result) {
141
            while (result[2] == null) {
152
            while (result.isEmpty()) {
142
                try {
153
                try {
143
                    result.wait();
154
                    result.wait();
144
                } catch (InterruptedException ie) {
155
                } catch (InterruptedException ie) {
145
                    ie.printStackTrace();
156
                    ie.printStackTrace();
146
                }
157
                }
147
            }
158
            }
148
            if (result[1] != null) {
159
            Holder<T,E> h = result.get(0);
149
                throw (Exception)result[1];
160
            if (h.exception != null) {
161
                throw h.exception;
150
            } else {
162
            } else {
151
                return result[0];
163
                return h.object;
152
            }
164
            }
153
        }
165
        }
154
    }
166
    }
155
    
167
    
156
}
168
}
157
(-)threaddemo/util/DocumentParseSupport.java (-29 / +21 lines)
Lines 33-43 Link Here
33
 * writing to the text document from the model.
35
 * writing to the text document from the model.
34
 * <p>The underlying model is a text document. The deltas to the underlying model
36
 * <p>The underlying model is a text document. The deltas to the underlying model
35
 * in this implementation are document text changes or reload events, though that
37
 * in this implementation are document text changes or reload events, though that
36
 * fact is not visible to subclasses. The derived model must be defined by the
38
 * fact should not matter to subclasses. The derived model must be defined by the
37
 * subclass.
39
 * subclass.
38
 * @author Jesse Glick
40
 * @author Jesse Glick
39
 */
41
 */
40
public abstract class DocumentParseSupport extends TwoWaySupport {
42
public abstract class DocumentParseSupport<DM,DMD> extends TwoWaySupport<DM, DocumentParseSupportDelta, DMD> {
41
    
43
    
42
    private static final Logger logger = Logger.getLogger(DocumentParseSupport.class.getName());
44
    private static final Logger logger = Logger.getLogger(DocumentParseSupport.class.getName());
43
    
45
    
Lines 67-84 Link Here
67
     * of {@link org.openide.cookies.EditorCookie.Observable#PROP_DOCUMENT} indicating that the whole
69
     * of {@link org.openide.cookies.EditorCookie.Observable#PROP_DOCUMENT} indicating that the whole
68
     * document changed (was reloaded, for example), or lists of {@link DocumentEvent}s.
70
     * document changed (was reloaded, for example), or lists of {@link DocumentEvent}s.
69
     */
71
     */
70
    protected final Object composeUnderlyingDeltas(Object underlyingDelta1, Object underlyingDelta2) {
72
    protected final DocumentParseSupportDelta composeUnderlyingDeltas(DocumentParseSupportDelta underlyingDelta1, DocumentParseSupportDelta underlyingDelta2) {
71
        assert underlyingDelta1 instanceof PropertyChangeEvent || underlyingDelta1 instanceof List;
73
        if (underlyingDelta1.changeEvent != null) {
72
        assert underlyingDelta2 instanceof PropertyChangeEvent || underlyingDelta2 instanceof List;
73
        if (underlyingDelta1 instanceof PropertyChangeEvent) {
74
            // PROP_DOCUMENT that is. Need to recreate the whole thing generally.
74
            // PROP_DOCUMENT that is. Need to recreate the whole thing generally.
75
            return underlyingDelta1;
75
            return underlyingDelta1;
76
        } else if (underlyingDelta2 instanceof PropertyChangeEvent) {
76
        } else if (underlyingDelta2.changeEvent != null) {
77
            // Ditto.
77
            // Ditto.
78
            return underlyingDelta2;
78
            return underlyingDelta2;
79
        } else {
79
        } else {
80
            // Append changes.
80
            // Append changes.
81
            ((List)underlyingDelta1).addAll((List)underlyingDelta2);
81
            underlyingDelta1.documentEvents.addAll(underlyingDelta2.documentEvents);
82
            return underlyingDelta1;
82
            return underlyingDelta1;
83
        }
83
        }
84
    }
84
    }
Lines 132-153 Link Here
132
     * Parse the document.
132
     * Parse the document.
133
     * Calls {@link #doDerive(StyledDocument, List, Object)}.
133
     * Calls {@link #doDerive(StyledDocument, List, Object)}.
134
     */
134
     */
135
    protected final DerivationResult doDerive(final Object oldValue, Object underlyingDelta) throws Exception {
135
    protected final DerivationResult<DM,DMD> doDerive(final DM oldValue, final DocumentParseSupportDelta underlyingDelta) throws Exception {
136
        if (document == null) {
136
        if (document == null) {
137
            refreshDocument(requiresUnmodifiedDocument());
137
            refreshDocument(requiresUnmodifiedDocument());
138
        }
138
        }
139
        final List documentEvents; // List<DocumentEvent>
139
        final List<DerivationResult<DM,DMD>> val = new ArrayList<DerivationResult<DM,DMD>>(1);
140
        if (underlyingDelta instanceof List) {
141
            documentEvents = (List)underlyingDelta;
142
        } else {
143
            documentEvents = null;
144
        }
145
        final DerivationResult[] val = new DerivationResult[1];
146
        final Exception[] exc = new Exception[1];
140
        final Exception[] exc = new Exception[1];
147
        Runnable r = new Runnable() {
141
        Runnable r = new Runnable() {
148
            public void run() {
142
            public void run() {
149
                try {
143
                try {
150
                    val[0] = doDerive(document, documentEvents, oldValue);
144
                    val.add(doDerive(document, underlyingDelta != null ? underlyingDelta.documentEvents : null, oldValue));
151
                } catch (Exception e) {
145
                } catch (Exception e) {
152
                    exc[0] = e;
146
                    exc[0] = e;
153
                }
147
                }
Lines 161-167 Link Here
161
        if (exc[0] != null) {
155
        if (exc[0] != null) {
162
            throw exc[0];
156
            throw exc[0];
163
        }
157
        }
164
        return val[0];
158
        return val.get(0);
165
    }
159
    }
166
    
160
    
167
    /**
161
    /**
Lines 198-221 Link Here
198
     * @return the new derived model value plus the change made to it
192
     * @return the new derived model value plus the change made to it
199
     * @throws Exception (checked) in case of parsing problems
193
     * @throws Exception (checked) in case of parsing problems
200
     */
194
     */
201
    protected abstract DerivationResult doDerive(StyledDocument document, List documentEvents, Object oldValue) throws Exception;
195
    protected abstract DerivationResult<DM,DMD> doDerive(StyledDocument document, List<DocumentEvent> documentEvents, DM oldValue) throws Exception;
202
    
196
    
203
    /**
197
    /**
204
     * Regenerates the document.
198
     * Regenerates the document.
205
     * Calls {@link #doRecreate(StyledDocument, Object, Object)}.
199
     * Calls {@link #doRecreate(StyledDocument, Object, Object)}.
206
     */
200
     */
207
    protected final Object doRecreate(final Object oldValue, final Object derivedDelta) throws Exception {
201
    protected final DM doRecreate(final DM oldValue, final DMD derivedDelta) throws Exception {
208
        if (document == null) {
202
        if (document == null) {
209
            refreshDocument(true);
203
            refreshDocument(true);
210
        }
204
        }
211
        final Object[] val = new Object[1];
205
        final List<DM> val = new ArrayList<DM>(1);
212
        final Exception[] exc = new Exception[1];
206
        final Exception[] exc = new Exception[1];
213
        Runnable r = new Runnable() {
207
        Runnable r = new Runnable() {
214
            public void run() {
208
            public void run() {
215
                document.removeDocumentListener(listener);
209
                document.removeDocumentListener(listener);
216
                assert --listenerCount == 0;
210
                assert --listenerCount == 0;
217
                try {
211
                try {
218
                    val[0] = doRecreate(document, oldValue, derivedDelta);
212
                    val.add(doRecreate(document, oldValue, derivedDelta));
219
                } catch (Exception e) {
213
                } catch (Exception e) {
220
                    exc[0] = e;
214
                    exc[0] = e;
221
                } finally {
215
                } finally {
Lines 232-238 Link Here
232
        if (exc[0] != null) {
226
        if (exc[0] != null) {
233
            throw exc[0];
227
            throw exc[0];
234
        }
228
        }
235
        return val[0];
229
        return val.get(0);
236
    }
230
    }
237
    
231
    
238
    /**
232
    /**
Lines 255-261 Link Here
255
     * @return the new derived model
249
     * @return the new derived model
256
     * @see org.openide.text.NbDocument.WriteLockable
250
     * @see org.openide.text.NbDocument.WriteLockable
257
     */
251
     */
258
    protected abstract Object doRecreate(StyledDocument document, Object oldValue, Object derivedDelta) throws Exception;
252
    protected abstract DM doRecreate(StyledDocument document, DM oldValue, DMD derivedDelta) throws Exception;
259
    
253
    
260
    /**
254
    /**
261
     * Listens to changes in identity or content of the text document.
255
     * Listens to changes in identity or content of the text document.
Lines 275-285 Link Here
275
        }
269
        }
276
        
270
        
277
        private void documentUpdate(DocumentEvent e) {
271
        private void documentUpdate(DocumentEvent e) {
278
            final List l = new ArrayList(1); // List<DocumentEvent>
272
            final List<DocumentEvent> l = new ArrayList<DocumentEvent>(1);
279
            l.add(e);
273
            l.add(e);
280
            getLock().read(new LockAction() {
274
            getLock().read(new LockAction<Void>() {
281
                public Object run() {
275
                public Void run() {
282
                    invalidate(l);
276
                    invalidate(new DocumentParseSupportDelta(l));
283
                    return null;
277
                    return null;
284
                }
278
                }
285
            });
279
            });
Lines 303-309 Link Here
303
                // the EQ with CES.open or .openDocument.
297
                // the EQ with CES.open or .openDocument.
304
                getLock().readLater(new Runnable() {
298
                getLock().readLater(new Runnable() {
305
                    public void run() {
299
                    public void run() {
306
                        invalidate(evt);
300
                        invalidate(new DocumentParseSupportDelta(evt));
307
                    }
301
                    }
308
                });
302
                });
309
            }
303
            }
(-)threaddemo/util/TwoWayEvent.java (-35 / +43 lines)
Lines 21-29 Link Here
21
 * @author Jesse Glick
21
 * @author Jesse Glick
22
 * @see TwoWaySupport
22
 * @see TwoWaySupport
23
 */
23
 */
24
public abstract class TwoWayEvent extends EventObject {
24
public abstract class TwoWayEvent<DM, UMD, DMD> extends EventObject {
25
    
25
    
26
    private TwoWayEvent(TwoWaySupport s) {
26
    private TwoWayEvent(TwoWaySupport<DM, UMD, DMD> s) {
27
        super(s);
27
        super(s);
28
        assert s != null;
28
        assert s != null;
29
    }
29
    }
Lines 32-49 Link Here
32
     * Get the associated two-way support.
32
     * Get the associated two-way support.
33
     * @return the support
33
     * @return the support
34
     */
34
     */
35
    public TwoWaySupport getTwoWaySupport() {
35
    public TwoWaySupport<DM, UMD, DMD> getTwoWaySupport() {
36
        return (TwoWaySupport)getSource();
36
        @SuppressWarnings("unchecked")
37
        TwoWaySupport<DM, UMD, DMD> source = (TwoWaySupport<DM, UMD, DMD>) getSource();
38
        return source;
37
    }
39
    }
38
    
40
    
39
    /**
41
    /**
40
     * Event indicating a derived value has been produced.
42
     * Event indicating a derived value has been produced.
41
     */
43
     */
42
    public static final class Derived extends TwoWayEvent {
44
    public static final class Derived<DM, UMD, DMD> extends TwoWayEvent<DM, UMD, DMD> {
43
        
45
        
44
        private final Object oldValue, newValue, derivedDelta, underlyingDelta;
46
        private final DM oldValue, newValue;
47
        private final DMD derivedDelta;
48
        private final UMD underlyingDelta;
45
        
49
        
46
        Derived(TwoWaySupport s, Object oldValue, Object newValue, Object derivedDelta, Object underlyingDelta) {
50
        Derived(TwoWaySupport<DM, UMD, DMD> s, DM oldValue, DM newValue, DMD derivedDelta, UMD underlyingDelta) {
47
            super(s);
51
            super(s);
48
            this.oldValue = oldValue;
52
            this.oldValue = oldValue;
49
            assert newValue != null;
53
            assert newValue != null;
Lines 57-63 Link Here
57
         * Get the old value of the derived model.
61
         * Get the old value of the derived model.
58
         * @return the old value, or null if it was never calculated
62
         * @return the old value, or null if it was never calculated
59
         */
63
         */
60
        public Object getOldValue() {
64
        public DM getOldValue() {
61
            return oldValue;
65
            return oldValue;
62
        }
66
        }
63
        
67
        
Lines 65-71 Link Here
65
         * Get the new value of the derived model.
69
         * Get the new value of the derived model.
66
         * @return the new value
70
         * @return the new value
67
         */
71
         */
68
        public Object getNewValue() {
72
        public DM getNewValue() {
69
            return newValue;
73
            return newValue;
70
        }
74
        }
71
        
75
        
Lines 73-79 Link Here
73
         * Get the change to the derived model.
77
         * Get the change to the derived model.
74
         * @return the delta, or null if the old value was null
78
         * @return the delta, or null if the old value was null
75
         */
79
         */
76
        public Object getDerivedDelta() {
80
        public DMD getDerivedDelta() {
77
            return derivedDelta;
81
            return derivedDelta;
78
        }
82
        }
79
        
83
        
Lines 84-90 Link Here
84
         * @return the invalidating change to the underlying model, or null if
88
         * @return the invalidating change to the underlying model, or null if
85
         *         the derived model is simply being computed for the first time
89
         *         the derived model is simply being computed for the first time
86
         */
90
         */
87
        public Object getUnderlyingDelta() {
91
        public UMD getUnderlyingDelta() {
88
            return underlyingDelta;
92
            return underlyingDelta;
89
        }
93
        }
90
        
94
        
Lines 97-107 Link Here
97
    /**
101
    /**
98
     * Event indicating a derived model has been invalidated.
102
     * Event indicating a derived model has been invalidated.
99
     */
103
     */
100
    public static final class Invalidated extends TwoWayEvent {
104
    public static final class Invalidated<DM, UMD, DMD> extends TwoWayEvent<DM, UMD, DMD> {
101
        
105
        
102
        private final Object oldValue, underlyingDelta;
106
        private final DM oldValue;
107
        private final UMD underlyingDelta;
103
        
108
        
104
        Invalidated(TwoWaySupport s, Object oldValue, Object underlyingDelta) {
109
        Invalidated(TwoWaySupport<DM, UMD, DMD> s, DM oldValue, UMD underlyingDelta) {
105
            super(s);
110
            super(s);
106
            assert oldValue != null;
111
            assert oldValue != null;
107
            this.oldValue = oldValue;
112
            this.oldValue = oldValue;
Lines 113-119 Link Here
113
         * Get the old value of the derived model that is now invalid.
118
         * Get the old value of the derived model that is now invalid.
114
         * @return the old value
119
         * @return the old value
115
         */
120
         */
116
        public Object getOldValue() {
121
        public DM getOldValue() {
117
            return oldValue;
122
            return oldValue;
118
        }
123
        }
119
        
124
        
Lines 121-127 Link Here
121
         * Get the change to the underlying model that triggered this invalidation.
126
         * Get the change to the underlying model that triggered this invalidation.
122
         * @return the invalidating change to the underlying model
127
         * @return the invalidating change to the underlying model
123
         */
128
         */
124
        public Object getUnderlyingDelta() {
129
        public UMD getUnderlyingDelta() {
125
            return underlyingDelta;
130
            return underlyingDelta;
126
        }
131
        }
127
        
132
        
Lines 134-144 Link Here
134
    /**
139
    /**
135
     * Event indicating the derived model was changed and the underlying model recreated.
140
     * Event indicating the derived model was changed and the underlying model recreated.
136
     */
141
     */
137
    public static final class Recreated extends TwoWayEvent {
142
    public static final class Recreated<DM, UMD, DMD> extends TwoWayEvent<DM, UMD, DMD> {
138
        
143
        
139
        private final Object oldValue, newValue, derivedDelta;
144
        private final DM oldValue, newValue;
145
        private final DMD derivedDelta;
140
        
146
        
141
        Recreated(TwoWaySupport s, Object oldValue, Object newValue, Object derivedDelta) {
147
        Recreated(TwoWaySupport<DM, UMD, DMD> s, DM oldValue, DM newValue, DMD derivedDelta) {
142
            super(s);
148
            super(s);
143
            assert oldValue != null;
149
            assert oldValue != null;
144
            this.oldValue = oldValue;
150
            this.oldValue = oldValue;
Lines 152-158 Link Here
152
         * Get the old value of the derived model that is now invalid.
158
         * Get the old value of the derived model that is now invalid.
153
         * @return the old value
159
         * @return the old value
154
         */
160
         */
155
        public Object getOldValue() {
161
        public DM getOldValue() {
156
            return oldValue;
162
            return oldValue;
157
        }
163
        }
158
        
164
        
Lines 160-166 Link Here
160
         * Get the new value of the derived model.
166
         * Get the new value of the derived model.
161
         * @return the new value
167
         * @return the new value
162
         */
168
         */
163
        public Object getNewValue() {
169
        public DM getNewValue() {
164
            return newValue;
170
            return newValue;
165
        }
171
        }
166
        
172
        
Lines 169-175 Link Here
169
         * model as well.
175
         * model as well.
170
         * @return the delta to the derived model
176
         * @return the delta to the derived model
171
         */
177
         */
172
        public Object getDerivedDelta() {
178
        public DMD getDerivedDelta() {
173
            return derivedDelta;
179
            return derivedDelta;
174
        }
180
        }
175
        
181
        
Lines 183-193 Link Here
183
     * Event indicating changes in the underlying model were clobbered by changes to
189
     * Event indicating changes in the underlying model were clobbered by changes to
184
     * the derived model.
190
     * the derived model.
185
     */
191
     */
186
    public static final class Clobbered extends TwoWayEvent {
192
    public static final class Clobbered<DM, UMD, DMD> extends TwoWayEvent<DM, UMD, DMD> {
187
        
193
        
188
        private final Object oldValue, newValue, derivedDelta;
194
        private final DM oldValue, newValue;
195
        private final DMD derivedDelta;
189
        
196
        
190
        Clobbered(TwoWaySupport s, Object oldValue, Object newValue, Object derivedDelta) {
197
        Clobbered(TwoWaySupport<DM, UMD, DMD> s, DM oldValue, DM newValue, DMD derivedDelta) {
191
            super(s);
198
            super(s);
192
            this.oldValue = oldValue;
199
            this.oldValue = oldValue;
193
            assert newValue != null;
200
            assert newValue != null;
Lines 200-206 Link Here
200
         * Get the old value of the derived model that is now invalid.
207
         * Get the old value of the derived model that is now invalid.
201
         * @return the old value, or null if it was never calculated
208
         * @return the old value, or null if it was never calculated
202
         */
209
         */
203
        public Object getOldValue() {
210
        public DM getOldValue() {
204
            return oldValue;
211
            return oldValue;
205
        }
212
        }
206
        
213
        
Lines 208-214 Link Here
208
         * Get the new value of the derived model.
215
         * Get the new value of the derived model.
209
         * @return the new value
216
         * @return the new value
210
         */
217
         */
211
        public Object getNewValue() {
218
        public DM getNewValue() {
212
            return newValue;
219
            return newValue;
213
        }
220
        }
214
        
221
        
Lines 217-223 Link Here
217
         * model as well whether it is applicable or not.
224
         * model as well whether it is applicable or not.
218
         * @return the delta to the derived model
225
         * @return the delta to the derived model
219
         */
226
         */
220
        public Object getDerivedDelta() {
227
        public DMD getDerivedDelta() {
221
            return derivedDelta;
228
            return derivedDelta;
222
        }
229
        }
223
        
230
        
Lines 234-242 Link Here
234
     * ever fire this event, since the default implementation creates a strong
241
     * ever fire this event, since the default implementation creates a strong
235
     * reference that cannot be collected.
242
     * reference that cannot be collected.
236
     */
243
     */
237
    public static final class Forgotten extends TwoWayEvent {
244
    public static final class Forgotten<DM, UMD, DMD> extends TwoWayEvent<DM, UMD, DMD> {
238
        
245
        
239
        Forgotten(TwoWaySupport s) {
246
        Forgotten(TwoWaySupport<DM, UMD, DMD> s) {
240
            super(s);
247
            super(s);
241
        }
248
        }
242
        
249
        
Lines 250-262 Link Here
250
     * Event indicating an attempted derivation failed with an exception.
257
     * Event indicating an attempted derivation failed with an exception.
251
     * The underlying model is thus considered to be in an inconsistent state.
258
     * The underlying model is thus considered to be in an inconsistent state.
252
     */
259
     */
253
    public static final class Broken extends TwoWayEvent {
260
    public static final class Broken<DM, UMD, DMD> extends TwoWayEvent<DM, UMD, DMD> {
254
        
261
        
255
        private final Object oldValue, underlyingDelta;
262
        private final DM oldValue;
263
        private final UMD underlyingDelta;
256
        
264
        
257
        private final Exception exception;
265
        private final Exception exception;
258
        
266
        
259
        Broken(TwoWaySupport s, Object oldValue, Object underlyingDelta, Exception exception) {
267
        Broken(TwoWaySupport<DM, UMD, DMD> s, DM oldValue, UMD underlyingDelta, Exception exception) {
260
            super(s);
268
            super(s);
261
            this.oldValue = oldValue;
269
            this.oldValue = oldValue;
262
            this.underlyingDelta = underlyingDelta;
270
            this.underlyingDelta = underlyingDelta;
Lines 268-274 Link Here
268
         * Get the old value of the derived model that is now invalid.
276
         * Get the old value of the derived model that is now invalid.
269
         * @return the old value, or null if it was never calculated
277
         * @return the old value, or null if it was never calculated
270
         */
278
         */
271
        public Object getOldValue() {
279
        public DM getOldValue() {
272
            return oldValue;
280
            return oldValue;
273
        }
281
        }
274
        
282
        
Lines 279-285 Link Here
279
         * @return the invalidating change to the underlying model, or null if
287
         * @return the invalidating change to the underlying model, or null if
280
         *         the derived model is simply being computed for the first time
288
         *         the derived model is simply being computed for the first time
281
         */
289
         */
282
        public Object getUnderlyingDelta() {
290
        public UMD getUnderlyingDelta() {
283
            return underlyingDelta;
291
            return underlyingDelta;
284
        }
292
        }
285
        
293
        
(-)threaddemo/util/TwoWayListener.java (-7 / +7 lines)
Lines 20-64 Link Here
20
 * @author Jesse Glick
20
 * @author Jesse Glick
21
 * @see TwoWaySupport
21
 * @see TwoWaySupport
22
 */
22
 */
23
public interface TwoWayListener extends EventListener {
23
public interface TwoWayListener<DM, UMD, DMD> extends EventListener {
24
    
24
    
25
    /**
25
    /**
26
     * Called when a new derived value has been produced.
26
     * Called when a new derived value has been produced.
27
     * May have been a result of a synchronous or asynchronous derivation.
27
     * May have been a result of a synchronous or asynchronous derivation.
28
     * @param evt the associated event with more information
28
     * @param evt the associated event with more information
29
     */
29
     */
30
    void derived(TwoWayEvent.Derived evt);
30
    void derived(TwoWayEvent.Derived<DM, UMD, DMD> evt);
31
    
31
    
32
    /**
32
    /**
33
     * Called when a derived model has been invalidated.
33
     * Called when a derived model has been invalidated.
34
     * @param evt the associated event with more information
34
     * @param evt the associated event with more information
35
     */
35
     */
36
    void invalidated(TwoWayEvent.Invalidated evt);
36
    void invalidated(TwoWayEvent.Invalidated<DM, UMD, DMD> evt);
37
    
37
    
38
    /**
38
    /**
39
     * Called when the derived model was changed and the underlying model recreated.
39
     * Called when the derived model was changed and the underlying model recreated.
40
     * @param evt the associated event with more information
40
     * @param evt the associated event with more information
41
     */
41
     */
42
    void recreated(TwoWayEvent.Recreated evt);
42
    void recreated(TwoWayEvent.Recreated<DM, UMD, DMD> evt);
43
    
43
    
44
    /**
44
    /**
45
     * Called when changes in the underlying model were clobbered by changes to
45
     * Called when changes in the underlying model were clobbered by changes to
46
     * the derived model.
46
     * the derived model.
47
     * @param evt the associated event with more information
47
     * @param evt the associated event with more information
48
     */
48
     */
49
    void clobbered(TwoWayEvent.Clobbered evt);
49
    void clobbered(TwoWayEvent.Clobbered<DM, UMD, DMD> evt);
50
    
50
    
51
    /**
51
    /**
52
     * Called when the reference to the derived model was garbage collected.
52
     * Called when the reference to the derived model was garbage collected.
53
     * @param evt the associated event
53
     * @param evt the associated event
54
     */
54
     */
55
    void forgotten(TwoWayEvent.Forgotten evt);
55
    void forgotten(TwoWayEvent.Forgotten<DM, UMD, DMD> evt);
56
    
56
    
57
    /**
57
    /**
58
     * Called when an attempted derivation failed with an exception.
58
     * Called when an attempted derivation failed with an exception.
59
     * The underlying model is thus considered to be in an inconsistent state.
59
     * The underlying model is thus considered to be in an inconsistent state.
60
     * @param evt the associated event with more information
60
     * @param evt the associated event with more information
61
     */
61
     */
62
    void broken(TwoWayEvent.Broken evt);
62
    void broken(TwoWayEvent.Broken<DM, UMD, DMD> evt);
63
    
63
    
64
}
64
}
(-)threaddemo/util/TwoWaySupport.java (-70 / +76 lines)
Lines 151-157 Link Here
151
 *
159
 *
152
 * @author Jesse Glick
160
 * @author Jesse Glick
153
 */
161
 */
154
public abstract class TwoWaySupport {
162
public abstract class TwoWaySupport<DM, UMD, DMD> {
155
    
163
    
156
    /** logging support */
164
    /** logging support */
157
    private static final Logger logger = Logger.getLogger(TwoWaySupport.class.getName());
165
    private static final Logger logger = Logger.getLogger(TwoWaySupport.class.getName());
Lines 160-169 Link Here
160
    private static final Object LOCK = new String("TwoWaySupport");
168
    private static final Object LOCK = new String("TwoWaySupport");
161
    
169
    
162
    /** supports which are scheduled to be derived but haven't been yet */
170
    /** supports which are scheduled to be derived but haven't been yet */
163
    private static final SortedSet toDerive = new TreeSet(); // SortedSet<DeriveTask>
171
    private static final SortedSet<DeriveTask> toDerive = new TreeSet<DeriveTask>();
164
    
172
    
165
    /** derivation tasks indexed by support */
173
    /** derivation tasks indexed by support */
166
    private static final Map tasks = new WeakHashMap(); // Map<TwoWaySupport,DeriveTask>
174
    private static final Map<TwoWaySupport,DeriveTask> tasks = new WeakHashMap<TwoWaySupport,DeriveTask>();
167
    
175
    
168
    /** derivation thread when it has been started */
176
    /** derivation thread when it has been started */
169
    private static boolean startedThread = false;
177
    private static boolean startedThread = false;
Lines 172-187 Link Here
172
    private static ReferenceQueue queue = null;
180
    private static ReferenceQueue queue = null;
173
    
181
    
174
    /** reverse lookup for model field to support queue collector */
182
    /** reverse lookup for model field to support queue collector */
175
    private static final Map referencesToSupports = new WeakHashMap(); // Map<Reference<Object>,Reference<TwoWaySupport>>
183
    private static final Map<Reference<Object>,Reference<TwoWaySupport>> referencesToSupports = new WeakHashMap<Reference<Object>,Reference<TwoWaySupport>>();
176
    
184
    
177
    /** associated lock */
185
    /** associated lock */
178
    private final Lock lock;
186
    private final Lock lock;
179
    
187
    
180
    /** listener list */
188
    /** listener list */
181
    private final List listeners; // List<TwoWayListener>
189
    private final List<TwoWayListener<DM, UMD, DMD>> listeners;
182
    
190
    
183
    /** current derived model, if any */
191
    /** current derived model, if any */
184
    private Reference model = null; // Reference<Object>
192
    private Reference<DM> model = null;
185
    
193
    
186
    /** current derivation problem, if any */
194
    /** current derivation problem, if any */
187
    private Exception problem = null; // XXX should perhaps be Reference<Exception>?
195
    private Exception problem = null; // XXX should perhaps be Reference<Exception>?
Lines 193-199 Link Here
193
    private boolean active = false;
201
    private boolean active = false;
194
    
202
    
195
    /** underlying delta, if one is being processed thru initiate + doDerive */
203
    /** underlying delta, if one is being processed thru initiate + doDerive */
196
    private Object underlyingDelta = null;
204
    private UMD underlyingDelta = null;
197
    
205
    
198
    /** currently in doRecreate() */
206
    /** currently in doRecreate() */
199
    private boolean mutating = false;
207
    private boolean mutating = false;
Lines 208-214 Link Here
208
     */
216
     */
209
    protected TwoWaySupport(Lock lock) {
217
    protected TwoWaySupport(Lock lock) {
210
        this.lock = lock;
218
        this.lock = lock;
211
        listeners = new ArrayList();
219
        listeners = new ArrayList<TwoWayListener<DM, UMD, DMD>>();
212
    }
220
    }
213
    
221
    
214
    /**
222
    /**
Lines 249-255 Link Here
249
     *         the old value) plus the derived delta
257
     *         the old value) plus the derived delta
250
     * @throws Exception (checked only!) if derivation of the model failed
258
     * @throws Exception (checked only!) if derivation of the model failed
251
     */
259
     */
252
    protected abstract DerivationResult doDerive(Object oldValue, Object underlyingDelta) throws Exception;
260
    protected abstract DerivationResult<DM, DMD> doDerive(DM oldValue, UMD underlyingDelta) throws Exception;
253
    
261
    
254
    /**
262
    /**
255
     * Result of a derivation. Includes both the final resulting value, and the
263
     * Result of a derivation. Includes both the final resulting value, and the
Lines 257-265 Link Here
257
     * to pass to {@link TwoWayEvent.Derived}, which may be useful for subclasses
265
     * to pass to {@link TwoWayEvent.Derived}, which may be useful for subclasses
258
     * firing changes.
266
     * firing changes.
259
     */
267
     */
260
    protected final static class DerivationResult {
268
    protected final static class DerivationResult<DM, DMD> {
261
        final Object newValue;
269
        final DM newValue;
262
        final Object derivedDelta;
270
        final DMD derivedDelta;
263
        /**
271
        /**
264
         * Create a derivation result wrapper object.
272
         * Create a derivation result wrapper object.
265
         * @param newValue the new value of the derived model
273
         * @param newValue the new value of the derived model
Lines 267-273 Link Here
267
         *                     model; must be null if the old derived value was null,
275
         *                     model; must be null if the old derived value was null,
268
         *                     and only then
276
         *                     and only then
269
         */
277
         */
270
        public DerivationResult(Object newValue, Object derivedDelta) {
278
        public DerivationResult(DM newValue, DMD derivedDelta) {
271
            if (newValue == null) throw new NullPointerException();
279
            if (newValue == null) throw new NullPointerException();
272
            this.newValue = newValue;
280
            this.newValue = newValue;
273
            this.derivedDelta = derivedDelta;
281
            this.derivedDelta = derivedDelta;
Lines 286-292 Link Here
286
     * @param underlyingDelta2 the newer delta
294
     * @param underlyingDelta2 the newer delta
287
     * @return a delta representing those two changes applied in sequence
295
     * @return a delta representing those two changes applied in sequence
288
     */
296
     */
289
    protected abstract Object composeUnderlyingDeltas(Object underlyingDelta1, Object underlyingDelta2);
297
    protected abstract UMD composeUnderlyingDeltas(UMD underlyingDelta1, UMD underlyingDelta2);
290
    
298
    
291
    /**
299
    /**
292
     * Recreate the underlying model from the derived model.
300
     * Recreate the underlying model from the derived model.
Lines 307-313 Link Here
307
     *         the old value)
315
     *         the old value)
308
     * @throws Exception (checked only!) if recreation of the underlying model failed
316
     * @throws Exception (checked only!) if recreation of the underlying model failed
309
     */
317
     */
310
    protected abstract Object doRecreate(Object oldValue, Object derivedDelta) throws Exception;
318
    protected abstract DM doRecreate(DM oldValue, DMD derivedDelta) throws Exception;
311
    
319
    
312
    private void assertStateConsistent() {
320
    private void assertStateConsistent() {
313
        assert Thread.holdsLock(LOCK);
321
        assert Thread.holdsLock(LOCK);
Lines 332-340 Link Here
332
     *                                   and threw an exception (possibly from an
340
     *                                   and threw an exception (possibly from an
333
     *                                   earlier derivation run that is still broken)
341
     *                                   earlier derivation run that is still broken)
334
     */
342
     */
335
    public final Object getValueBlocking() throws InvocationTargetException {
343
    public final DM getValueBlocking() throws InvocationTargetException {
336
        assert lock.canRead();
344
        assert lock.canRead();
337
        Object old;
345
        DM old;
338
        synchronized (LOCK) {
346
        synchronized (LOCK) {
339
            assertStateConsistent();
347
            assertStateConsistent();
340
            assert !mutating;
348
            assert !mutating;
Lines 346-352 Link Here
346
                } catch (InterruptedException e) {/* OK */}
354
                } catch (InterruptedException e) {/* OK */}
347
            }
355
            }
348
            if (fresh) {
356
            if (fresh) {
349
                Object o = model.get();
357
                DM o = model.get();
350
                if (o != null) {
358
                if (o != null) {
351
                    logger.log(Level.FINER, "fresh value: {0}", o);
359
                    logger.log(Level.FINER, "fresh value: {0}", o);
352
                    return o;
360
                    return o;
Lines 362-369 Link Here
362
            fresh = false;
370
            fresh = false;
363
        }
371
        }
364
        // Getting the value:
372
        // Getting the value:
365
        DerivationResult result;
373
        DerivationResult<DM, DMD> result;
366
        Object newValue = null;
374
        DM newValue = null;
367
        try {
375
        try {
368
            result = doDerive(old, null);
376
            result = doDerive(old, null);
369
            if (result == null) {
377
            if (result == null) {
Lines 385-391 Link Here
385
        } catch (Exception e) {
393
        } catch (Exception e) {
386
            problem = e;
394
            problem = e;
387
            fresh = false;
395
            fresh = false;
388
            fireChange(new TwoWayEvent.Broken(this, old, underlyingDelta, e));
396
            fireChange(new TwoWayEvent.Broken<DM, UMD, DMD>(this, old, underlyingDelta, e));
389
            throw new InvocationTargetException(e);
397
            throw new InvocationTargetException(e);
390
        } finally {
398
        } finally {
391
            synchronized (LOCK) {
399
            synchronized (LOCK) {
Lines 397-403 Link Here
397
                deactivate();
405
                deactivate();
398
            }
406
            }
399
        }
407
        }
400
        fireChange(new TwoWayEvent.Derived(this, old, result.newValue, result.derivedDelta, underlyingDelta));
408
        fireChange(new TwoWayEvent.Derived<DM, UMD, DMD>(this, old, result.newValue, result.derivedDelta, underlyingDelta));
401
        return result.newValue;
409
        return result.newValue;
402
    }
410
    }
403
    
411
    
Lines 406-412 Link Here
406
        if (active) {
414
        if (active) {
407
            // No longer need to run this.
415
            // No longer need to run this.
408
            active = false;
416
            active = false;
409
            DeriveTask t = (DeriveTask)tasks.remove(this);
417
            DeriveTask t = tasks.remove(this);
410
            assert t != null;
418
            assert t != null;
411
            toDerive.remove(t);
419
            toDerive.remove(t);
412
        }
420
        }
Lines 421-434 Link Here
421
        }
429
        }
422
    }
430
    }
423
    
431
    
424
    private void setModel(Object result) {
432
    private void setModel(DM result) {
425
        assert Thread.holdsLock(LOCK);
433
        assert Thread.holdsLock(LOCK);
426
        assert result != null;
434
        assert result != null;
427
        if (model != null) {
435
        if (model != null) {
428
            referencesToSupports.remove(model);
436
            referencesToSupports.remove(model);
429
        }
437
        }
430
        model = createEnqueuedReference(result);
438
        model = createEnqueuedReference(result);
431
        referencesToSupports.put(model, new WeakReference(this));
439
        @SuppressWarnings("unchecked")
440
        Reference<Object> _model = (Reference<Object>) model;
441
        referencesToSupports.put(_model, new WeakReference<TwoWaySupport>(this));
432
    }
442
    }
433
    
443
    
434
    /**
444
    /**
Lines 437-443 Link Here
437
     * @return the value of the derived model, or null if it is stale or has never
447
     * @return the value of the derived model, or null if it is stale or has never
438
     *         been computed at all
448
     *         been computed at all
439
     */
449
     */
440
    public final Object getValueNonBlocking() {
450
    public final DM getValueNonBlocking() {
441
        assert lock.canRead();
451
        assert lock.canRead();
442
        synchronized (LOCK) {
452
        synchronized (LOCK) {
443
            assertStateConsistent();
453
            assertStateConsistent();
Lines 452-458 Link Here
452
     * @return the value of the derived model, or null if it has never been
462
     * @return the value of the derived model, or null if it has never been
453
     *         computed at all
463
     *         computed at all
454
     */
464
     */
455
    public final Object getStaleValueNonBlocking() {
465
    public final DM getStaleValueNonBlocking() {
456
        assert lock.canRead();
466
        assert lock.canRead();
457
        synchronized (LOCK) {
467
        synchronized (LOCK) {
458
            assertStateConsistent();
468
            assertStateConsistent();
Lines 474-483 Link Here
474
     * @throws InvocationTargetException if <code>doRecreate</code> throws an
484
     * @throws InvocationTargetException if <code>doRecreate</code> throws an
475
     *                                   exception
485
     *                                   exception
476
     */
486
     */
477
    public final Object mutate(Object derivedDelta) throws ClobberException, InvocationTargetException {
487
    public final DM mutate(DMD derivedDelta) throws ClobberException, InvocationTargetException {
478
        if (derivedDelta == null) throw new NullPointerException();
488
        if (derivedDelta == null) throw new NullPointerException();
479
        assert lock.canWrite();
489
        assert lock.canWrite();
480
        Object oldValue;
490
        DM oldValue;
481
        synchronized (LOCK) {
491
        synchronized (LOCK) {
482
            assertStateConsistent();
492
            assertStateConsistent();
483
            assert !mutating;
493
            assert !mutating;
Lines 488-494 Link Here
488
            }
498
            }
489
            mutating = true;
499
            mutating = true;
490
        }
500
        }
491
        Object result = null;
501
        DM result = null;
492
        try {
502
        try {
493
            // XXX should also dequeue if necessary to avoid sequence:
503
            // XXX should also dequeue if necessary to avoid sequence:
494
            // invalidate -> initiate -> [pause] -> mutate -> [pause] -> invalidate -> [pause] -> derive
504
            // invalidate -> initiate -> [pause] -> mutate -> [pause] -> invalidate -> [pause] -> derive
Lines 508-516 Link Here
508
            }
518
            }
509
        }
519
        }
510
        if (fresh) {
520
        if (fresh) {
511
            fireChange(new TwoWayEvent.Recreated(this, oldValue, result, derivedDelta));
521
            fireChange(new TwoWayEvent.Recreated<DM, UMD, DMD>(this, oldValue, result, derivedDelta));
512
        } else {
522
        } else {
513
            fireChange(new TwoWayEvent.Clobbered(this, oldValue, result, derivedDelta));
523
            fireChange(new TwoWayEvent.Clobbered<DM, UMD, DMD>(this, oldValue, result, derivedDelta));
514
        }
524
        }
515
        return result;
525
        return result;
516
    }
526
    }
Lines 522-532 Link Here
522
     * except to call {@link #composeUnderlyingDeltas}.
532
     * except to call {@link #composeUnderlyingDeltas}.
523
     * @param underlyingDelta a change to the underlying model
533
     * @param underlyingDelta a change to the underlying model
524
     */
534
     */
525
    public final void invalidate(Object underlyingDelta) {
535
    public final void invalidate(UMD underlyingDelta) {
526
        if (underlyingDelta == null) throw new NullPointerException();
536
        if (underlyingDelta == null) throw new NullPointerException();
527
        assert lock.canRead();
537
        assert lock.canRead();
528
        boolean wasInited;
538
        boolean wasInited;
529
        Object oldValue;
539
        DM oldValue;
530
        synchronized (LOCK) {
540
        synchronized (LOCK) {
531
            assertStateConsistent();
541
            assertStateConsistent();
532
            assert !mutating;
542
            assert !mutating;
Lines 545-551 Link Here
545
            problem = null;
555
            problem = null;
546
        }
556
        }
547
        if (wasInited && oldValue != null) {
557
        if (wasInited && oldValue != null) {
548
            fireChange(new TwoWayEvent.Invalidated(this, oldValue, underlyingDelta));
558
            fireChange(new TwoWayEvent.Invalidated<DM, UMD, DMD>(this, oldValue, underlyingDelta));
549
        }
559
        }
550
    }
560
    }
551
561
Lines 561-568 Link Here
561
        synchronized (LOCK) {
571
        synchronized (LOCK) {
562
            assertStateConsistent();
572
            assertStateConsistent();
563
            if (!active && !fresh) {
573
            if (!active && !fresh) {
564
                Object oldValue = (model != null) ? model.get() : null;
574
                DM oldValue = (model != null) ? model.get() : null;
565
                DeriveTask t = new DeriveTask(this, oldValue != null || problem != null);
575
                DeriveTask<DM, UMD, DMD> t = new DeriveTask<DM, UMD, DMD>(this, oldValue != null || problem != null);
566
                toDerive.add(t);
576
                toDerive.add(t);
567
                tasks.put(this, t);
577
                tasks.put(this, t);
568
                active = true;
578
                active = true;
Lines 595-601 Link Here
595
     * <p>This method may be called from any thread and will not block.
605
     * <p>This method may be called from any thread and will not block.
596
     * @param l a listener to add
606
     * @param l a listener to add
597
     */
607
     */
598
    public final void addTwoWayListener(TwoWayListener l) {
608
    public final void addTwoWayListener(TwoWayListener<DM, UMD, DMD> l) {
599
        synchronized (listeners) {
609
        synchronized (listeners) {
600
            listeners.add(l);
610
            listeners.add(l);
601
        }
611
        }
Lines 606-612 Link Here
606
     * <p>This method may be called from any thread and will not block.
616
     * <p>This method may be called from any thread and will not block.
607
     * @param l a listener to remove
617
     * @param l a listener to remove
608
     */
618
     */
609
    public final void removeTwoWayListener(TwoWayListener l) {
619
    public final void removeTwoWayListener(TwoWayListener<DM, UMD, DMD> l) {
610
        synchronized (listeners) {
620
        synchronized (listeners) {
611
            listeners.remove(l);
621
            listeners.remove(l);
612
        }
622
        }
Lines 615-644 Link Here
615
    /**
625
    /**
616
     * Fire an event to all listeners in the read lock.
626
     * Fire an event to all listeners in the read lock.
617
     */
627
     */
618
    private void fireChange(final TwoWayEvent e) {
628
    private void fireChange(final TwoWayEvent<DM, UMD, DMD> e) {
619
        final TwoWayListener[] ls;
629
        final List<TwoWayListener<DM, UMD, DMD>> ls;
620
        synchronized (listeners) {
630
        synchronized (listeners) {
621
            if (listeners.isEmpty()) {
631
            if (listeners.isEmpty()) {
622
                return;
632
                return;
623
            }
633
            }
624
            ls = (TwoWayListener[])listeners.toArray(new TwoWayListener[listeners.size()]);
634
            ls = new ArrayList<TwoWayListener<DM, UMD, DMD>>(listeners);
625
        }
635
        }
626
        lock.read(new Runnable() {
636
        lock.read(new Runnable() {
627
            public void run() {
637
            public void run() {
628
                for (int i = 0; i < ls.length; i++) {
638
                for (TwoWayListener<DM, UMD, DMD> l : ls) {
629
                    if (e instanceof TwoWayEvent.Derived) {
639
                    if (e instanceof TwoWayEvent.Derived) {
630
                        ls[i].derived((TwoWayEvent.Derived)e);
640
                        l.derived((TwoWayEvent.Derived<DM, UMD, DMD>) e);
631
                    } else if (e instanceof TwoWayEvent.Invalidated) {
641
                    } else if (e instanceof TwoWayEvent.Invalidated) {
632
                        ls[i].invalidated((TwoWayEvent.Invalidated)e);
642
                        l.invalidated((TwoWayEvent.Invalidated<DM, UMD, DMD>) e);
633
                    } else if (e instanceof TwoWayEvent.Recreated) {
643
                    } else if (e instanceof TwoWayEvent.Recreated) {
634
                        ls[i].recreated((TwoWayEvent.Recreated)e);
644
                        l.recreated((TwoWayEvent.Recreated<DM, UMD, DMD>) e);
635
                    } else if (e instanceof TwoWayEvent.Clobbered) {
645
                    } else if (e instanceof TwoWayEvent.Clobbered) {
636
                        ls[i].clobbered((TwoWayEvent.Clobbered)e);
646
                        l.clobbered((TwoWayEvent.Clobbered<DM, UMD, DMD>) e);
637
                    } else if (e instanceof TwoWayEvent.Forgotten) {
647
                    } else if (e instanceof TwoWayEvent.Forgotten) {
638
                        ls[i].forgotten((TwoWayEvent.Forgotten)e);
648
                        l.forgotten((TwoWayEvent.Forgotten<DM, UMD, DMD>) e);
639
                    } else {
649
                    } else {
640
                        assert e instanceof TwoWayEvent.Broken;
650
                        assert e instanceof TwoWayEvent.Broken;
641
                        ls[i].broken((TwoWayEvent.Broken)e);
651
                        l.broken((TwoWayEvent.Broken<DM, UMD, DMD>) e);
642
                    }
652
                    }
643
                }
653
                }
644
            }
654
            }
Lines 668-675 Link Here
668
        return false;
678
        return false;
669
    }
679
    }
670
    
680
    
671
    private Reference createEnqueuedReference(Object value) {
681
    private Reference<DM> createEnqueuedReference(DM value) {
672
        Reference r = createReference(value, queue);
682
        Reference<DM> r = createReference(value, queue);
673
        if (!(r instanceof StrongReference) && queue == null) {
683
        if (!(r instanceof StrongReference) && queue == null) {
674
            // Well discard that one; optimistically assumed that
684
            // Well discard that one; optimistically assumed that
675
            // createReference is not overridden, in which case we
685
            // createReference is not overridden, in which case we
Lines 692-702 Link Here
692
                    Reference r = queue.remove();
702
                    Reference r = queue.remove();
693
                    TwoWaySupport s;
703
                    TwoWaySupport s;
694
                    synchronized (LOCK) {
704
                    synchronized (LOCK) {
695
                        Reference r2 = (Reference)referencesToSupports.remove(r);
705
                        Reference<TwoWaySupport> r2 = referencesToSupports.remove(r);
696
                        s = (r2 != null) ? (TwoWaySupport)r2.get() : null;
706
                        s = (r2 != null) ? r2.get() : null;
697
                    }
707
                    }
698
                    if (s != null) {
708
                    if (s != null) {
699
                        s.fireChange(new TwoWayEvent.Forgotten(s));
709
                        notify(s);
700
                    }
710
                    }
701
                } catch (InterruptedException e) {
711
                } catch (InterruptedException e) {
702
                    assert false : e;
712
                    assert false : e;
Lines 704-709 Link Here
704
            }
714
            }
705
        }
715
        }
706
        
716
        
717
        @SuppressWarnings("unchecked")
718
        private void notify(TwoWaySupport s) {
719
            s.fireChange(new TwoWayEvent.Forgotten(s));
720
        }
721
        
707
    }
722
    }
708
    
723
    
709
    /**
724
    /**
Lines 718-740 Link Here
718
     * @param q a reference queue supplied by the support
733
     * @param q a reference queue supplied by the support
719
     * @return a reference to the model enqueued on that reference queue
734
     * @return a reference to the model enqueued on that reference queue
720
     */
735
     */
721
    protected Reference createReference(Object value, ReferenceQueue q) {
736
    protected Reference<DM> createReference(DM value, ReferenceQueue q) {
722
        // Does not matter what the queue is.
737
        // Does not matter what the queue is.
723
        return new StrongReference(value);
738
        return new StrongReference<DM>(value);
724
    }
739
    }
725
740
726
    /**
741
    /**
727
     * A strong reference whose referent will not be collected unless the
742
     * A strong reference whose referent will not be collected unless the
728
     * reference is too.
743
     * reference is too.
729
     */
744
     */
730
    private static final class StrongReference extends WeakReference {
745
    private static final class StrongReference<DM> extends WeakReference<DM> {
731
        private Object value;
746
        private DM value;
732
        public StrongReference(Object value) {
747
        public StrongReference(DM value) {
733
            super(value);
748
            super(value);
734
            assert value != null;
749
            assert value != null;
735
            this.value = value;
750
            this.value = value;
736
        }
751
        }
737
        public Object get() {
752
        public DM get() {
738
            return value;
753
            return value;
739
        }
754
        }
740
        public void clear() {
755
        public void clear() {
Lines 743-761 Link Here
743
        }
758
        }
744
    }
759
    }
745
    
760
    
746
    private static final class DeriveTask implements Comparable {
761
    static final class DeriveTask<DM, UMD, DMD> implements Comparable<DeriveTask<DM, UMD, DMD>> {
747
        
762
        
748
        public final Reference support; // Reference<TwoWaySupport>
763
        public final Reference<TwoWaySupport<DM, UMD, DMD>> support;
749
        
764
        
750
        public final long schedule;
765
        public final long schedule;
751
        
766
        
752
        public DeriveTask(TwoWaySupport support, boolean delay) {
767
        public DeriveTask(TwoWaySupport<DM, UMD, DMD> support, boolean delay) {
753
            this.support = new WeakReference(support);
768
            this.support = new WeakReference<TwoWaySupport<DM, UMD, DMD>>(support);
754
            schedule = System.currentTimeMillis() + (delay ? support.delay() : 0L);
769
            schedule = System.currentTimeMillis() + (delay ? support.delay() : 0L);
755
        }
770
        }
756
        
771
        
757
        public int compareTo(Object o) {
772
        public int compareTo(DeriveTask<DM, UMD, DMD> t) {
758
            DeriveTask t = (DeriveTask)o;
759
            if (t == this) return 0;
773
            if (t == this) return 0;
760
            if (schedule > t.schedule) return 1;
774
            if (schedule > t.schedule) return 1;
761
            if (schedule < t.schedule) return -1;
775
            if (schedule < t.schedule) return -1;
Lines 792-800 Link Here
792
                            assert false : e;
806
                            assert false : e;
793
                        }
807
                        }
794
                    }
808
                    }
795
                    Iterator it = toDerive.iterator();
809
                    Iterator<DeriveTask> it = toDerive.iterator();
796
                    DeriveTask t = (DeriveTask)it.next();
810
                    DeriveTask t = it.next();
797
                    s[0] = (TwoWaySupport)t.support.get();
811
                    s[0] = (TwoWaySupport) t.support.get();
798
                    logger.log(Level.FINER, "derivation thread found: {0}", s[0]);
812
                    logger.log(Level.FINER, "derivation thread found: {0}", s[0]);
799
                    if (s[0] == null) {
813
                    if (s[0] == null) {
800
                        // Dead - support was collected before we got to it.
814
                        // Dead - support was collected before we got to it.
Lines 803-809 Link Here
803
                    }
817
                    }
804
                    long now = System.currentTimeMillis();
818
                    long now = System.currentTimeMillis();
805
                    if (t.schedule > now) {
819
                    if (t.schedule > now) {
806
                        logger.log(Level.FINER, "derivation thread deferring: {0} for {1}msec", new Object[] {s[0], new Long(t.schedule - now)});
820
                        logger.log(Level.FINER, "derivation thread deferring: {0} for {1}msec", new Object[] {s[0], t.schedule - now});
807
                        try {
821
                        try {
808
                            LOCK.wait(t.schedule - now);
822
                            LOCK.wait(t.schedule - now);
809
                        } catch (InterruptedException e) {
823
                        } catch (InterruptedException e) {
(-)threaddemo/views/ElementLook.java (-2 / +2 lines)
Lines 120-130 Link Here
120
    
127
    
121
    public List getChildObjects(Object o, Lookup env) {
128
    public List getChildObjects(Object o, Lookup env) {
122
        NodeList nl = ((Element)o).getChildNodes();
129
        NodeList nl = ((Element)o).getChildNodes();
123
        List l = new ArrayList(Math.max(nl.getLength(), 1));
130
        List<Element> l = new ArrayList<Element>(Math.max(nl.getLength(), 1));
124
        for (int i = 0; i < nl.getLength(); i++) {
131
        for (int i = 0; i < nl.getLength(); i++) {
125
            Node n = nl.item(i);
132
            Node n = nl.item(i);
126
            if (n instanceof Element) {
133
            if (n instanceof Element) {
127
                l.add(n);
134
                l.add((Element) n);
128
            }
135
            }
129
        }
136
        }
130
        return l;
137
        return l;
(-)threaddemo/views/PhadhailLook.java (-7 / +7 lines)
Lines 52-61 Link Here
52
    
52
    
53
    private static final Logger logger = Logger.getLogger(PhadhailLook.class.getName());
53
    private static final Logger logger = Logger.getLogger(PhadhailLook.class.getName());
54
    
54
    
55
    private static final Map phadhails2Results = new IdentityHashMap(); // Map<Phadhail,Lookup.Result>
55
    private static final Map<Phadhail,Lookup.Result> phadhails2Results = new IdentityHashMap<Phadhail,Lookup.Result>();
56
    private static final Map results2Phadhails = new IdentityHashMap(); // Map<Lookup.Result,Phadhail>
56
    private static final Map<Lookup.Result,Phadhail> results2Phadhails = new IdentityHashMap<Lookup.Result,Phadhail>();
57
    private static final Map phadhails2DomProviders = new IdentityHashMap(); // Map<Phadhail,DomProvider>
57
    private static final Map<Phadhail,DomProvider> phadhails2DomProviders = new IdentityHashMap<Phadhail,DomProvider>();
58
    private static final Map domProviders2Phadhails = new IdentityHashMap(); // Map<DomProvider,Phadhail>
58
    private static final Map<DomProvider,Phadhail> domProviders2Phadhails = new IdentityHashMap<DomProvider,Phadhail>();
59
    
59
    
60
    PhadhailLook() {
60
    PhadhailLook() {
61
        super("PhadhailLook");
61
        super("PhadhailLook");
Lines 74-86 Link Here
74
    protected void detachFrom(Object o) {
74
    protected void detachFrom(Object o) {
75
        Phadhail ph = (Phadhail)o;
75
        Phadhail ph = (Phadhail)o;
76
        ph.removePhadhailListener(this);
76
        ph.removePhadhailListener(this);
77
        Lookup.Result r = (Lookup.Result)phadhails2Results.remove(ph);
77
        Lookup.Result r = phadhails2Results.remove(ph);
78
        if (r != null) {
78
        if (r != null) {
79
            r.removeLookupListener(this);
79
            r.removeLookupListener(this);
80
            assert results2Phadhails.containsKey(r);
80
            assert results2Phadhails.containsKey(r);
81
            results2Phadhails.remove(r);
81
            results2Phadhails.remove(r);
82
        }
82
        }
83
        DomProvider p = (DomProvider)phadhails2DomProviders.remove(ph);
83
        DomProvider p = phadhails2DomProviders.remove(ph);
84
        if (p != null) {
84
        if (p != null) {
85
            p.removeChangeListener(this);
85
            p.removeChangeListener(this);
86
            assert domProviders2Phadhails.containsKey(p);
86
            assert domProviders2Phadhails.containsKey(p);
Lines 234-240 Link Here
234
    public void stateChanged(ChangeEvent e) {
234
    public void stateChanged(ChangeEvent e) {
235
        logger.finer("got change");
235
        logger.finer("got change");
236
        DomProvider p = (DomProvider)e.getSource();
236
        DomProvider p = (DomProvider)e.getSource();
237
        final Phadhail ph = (Phadhail)domProviders2Phadhails.get(p);
237
        final Phadhail ph = domProviders2Phadhails.get(p);
238
        assert ph != null;
238
        assert ph != null;
239
        Locks.event().readLater(new Runnable() {
239
        Locks.event().readLater(new Runnable() {
240
            public void run() {
240
            public void run() {
(-)threaddemo/views/PhadhailViews.java (-8 / +8 lines)
Lines 114-128 Link Here
114
            super(n, n.isLeaf() ? Children.LEAF : new EQReplannedChildren(n));
114
            super(n, n.isLeaf() ? Children.LEAF : new EQReplannedChildren(n));
115
        }
115
        }
116
        public String getName() {
116
        public String getName() {
117
            return (String)Locks.event().read(new LockAction() {
117
            return Locks.event().read(new LockAction<String>() {
118
                public Object run() {
118
                public String run() {
119
                    return EQReplannedNode.super.getName();
119
                    return EQReplannedNode.super.getName();
120
                }
120
                }
121
            });
121
            });
122
        }
122
        }
123
        public String getDisplayName() {
123
        public String getDisplayName() {
124
            return (String)Locks.event().read(new LockAction() {
124
            return Locks.event().read(new LockAction<String>() {
125
                public Object run() {
125
                public String run() {
126
                    return EQReplannedNode.super.getDisplayName();
126
                    return EQReplannedNode.super.getDisplayName();
127
                }
127
                }
128
            });
128
            });
Lines 137-151 Link Here
137
            return new EQReplannedNode(n);
137
            return new EQReplannedNode(n);
138
        }
138
        }
139
        public Node findChild(final String name) {
139
        public Node findChild(final String name) {
140
            return (Node)Locks.event().read(new LockAction() {
140
            return Locks.event().read(new LockAction<Node>() {
141
                public Object run() {
141
                public Node run() {
142
                    return EQReplannedChildren.super.findChild(name);
142
                    return EQReplannedChildren.super.findChild(name);
143
                }
143
                }
144
            });
144
            });
145
        }
145
        }
146
        public Node[] getNodes(final boolean optimalResult) {
146
        public Node[] getNodes(final boolean optimalResult) {
147
            return (Node[])Locks.event().read(new LockAction() {
147
            return Locks.event().read(new LockAction<Node[]>() {
148
                public Object run() {
148
                public Node[] run() {
149
                    return EQReplannedChildren.super.getNodes(optimalResult);
149
                    return EQReplannedChildren.super.getNodes(optimalResult);
150
                }
150
                }
151
            });
151
            });
(-)threaddemo/views/looktree/LookTreeModel.java (-8 / +4 lines)
Lines 33-42 Link Here
33
    private final Object rootObject;
35
    private final Object rootObject;
34
    private final LookSelector sel;
36
    private final LookSelector sel;
35
    private LookTreeNode root;
37
    private LookTreeNode root;
36
    private final List listeners; // List<TreeModelListener>
38
    private final List<TreeModelListener> listeners;
37
    
39
    
38
    public LookTreeModel(Object root, LookSelector sel) {
40
    public LookTreeModel(Object root, LookSelector sel) {
39
        listeners = new ArrayList();
41
        listeners = new ArrayList<TreeModelListener>();
40
        this.rootObject = root;
42
        this.rootObject = root;
41
        this.sel = sel;
43
        this.sel = sel;
42
    }
44
    }
Lines 104-112 Link Here
104
        int[] childIndices = parent != null ? new int[] {getIndexOfChild(parent, source)} : null;
106
        int[] childIndices = parent != null ? new int[] {getIndexOfChild(parent, source)} : null;
105
        Object[] children = parent != null ? new Object[] {source} : null;
107
        Object[] children = parent != null ? new Object[] {source} : null;
106
        TreeModelEvent ev = new TreeModelEvent(this, path, childIndices, children);
108
        TreeModelEvent ev = new TreeModelEvent(this, path, childIndices, children);
107
        Iterator it = listeners.iterator();
109
        for (TreeModelListener l : listeners) {
108
        while (it.hasNext()) {
109
            TreeModelListener l = (TreeModelListener)it.next();
110
            l.treeNodesChanged(ev);
110
            l.treeNodesChanged(ev);
111
        }
111
        }
112
    }
112
    }
Lines 119-127 Link Here
119
        // XXX this is crude, could try to actually compute added/removed children...
119
        // XXX this is crude, could try to actually compute added/removed children...
120
        TreePath path = (source == root) ? null : findPath(source.getParent());
120
        TreePath path = (source == root) ? null : findPath(source.getParent());
121
        TreeModelEvent ev = new TreeModelEvent(this, path, null, null);
121
        TreeModelEvent ev = new TreeModelEvent(this, path, null, null);
122
        Iterator it = listeners.iterator();
122
        for (TreeModelListener l : listeners) {
123
        while (it.hasNext()) {
124
            TreeModelListener l = (TreeModelListener)it.next();
125
            logger.log(Level.FINER, "firing: {0} to {1}", new Object[] {ev, l});
123
            logger.log(Level.FINER, "firing: {0} to {1}", new Object[] {ev, l});
126
            l.treeStructureChanged(ev);
124
            l.treeStructureChanged(ev);
127
        }
125
        }
(-)threaddemo/views/looktree/LookTreeNode.java (-5 / +4 lines)
Lines 32-38 Link Here
32
    
34
    
33
    private final Object representedObject;
35
    private final Object representedObject;
34
    private final Look look;
36
    private final Look look;
35
    // private Map children = null; // Map<Object,LookTreeNode>
37
    // private Map<Object,LookTreeNode> children = null;
36
    private LookTreeNode[] children;
38
    private LookTreeNode[] children;
37
    private List childrenList;
39
    private List childrenList;
38
    protected int index = -1;
40
    protected int index = -1;
Lines 85-91 Link Here
85
    private LookTreeNode(Look l, Object o) {
87
    private LookTreeNode(Look l, Object o) {
86
        this.representedObject = o;
88
        this.representedObject = o;
87
        this.look = l;
89
        this.look = l;
88
        org.netbeans.modules.looks.Accessor.DEFAULT.addLookListener( l, representedObject, this );
90
        Accessor.DEFAULT.addLookListener( l, representedObject, this );
89
    }
91
    }
90
    
92
    
91
    private static Look findLook(Object o, LookSelector s) {
93
    private static Look findLook(Object o, LookSelector s) {
Lines 114-122 Link Here
114
    void forgetChildren() {
116
    void forgetChildren() {
115
        /*
117
        /*
116
        if (children != null) {
118
        if (children != null) {
117
            Iterator it = children.values().iterator();
119
            for (LookTreeNode child : children) {
118
            while (it.hasNext()) {
120
                child.forgetEverything();
119
                ((LookTreeNode)it.next()).forgetEverything();
120
            }
121
            }
121
            children = null;
122
            children = null;
122
        }
123
        }
(-)threaddemo/views/looktree/PopupHandler.java (-3 / +3 lines)
Lines 43-49 Link Here
43
    
43
    
44
    private final LookTreeView view;
44
    private final LookTreeView view;
45
    private final ActionMap actionMap;
45
    private final ActionMap actionMap;
46
    private Reference clicked; // Reference<LookTreeNode>
46
    private Reference<LookTreeNode> clicked;
47
    
47
    
48
    public PopupHandler(LookTreeView view) {
48
    public PopupHandler(LookTreeView view) {
49
        this.view = view;
49
        this.view = view;
Lines 58-64 Link Here
58
            TreePath path = view.getClosestPathForLocation(x, y);
58
            TreePath path = view.getClosestPathForLocation(x, y);
59
            if (path != null) {
59
            if (path != null) {
60
                LookTreeNode n = (LookTreeNode)path.getLastPathComponent();
60
                LookTreeNode n = (LookTreeNode)path.getLastPathComponent();
61
                clicked = new WeakReference(n);
61
                clicked = new WeakReference<LookTreeNode>(n);
62
                Action[] actions = n.getLook().getActions(n.getData(), n.getLookup() );
62
                Action[] actions = n.getLook().getActions(n.getData(), n.getLookup() );
63
                // XXX handle multiselects...
63
                // XXX handle multiselects...
64
                Node selection = makeNode( n );
64
                Node selection = makeNode( n );
Lines 87-93 Link Here
87
        
87
        
88
        public void actionPerformed(ActionEvent e) {
88
        public void actionPerformed(ActionEvent e) {
89
            // XXX should confirm deletion first
89
            // XXX should confirm deletion first
90
            LookTreeNode n = (LookTreeNode)clicked.get();
90
            LookTreeNode n = clicked.get();
91
            try {
91
            try {
92
                n.getLook().destroy(n.getData(), n.getLookup() );
92
                n.getLook().destroy(n.getData(), n.getLookup() );
93
            } catch (IOException ex) {
93
            } catch (IOException ex) {
94
   
94
   
95
   public final PropertyChangeEvent changeEvent;
95
   public final PropertyChangeEvent changeEvent;
96
   public final List<DocumentEvent> documentEvents;
96
   public final List<DocumentEvent> documentEvents;
97
   
97
   
98
   public DocumentParseSupportDelta(PropertyChangeEvent e) {
98
   public DocumentParseSupportDelta(PropertyChangeEvent e) {
99
       changeEvent = e;
99
       changeEvent = e;
100
       documentEvents = null;
100
       documentEvents = null;
101
   }
101
   }
102
   
102
   
103
   public DocumentParseSupportDelta(List<DocumentEvent> e) {
103
   public DocumentParseSupportDelta(List<DocumentEvent> e) {
104
       changeEvent = null;
104
       changeEvent = null;
105
       documentEvents = e;
105
       documentEvents = e;
106
   }
106
   }
107
   
107
   

Return to bug 56726