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 134297
Collapse All | Expand All

(-)a/.hgtags (+1 lines)
Lines 893-895 2fe642f5246f9e464deb29395b52fbedd3e0c120 Link Here
893
2fe642f5246f9e464deb29395b52fbedd3e0c120 release61_base
893
2fe642f5246f9e464deb29395b52fbedd3e0c120 release61_base
894
e08db7ef4b64aa1369693ab815ecfd614eb6363b merge_php_to_main
894
e08db7ef4b64aa1369693ab815ecfd614eb6363b merge_php_to_main
895
d7584415c0aa6226b2cd511f65942827a0da78d3 JavaScriptLibrarySupportTechnologyPreview
895
d7584415c0aa6226b2cd511f65942827a0da78d3 JavaScriptLibrarySupportTechnologyPreview
896
002c8f68e8dfb283e0e17eba9fe455a4a43e58ea asynchronous_lookup_events_base
(-)a/openide.loaders/apichanges.xml (+19 lines)
Lines 106-111 is the proper place. Link Here
106
<!-- ACTUAL CHANGES BEGIN HERE: -->
106
<!-- ACTUAL CHANGES BEGIN HERE: -->
107
107
108
  <changes>
108
  <changes>
109
     <change id="FolderLookup.dispatch">
110
        <api name="loaders"/>
111
        <summary>Changes in FolderLookup are delivered in dedicated thread</summary>
112
        <version major="7" minor="2"/>
113
        <date day="27" month="6" year="2008"/>
114
        <author login="jtulach"/>
115
        <compatibility binary="compatible" semantic="incompatible"/>
116
        <description>
117
        <p>
118
            Changes found in <code>FolderLookup</code> are delivered in own
119
            thread. This is a change to previous behaviour which used 
120
            <q>Folder recognizer</q> thread for the event delivery, which could
121
            caused deadlocks, if mallicious code decided to do something wild
122
            in the <code>resultChanged</code> method.
123
        </p>
124
        </description>
125
        <class package="org.openide.loaders" name="FolderLookup" />
126
        <issue number="134297"/>
127
    </change>
109
     <change id="factory">
128
     <change id="factory">
110
        <api name="loaders"/>
129
        <api name="loaders"/>
111
        <summary>DataObjects without DataLoaders</summary>
130
        <summary>DataObjects without DataLoaders</summary>
(-)a/openide.loaders/manifest.mf (-1 / +1 lines)
Lines 1-6 Manifest-Version: 1.0 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.loaders
2
OpenIDE-Module: org.openide.loaders
3
OpenIDE-Module-Specification-Version: 7.1
3
OpenIDE-Module-Specification-Version: 7.2
4
OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties
5
OpenIDE-Module-Recommends: org.netbeans.modules.templates.v1_0
5
OpenIDE-Module-Recommends: org.netbeans.modules.templates.v1_0
6
AutoUpdate-Essential-Module: true
6
AutoUpdate-Essential-Module: true
(-)a/openide.loaders/nbproject/project.xml (-1 / +1 lines)
Lines 133-139 made subject to such option by the copyr Link Here
133
                    <build-prerequisite/>
133
                    <build-prerequisite/>
134
                    <compile-dependency/>
134
                    <compile-dependency/>
135
                    <run-dependency>
135
                    <run-dependency>
136
                        <specification-version>7.8</specification-version>
136
                        <specification-version>7.16</specification-version>
137
                    </run-dependency>
137
                    </run-dependency>
138
                </dependency>
138
                </dependency>
139
                <dependency>
139
                <dependency>
(-)a/openide.loaders/src/org/openide/loaders/FolderLookup.java (-3 / +6 lines)
Lines 280-285 public class FolderLookup extends Folder Link Here
280
    
280
    
281
    /** <code>ProxyLookup</code> delegate so we can change the lookups on fly. */
281
    /** <code>ProxyLookup</code> delegate so we can change the lookups on fly. */
282
    static final class ProxyLkp extends ProxyLookup implements Serializable {
282
    static final class ProxyLkp extends ProxyLookup implements Serializable {
283
        static final RequestProcessor DISPATCH = new RequestProcessor("Lookup Dispatch Thread"); // NOI18N
283
        
284
        
284
        private static final long serialVersionUID = 1L;
285
        private static final long serialVersionUID = 1L;
285
286
Lines 294-300 public class FolderLookup extends Folder Link Here
294
        /** Constructs lookup which holds all items+lookups from underlying world.
295
        /** Constructs lookup which holds all items+lookups from underlying world.
295
         * @param folder <code>FolderLookup</code> to associate to */
296
         * @param folder <code>FolderLookup</code> to associate to */
296
        public ProxyLkp(FolderLookup folder) {
297
        public ProxyLkp(FolderLookup folder) {
297
            this(folder, new AbstractLookup.Content());
298
            this(folder, new AbstractLookup.Content(DISPATCH));
298
        }
299
        }
299
300
300
        /** Constructs lookup. */
301
        /** Constructs lookup. */
Lines 305-310 public class FolderLookup extends Folder Link Here
305
            this.content = content;
306
            this.content = content;
306
        }
307
        }
307
        
308
        
309
        @Override
308
        public String toString() {
310
        public String toString() {
309
            return "FolderLookup.lookup[\"" + fl.rootName + "\"]";
311
            return "FolderLookup.lookup[\"" + fl.rootName + "\"]";
310
        }
312
        }
Lines 335-341 public class FolderLookup extends Folder Link Here
335
            
337
            
336
            content = (AbstractLookup.Content)ois.readObject ();
338
            content = (AbstractLookup.Content)ois.readObject ();
337
            
339
            
338
            setLookups (arr);
340
            setLookups (DISPATCH, arr);
339
341
340
            readFromStream = true;
342
            readFromStream = true;
341
            org.openide.util.RequestProcessor.getDefault ().post (fl, 0, Thread.MIN_PRIORITY);
343
            org.openide.util.RequestProcessor.getDefault ().post (fl, 0, Thread.MIN_PRIORITY);
Lines 359-369 public class FolderLookup extends Folder Link Here
359
            lookups.set(0, pairs);
361
            lookups.set(0, pairs);
360
362
361
            Lookup[] arr = (Lookup[])lookups.toArray (new Lookup[lookups.size ()]);
363
            Lookup[] arr = (Lookup[])lookups.toArray (new Lookup[lookups.size ()]);
362
            setLookups (arr);
364
            setLookups (DISPATCH, arr);
363
            if (fl.err().isLoggable(Level.FINE)) fl.err ().fine("Changed lookups: " + lookups); // NOI18N
365
            if (fl.err().isLoggable(Level.FINE)) fl.err ().fine("Changed lookups: " + lookups); // NOI18N
364
        }
366
        }
365
        
367
        
366
        /** Waits before the processing of changes is finished. */
368
        /** Waits before the processing of changes is finished. */
369
        @Override
367
        protected void beforeLookup (Template template) {
370
        protected void beforeLookup (Template template) {
368
            if (readFromStream) {
371
            if (readFromStream) {
369
                // ok
372
                // ok
(-)a/openide.loaders/test/unit/src/org/openide/loaders/FolderLookupTest.java (-5 / +51 lines)
Lines 52-64 import org.openide.filesystems.FileUtil; Link Here
52
import org.openide.filesystems.FileUtil;
52
import org.openide.filesystems.FileUtil;
53
import org.openide.filesystems.Repository;
53
import org.openide.filesystems.Repository;
54
import org.openide.util.Lookup;
54
import org.openide.util.Lookup;
55
import org.openide.util.Lookup.Result;
55
import org.openide.util.LookupEvent;
56
import org.openide.util.LookupListener;
56
import org.openide.util.lookup.AbstractLookup;
57
import org.openide.util.lookup.AbstractLookup;
57
import org.openide.util.lookup.InstanceContent;
58
import org.openide.util.lookup.InstanceContent;
58
import org.openide.util.lookup.Lookups;
59
import org.openide.util.lookup.Lookups;
59
import org.openide.util.lookup.ProxyLookup;
60
import org.openide.util.lookup.ProxyLookup;
60
61
61
public class FolderLookupTest extends NbTestCase {
62
public class FolderLookupTest extends NbTestCase implements LookupListener {
63
    private Lookup.Result<?> res;
64
    private boolean bad;
65
    private String threadName = "";
62
    
66
    
63
    public FolderLookupTest(java.lang.String testName) {
67
    public FolderLookupTest(java.lang.String testName) {
64
        super(testName);
68
        super(testName);
Lines 68-78 public class FolderLookupTest extends Nb Link Here
68
        System.setProperty ("org.openide.util.Lookup", GLkp.class.getName());
72
        System.setProperty ("org.openide.util.Lookup", GLkp.class.getName());
69
    }
73
    }
70
    
74
    
75
    @Override
71
    protected void setUp() throws Exception {
76
    protected void setUp() throws Exception {
72
        super.setUp();
77
        super.setUp();
73
        clearWorkDir();
78
        clearWorkDir();
74
    }
79
    }
80
81
    @Override
82
    protected void tearDown() throws Exception {
83
        super.tearDown();
84
        if (res != null) {
85
            res.allItems();
86
            FolderLookup.ProxyLkp.DISPATCH.post(new Runnable() {
87
                public void run() {
88
                }
89
            }).waitFinished();
90
            if (threadName.contains("Folder") || threadName.length() == 0) {
91
                fail("Wrong thread name: " + threadName);
92
            }
93
        }
94
    }
75
    
95
    
96
    
97
    
98
    private void addListener(Lookup l) {
99
        bad = true;
100
        assertNull("No result yet", res);
101
        res = l.lookupResult(Object.class);
102
        res.addLookupListener(this);
103
        res.allItems();
104
    }
105
    
106
    public void resultChanged(LookupEvent ev) {
107
        if (threadName.length() == 0) {
108
            threadName = Thread.currentThread().getName();
109
        } else {
110
            threadName = threadName + ", " + Thread.currentThread().getName();
111
        }
112
    }
113
76
    /** Test of the lookup method. Creates a file under Services directory 
114
    /** Test of the lookup method. Creates a file under Services directory 
77
     * and tries to lookup it. The object should be immediatelly found.
115
     * and tries to lookup it. The object should be immediatelly found.
78
     *
116
     *
Lines 100-105 public class FolderLookupTest extends Nb Link Here
100
138
101
139
102
   private void checkTheLookup (Lookup lookup, DataFolder folder) throws Exception {
140
   private void checkTheLookup (Lookup lookup, DataFolder folder) throws Exception {
141
       addListener(lookup);
142
       
103
        Class toFind = java.util.Dictionary.class;
143
        Class toFind = java.util.Dictionary.class;
104
        Class toCreate = java.util.Hashtable.class;
144
        Class toCreate = java.util.Hashtable.class;
105
        
145
        
Lines 145-150 public class FolderLookupTest extends Nb Link Here
145
    }
185
    }
146
    
186
    
147
    private void checkTheLookupForSubfolders (Lookup lookup, DataFolder folder) throws Exception {
187
    private void checkTheLookupForSubfolders (Lookup lookup, DataFolder folder) throws Exception {
188
        addListener(lookup);
189
        
148
        Class toFind = java.awt.Component.class;
190
        Class toFind = java.awt.Component.class;
149
        Class toCreate = javax.swing.JButton.class;
191
        Class toCreate = javax.swing.JButton.class;
150
192
Lines 180-189 public class FolderLookupTest extends Nb Link Here
180
        
222
        
181
        DataFolder folder = DataFolder.findFolder (bb);
223
        DataFolder folder = DataFolder.findFolder (bb);
182
224
183
        InstanceDataObject obj = InstanceDataObject.create (folder, null, ALkp.class);
184
        
225
        
185
        Lookup lookup = new org.openide.loaders.FolderLookup (folder).getLookup ();
226
        Lookup lookup = new org.openide.loaders.FolderLookup (folder).getLookup ();
227
        addListener(lookup);
186
        
228
        
229
        InstanceDataObject obj = InstanceDataObject.create (folder, null, ALkp.class);
187
        if (lookup.lookup (Integer.class) == null) {
230
        if (lookup.lookup (Integer.class) == null) {
188
            fail ("Integer not found in delegating lookup");
231
            fail ("Integer not found in delegating lookup");
189
        }
232
        }
Lines 337-344 public class FolderLookupTest extends Nb Link Here
337
                    } catch (Exception ex) {
380
                    } catch (Exception ex) {
338
                        this.ex = ex;
381
                        this.ex = ex;
339
                    }
382
                    }
340
                    // and this will deadlock
383
                    Lookup l = lookup;
341
                    lookup.lookup (String.class);
384
                    if (l != null) {
385
                        // and this will deadlock
386
                        lookup.lookup (String.class);
387
                    }
342
                }
388
                }
343
            }
389
            }
344
390
(-)a/openide.util/apichanges.xml (+41 lines)
Lines 49-54 made subject to such option by the copyr Link Here
49
    <apidef name="actions">Actions API</apidef>
49
    <apidef name="actions">Actions API</apidef>
50
</apidefs>
50
</apidefs>
51
<changes>
51
<changes>
52
    <change id="Lookup.asynchronous">
53
        <api name="lookup"/>
54
        <summary>AbstractLookup and ProxyLookup fires changes asynchronously</summary>
55
        <version major="7" minor="16"/>
56
        <date day="27" month="6" year="2008"/>
57
        <author login="jtulach"/>
58
        <compatibility addition="yes" binary="compatible" semantic="compatible"/>
59
        <description>
60
            <p>
61
                All modification methods in <code>AbstractLookup</code> and <code>ProxyLookup</code>
62
                were extended to accept an 
63
                <a href="@JDK@/java/util/concurrent/Executor.html">Executor</a>.
64
                If not null, it is used to dispatch events to listeners sometime
65
                "later". Also the <code>AbstractLookup.Content</code> 
66
                and <code>InstanceContent</code> constructors
67
                have been extended to accept such <code>Executor</code>.
68
            </p>
69
        </description> 
70
        <class package="org.openide.util.lookup" name="AbstractLookup"/>
71
        <class package="org.openide.util.lookup" name="ProxyLookup"/>
72
        <class package="org.openide.util.lookup" name="InstanceContent"/>
73
        <issue number="134297"/>
74
    </change>
75
    <change id="RequestProcessor.Executor">
76
        <api name="util"/>
77
        <summary>RequestProcessor implements Executor interface</summary>
78
        <version major="7" minor="16"/>
79
        <date day="27" month="6" year="2008"/>
80
        <author login="jtulach"/>
81
        <compatibility addition="yes"/>
82
        <description>
83
            <p>
84
                In order to align <code>RequestProcessor</code> closer to standard 
85
                Java 5 concurency utilities, the class now implements
86
                <a href="@JDK@/java/util/concurrent/Executor.html">Executor</a>
87
                interfaces and its <code>execute(Runnable)</code> method.
88
            </p>
89
        </description> 
90
        <class package="org.openide.util" name="RequestProcessor"/>
91
        <issue number="134297"/>
92
    </change>
52
    <change id="Utilities.toolTips">
93
    <change id="Utilities.toolTips">
53
        <api name="util"/>
94
        <api name="util"/>
54
        <summary>Image methods were made deprecated in Utilities, replacement is 
95
        <summary>Image methods were made deprecated in Utilities, replacement is 
(-)a/openide.util/nbproject/project.properties (-1 / +1 lines)
Lines 41-47 javac.source=1.5 Link Here
41
javac.source=1.5
41
javac.source=1.5
42
module.jar.dir=lib
42
module.jar.dir=lib
43
43
44
spec.version.base=7.15.0
44
spec.version.base=7.16.0
45
45
46
# For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
46
# For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
47
47
(-)a/openide.util/src/org/openide/util/RequestProcessor.java (-1 / +12 lines)
Lines 48-53 import java.util.Stack; Link Here
48
import java.util.Stack;
48
import java.util.Stack;
49
import java.util.Timer;
49
import java.util.Timer;
50
import java.util.TimerTask;
50
import java.util.TimerTask;
51
import java.util.concurrent.Executor;
51
import java.util.logging.Level;
52
import java.util.logging.Level;
52
import java.util.logging.Logger;
53
import java.util.logging.Logger;
53
54
Lines 113-122 import java.util.logging.Logger; Link Here
113
 *     }
114
 *     }
114
 * }
115
 * }
115
 * </PRE>
116
 * </PRE>
117
 * Since version 7.16 it implements {@link Executor}
116
 * 
118
 * 
117
 * @author Petr Nejedly, Jaroslav Tulach
119
 * @author Petr Nejedly, Jaroslav Tulach
118
 */
120
 */
119
public final class RequestProcessor {
121
public final class RequestProcessor implements Executor{
120
    /** the static instance for users that do not want to have own processor */
122
    /** the static instance for users that do not want to have own processor */
121
    private static RequestProcessor DEFAULT = new RequestProcessor();
123
    private static RequestProcessor DEFAULT = new RequestProcessor();
122
124
Lines 240-245 public final class RequestProcessor { Link Here
240
        return UNLIMITED;
242
        return UNLIMITED;
241
    }
243
    }
242
244
245
    /** Implements contract of {@link Executor}. 
246
     * Simply delegates to {@link #post(java.lang.Runnable)}.
247
     * @param command the runnable to execute
248
     * @since 7.16
249
     */
250
    public void execute(Runnable command) {
251
        post(command);
252
    }
253
    
243
    /** This methods asks the request processor to start given
254
    /** This methods asks the request processor to start given
244
     * runnable immediately. The default priority is {@link Thread#MIN_PRIORITY}.
255
     * runnable immediately. The default priority is {@link Thread#MIN_PRIORITY}.
245
     *
256
     *
(-)a/openide.util/src/org/openide/util/lookup/AbstractLookup.java (-35 / +106 lines)
Lines 63-68 import java.util.Set; Link Here
63
import java.util.Set;
63
import java.util.Set;
64
import java.util.TreeSet;
64
import java.util.TreeSet;
65
65
66
import java.util.concurrent.Executor;
66
import org.openide.util.Utilities;
67
import org.openide.util.Utilities;
67
68
68
69
Lines 200-209 public class AbstractLookup extends Look Link Here
200
     * @param pair class/instance pair
201
     * @param pair class/instance pair
201
     */
202
     */
202
    protected final void addPair(Pair<?> pair) {
203
    protected final void addPair(Pair<?> pair) {
203
        addPairImpl(pair);
204
        addPairImpl(pair, null);
204
    }
205
    }
205
206
206
    private final <Transaction> void addPairImpl(Pair<?> pair) {
207
    /** The method to add instance to the lookup with.
208
     * @param pair class/instance pair
209
     * @param notifyIn the executor that will handle the notification of events
210
     * @since 7.16
211
     */
212
    protected final void addPair(Pair<?> pair, Executor notifyIn) {
213
        addPairImpl(pair, notifyIn);
214
    }
215
216
    private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
207
        HashSet<R> toNotify = new HashSet<R>();
217
        HashSet<R> toNotify = new HashSet<R>();
208
218
209
        AbstractLookup.Storage<Transaction> t = enterStorage();
219
        AbstractLookup.Storage<Transaction> t = enterStorage();
Lines 233-249 public class AbstractLookup extends Look Link Here
233
            exitStorage();
243
            exitStorage();
234
        }
244
        }
235
245
236
        notifyListeners(toNotify);
246
        notifyIn(notifyIn, toNotify);
237
    }
247
    }
238
248
239
    /** Remove instance.
249
    /** Remove instance.
240
     * @param pair class/instance pair
250
     * @param pair class/instance pair
241
     */
251
     */
242
    protected final void removePair(Pair<?> pair) {
252
    protected final void removePair(Pair<?> pair) {
243
        removePairImpl(pair);
253
        removePairImpl(pair, null);
254
    }
255
    /** Remove instance.
256
     * @param pair class/instance pair
257
     * @param notifyIn the executor that will handle the notification of events
258
     * @since 7.16
259
     */
260
    protected final void removePair(Pair<?> pair, Executor notifyIn) {
261
        removePairImpl(pair, notifyIn);
244
    }
262
    }
245
263
246
    private <Transaction> void removePairImpl(Pair<?> pair) {
264
    private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
247
        HashSet<R> toNotify = new HashSet<R>();
265
        HashSet<R> toNotify = new HashSet<R>();
248
266
249
        AbstractLookup.Storage<Transaction> t = enterStorage();
267
        AbstractLookup.Storage<Transaction> t = enterStorage();
Lines 257-270 public class AbstractLookup extends Look Link Here
257
            exitStorage();
275
            exitStorage();
258
        }
276
        }
259
277
260
        notifyListeners(toNotify);
278
        notifyIn(notifyIn, toNotify);
261
    }
279
    }
262
280
263
    /** Changes all pairs in the lookup to new values.
281
    /** Changes all pairs in the lookup to new values.
264
     * @param collection the collection of (Pair) objects
282
     * @param collection the collection of (Pair) objects
265
     */
283
     */
266
    protected final void setPairs(Collection<? extends Pair> collection) {
284
    protected final void setPairs(Collection<? extends Pair> collection) {
267
        notifyCollectedListeners(setPairsAndCollectListeners(collection));
285
        setPairs(collection, null);
286
    }
287
288
    /** Changes all pairs in the lookup to new values, notifies listeners
289
     * using provided executor.
290
     * 
291
     * @param collection the collection of (Pair) objects
292
     * @param notifyIn the executor that will handle the notification of events
293
     * @since 7.16
294
     */
295
    protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
296
        HashSet<R> listeners = setPairsAndCollectListeners(collection);
297
        notifyIn(notifyIn, listeners);
298
    }
299
    
300
    private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
301
        if (notifyIn == null) {
302
            notifyListeners(listeners);
303
            return;
304
        }
305
        
306
        class Notify implements Runnable {
307
            public void run() {
308
                notifyListeners(listeners);
309
            }
310
        }
311
        notifyIn.execute(new Notify());
268
    }
312
    }
269
    
313
    
270
    /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
314
    /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
Lines 349-361 public class AbstractLookup extends Look Link Here
349
        }
393
        }
350
394
351
        return toNotify;
395
        return toNotify;
352
    }
353
354
    /** Notifies all collected listeners. Needed by MetaInfServicesLookup,
355
     * maybe it will be an API later.
356
     */
357
    final void notifyCollectedListeners(Set<R> listeners) {
358
        notifyListeners(listeners);
359
    }
396
    }
360
397
361
    private final void writeObject(ObjectOutputStream oos)
398
    private final void writeObject(ObjectOutputStream oos)
Lines 461-467 public class AbstractLookup extends Look Link Here
461
    /** Notifies listeners.
498
    /** Notifies listeners.
462
     * @param allAffectedResults set of R
499
     * @param allAffectedResults set of R
463
     */
500
     */
464
    private static void notifyListeners(Set<R> allAffectedResults) {
501
    static void notifyListeners(Set<R> allAffectedResults) {
465
        if (allAffectedResults.isEmpty()) {
502
        if (allAffectedResults.isEmpty()) {
466
            return;
503
            return;
467
        }
504
        }
Lines 1078-1085 public class AbstractLookup extends Look Link Here
1078
        // one of them is always null (except attach stage)
1115
        // one of them is always null (except attach stage)
1079
1116
1080
        /** abstract lookup we are connected to */
1117
        /** abstract lookup we are connected to */
1081
        private AbstractLookup al = null;
1118
        private AbstractLookup al;
1082
        private transient ArrayList<Pair> earlyPairs;
1119
        private transient Object notifyIn;
1120
        
1121
        /** Default constructor.
1122
         */
1123
        public Content() {
1124
            this(null);
1125
        }
1126
        
1127
        /** Creates a content associated with an executor to handle dispatch
1128
         * of changes.
1129
         * @param notifyIn the executor to notify changes in
1130
         * @since  7.16
1131
         */
1132
        public Content(Executor notifyIn) {
1133
            this.notifyIn = notifyIn;
1134
        }
1135
        
1136
        /** for testing purposes */
1137
        final void attachExecutor(Executor notifyIn) {
1138
            this.notifyIn = notifyIn;
1139
        }
1083
1140
1084
        /** A lookup attaches to this object.
1141
        /** A lookup attaches to this object.
1085
         */
1142
         */
Lines 1087-1095 public class AbstractLookup extends Look Link Here
1087
            if (this.al == null) {
1144
            if (this.al == null) {
1088
                this.al = al;
1145
                this.al = al;
1089
1146
1090
                if (earlyPairs != null) {
1147
                ArrayList<Pair> ep = getEarlyPairs();
1091
                    ArrayList<Pair> ep = earlyPairs;
1148
                if (ep != null) {
1092
                    earlyPairs = null;
1149
                    notifyIn = null;
1093
                    setPairs(ep);
1150
                    setPairs(ep);
1094
                }
1151
                }
1095
            } else {
1152
            } else {
Lines 1104-1118 public class AbstractLookup extends Look Link Here
1104
         */
1161
         */
1105
        public final void addPair(Pair<?> pair) {
1162
        public final void addPair(Pair<?> pair) {
1106
            AbstractLookup a = al;
1163
            AbstractLookup a = al;
1164
            Executor e = getExecutor();
1107
1165
1108
            if (a != null) {
1166
            if (a != null || e != null) {
1109
                a.addPair(pair);
1167
                a.addPair(pair, e);
1110
            } else {
1168
            } else {
1111
                if (earlyPairs == null) {
1169
                if (notifyIn == null) {
1112
                    earlyPairs = new ArrayList<Pair>(3);
1170
                    notifyIn = new ArrayList<Pair>(3);
1113
                }
1171
                }
1114
1172
1115
                earlyPairs.add(pair);
1173
                getEarlyPairs().add(pair);
1116
            }
1174
            }
1117
        }
1175
        }
1118
1176
Lines 1121-1135 public class AbstractLookup extends Look Link Here
1121
         */
1179
         */
1122
        public final void removePair(Pair<?> pair) {
1180
        public final void removePair(Pair<?> pair) {
1123
            AbstractLookup a = al;
1181
            AbstractLookup a = al;
1182
            Executor e = getExecutor();
1124
1183
1125
            if (a != null) {
1184
            if (a != null || e != null) {
1126
                a.removePair(pair);
1185
                a.removePair(pair, e);
1127
            } else {
1186
            } else {
1128
                if (earlyPairs == null) {
1187
                if (notifyIn == null) {
1129
                    earlyPairs = new ArrayList<Pair>(3);
1188
                    notifyIn = new ArrayList<Pair>(3);
1130
                }
1189
                }
1131
1190
1132
                earlyPairs.remove(pair);
1191
                getEarlyPairs().remove(pair);
1133
            }
1192
            }
1134
        }
1193
        }
1135
1194
Lines 1138-1149 public class AbstractLookup extends Look Link Here
1138
         */
1197
         */
1139
        public final void setPairs(Collection<? extends Pair> c) {
1198
        public final void setPairs(Collection<? extends Pair> c) {
1140
            AbstractLookup a = al;
1199
            AbstractLookup a = al;
1200
            Executor e = getExecutor();
1201
            
1202
            if (a != null || e != null) {
1203
                a.setPairs(c, e);
1204
            } else {
1205
                notifyIn = new ArrayList<Pair>(c);
1206
            }
1207
        }
1141
1208
1142
            if (a != null) {
1209
        @SuppressWarnings("unchecked")
1143
                a.setPairs(c);
1210
        private ArrayList<Pair> getEarlyPairs() {
1144
            } else {
1211
            Object o = notifyIn;
1145
                earlyPairs = new ArrayList<Pair>(c);
1212
            return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
1146
            }
1213
        }
1214
        
1215
        private Executor getExecutor() {
1216
            Object o = notifyIn;
1217
            return o instanceof Executor ? (Executor)o : null;
1147
        }
1218
        }
1148
    }
1219
    }
1149
     // end of Content
1220
     // end of Content
(-)a/openide.util/src/org/openide/util/lookup/InstanceContent.java (-1 / +13 lines)
Lines 40-51 Link Here
40
 */
40
 */
41
package org.openide.util.lookup;
41
package org.openide.util.lookup;
42
42
43
import org.openide.util.lookup.AbstractLookup;
44
import org.openide.util.lookup.AbstractLookup.Pair;
43
import org.openide.util.lookup.AbstractLookup.Pair;
45
44
46
import java.lang.ref.WeakReference;
45
import java.lang.ref.WeakReference;
47
46
48
import java.util.*;
47
import java.util.*;
48
import java.util.concurrent.Executor;
49
49
50
50
51
/** A special content implementation that can be passed to AbstractLookup
51
/** A special content implementation that can be passed to AbstractLookup
Lines 71-76 public final class InstanceContent exten Link Here
71
    public InstanceContent() {
71
    public InstanceContent() {
72
    }
72
    }
73
73
74
    /** Creates a content associated with an executor to handle dispatch
75
     * of changes.
76
     * @param notifyIn the executor to notify changes in
77
     * @since  7.16
78
     */
79
    public InstanceContent(Executor notifyIn) {
80
        super(notifyIn);
81
    }
74
    /** The method to add instance to the lookup with.
82
    /** The method to add instance to the lookup with.
75
     * @param inst instance
83
     * @param inst instance
76
     */
84
     */
Lines 190-195 public final class InstanceContent exten Link Here
190
            return obj;
198
            return obj;
191
        }
199
        }
192
200
201
        @Override
193
        public boolean equals(Object o) {
202
        public boolean equals(Object o) {
194
            if (o instanceof SimpleItem) {
203
            if (o instanceof SimpleItem) {
195
                return obj.equals(((SimpleItem) o).obj);
204
                return obj.equals(((SimpleItem) o).obj);
Lines 198-203 public final class InstanceContent exten Link Here
198
            }
207
            }
199
        }
208
        }
200
209
210
        @Override
201
        public int hashCode() {
211
        public int hashCode() {
202
            return obj.hashCode();
212
            return obj.hashCode();
203
        }
213
        }
Lines 292-297 public final class InstanceContent exten Link Here
292
            return converted;
302
            return converted;
293
        }
303
        }
294
304
305
        @Override
295
        public boolean equals(Object o) {
306
        public boolean equals(Object o) {
296
            if (o instanceof ConvertingItem) {
307
            if (o instanceof ConvertingItem) {
297
                return obj.equals(((ConvertingItem) o).obj);
308
                return obj.equals(((ConvertingItem) o).obj);
Lines 300-305 public final class InstanceContent exten Link Here
300
            }
311
            }
301
        }
312
        }
302
313
314
        @Override
303
        public int hashCode() {
315
        public int hashCode() {
304
            return obj.hashCode();
316
            return obj.hashCode();
305
        }
317
        }
(-)a/openide.util/src/org/openide/util/lookup/MetaInfServicesLookup.java (-1 / +1 lines)
Lines 128-134 final class MetaInfServicesLookup extend Link Here
128
            }
128
            }
129
        }
129
        }
130
130
131
        notifyCollectedListeners(listeners);
131
        notifyListeners(listeners);
132
    }
132
    }
133
133
134
    /** Finds all pairs and adds them to the collection.
134
    /** Finds all pairs and adds them to the collection.
(-)a/openide.util/src/org/openide/util/lookup/ProxyLookup.java (-7 / +28 lines)
Lines 55-60 import java.util.Map; Link Here
55
import java.util.Map;
55
import java.util.Map;
56
import java.util.Map.Entry;
56
import java.util.Map.Entry;
57
import java.util.Set;
57
import java.util.Set;
58
import java.util.concurrent.Executor;
58
import javax.swing.event.EventListenerList;
59
import javax.swing.event.EventListenerList;
59
import org.openide.util.Lookup;
60
import org.openide.util.Lookup;
60
import org.openide.util.LookupEvent;
61
import org.openide.util.LookupEvent;
Lines 115-120 public class ProxyLookup extends Lookup Link Here
115
     * @since 1.19 protected
116
     * @since 1.19 protected
116
     */
117
     */
117
    protected final void setLookups(Lookup... lookups) {
118
    protected final void setLookups(Lookup... lookups) {
119
        setLookups(null, lookups);
120
    }
121
    
122
    /**
123
     * Changes the delegates immediatelly, notifies the listeners in provided
124
     * executor, potentially later.
125
     *
126
     * @param lookups the new lookups to delegate to
127
     * @param notifyIn executor to deliver the notification to listeners or null
128
     * @since 7.16
129
     */
130
    protected final void setLookups(Executor notifyIn, Lookup... lookups) {
118
        Collection<Reference<R>> arr;
131
        Collection<Reference<R>> arr;
119
        Set<Lookup> newL;
132
        Set<Lookup> newL;
120
        Set<Lookup> current;
133
        Set<Lookup> current;
Lines 143-149 public class ProxyLookup extends Lookup Link Here
143
156
144
157
145
        // this cannot be done from the synchronized block
158
        // this cannot be done from the synchronized block
146
        ArrayList<Object> evAndListeners = new ArrayList<Object>();
159
        final ArrayList<Object> evAndListeners = new ArrayList<Object>();
147
        for (Reference<R> ref : arr) {
160
        for (Reference<R> ref : arr) {
148
            R<?> r = ref.get();
161
            R<?> r = ref.get();
149
            if (r != null) {
162
            if (r != null) {
Lines 151-163 public class ProxyLookup extends Lookup Link Here
151
            }
164
            }
152
        }
165
        }
153
        
166
        
154
        {
167
        class Notify implements Runnable {
155
            Iterator it = evAndListeners.iterator();
168
            public void run() {
156
            while (it.hasNext()) {
169
                Iterator it = evAndListeners.iterator();
157
                LookupEvent ev = (LookupEvent)it.next();
170
                while (it.hasNext()) {
158
                LookupListener l = (LookupListener)it.next();
171
                    LookupEvent ev = (LookupEvent)it.next();
159
                l.resultChanged(ev);
172
                    LookupListener l = (LookupListener)it.next();
173
                    l.resultChanged(ev);
174
                }
160
            }
175
            }
176
        }
177
        Notify n = new Notify();
178
        if (notifyIn == null) {
179
            n.run();
180
        } else {
181
            notifyIn.execute(n);
161
        }
182
        }
162
    }
183
    }
163
184
(-)a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java (-1 / +6 lines)
Lines 47-53 import org.openide.util.*; Link Here
47
47
48
import java.lang.ref.WeakReference;
48
import java.lang.ref.WeakReference;
49
import java.util.*;
49
import java.util.*;
50
import junit.framework.*;
51
import org.netbeans.junit.*;
50
import org.netbeans.junit.*;
52
import java.io.Serializable;
51
import java.io.Serializable;
53
import java.lang.ref.Reference;
52
import java.lang.ref.Reference;
Lines 1688-1693 public class AbstractLookupBaseHid exten Link Here
1688
    protected static class LL implements LookupListener {
1687
    protected static class LL implements LookupListener {
1689
        private int count = 0;
1688
        private int count = 0;
1690
        public Object source;
1689
        public Object source;
1690
        public Thread changesIn;
1691
        
1691
        
1692
        public LL () {
1692
        public LL () {
1693
            this (null);
1693
            this (null);
Lines 1698-1703 public class AbstractLookupBaseHid exten Link Here
1698
        }
1698
        }
1699
        
1699
        
1700
        public void resultChanged(LookupEvent ev) {
1700
        public void resultChanged(LookupEvent ev) {
1701
            if (changesIn != null) {
1702
                assertEquals("Changes in the same thread", changesIn, Thread.currentThread());
1703
            } else {
1704
                changesIn = Thread.currentThread();
1705
            }
1701
            ++count;
1706
            ++count;
1702
            if (source != null) {
1707
            if (source != null) {
1703
                assertSame ("Source is the same", source, ev.getSource ());
1708
                assertSame ("Source is the same", source, ev.getSource ());
(-)002c8f68e8df (+97 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * Contributor(s):
25
 *
26
 * The Original Software is NetBeans. The Initial Developer of the Original
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
 * Microsystems, Inc. All Rights Reserved.
29
 *
30
 * If you wish your version of this file to be governed by only the CDDL
31
 * or only the GPL Version 2, indicate your decision by adding
32
 * "[Contributor] elects to include this software in this distribution
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
34
 * single choice of license, a recipient has the option to distribute
35
 * your version of this file under either the CDDL, the GPL Version 2 or
36
 * to extend the choice of license to its licensees as provided above.
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
38
 * Version 2 license, then the option applies only if the new code is
39
 * made subject to such option by the copyright holder.
40
 */
41
42
package org.openide.util.lookup;
43
44
import org.openide.util.*;
45
46
import java.util.concurrent.Executor;
47
48
public class AbstractLookupExecutorTest extends AbstractLookupBaseHid 
49
implements AbstractLookupBaseHid.Impl, Executor, LookupListener {
50
    Lookup.Result<?> res;
51
    
52
    
53
    public AbstractLookupExecutorTest(java.lang.String testName) {
54
        super(testName, null);
55
    }
56
57
    //
58
    // Impl of AbstractLookupBaseHid.Impl
59
    //
60
61
    /** Creates the initial abstract lookup.
62
     */
63
    public Lookup createInstancesLookup (InstanceContent ic) {
64
        ic.attachExecutor(this);
65
        Lookup l = new AbstractLookup (ic, new InheritanceTree ());
66
        return l;
67
    }
68
    
69
    /** Creates an lookup for given lookup. This class just returns 
70
     * the object passed in, but subclasses can be different.
71
     * @param lookup in lookup
72
     * @return a lookup to use
73
     */
74
    public Lookup createLookup (Lookup lookup) {
75
        res = lookup.lookupResult(Object.class);
76
        res.addLookupListener(this);
77
        return lookup;
78
    }
79
80
    public void clearCaches () {
81
    }    
82
83
    ThreadLocal<Object> ME = new ThreadLocal<Object>();
84
    public void execute(Runnable command) {
85
        assertEquals("Not yet set", null, ME.get());
86
        ME.set(this);
87
        try {
88
            command.run();
89
        } finally {
90
            ME.set(null);
91
        }
92
    }
93
94
    public void resultChanged(LookupEvent ev) {
95
        assertEquals("Changes delivered only from execute method", this, ME.get());
96
    }
97
}
(-)a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java (+60 lines)
Lines 47-52 import java.lang.ref.Reference; Link Here
47
import java.lang.ref.Reference;
47
import java.lang.ref.Reference;
48
import java.lang.ref.WeakReference;
48
import java.lang.ref.WeakReference;
49
import java.util.*;
49
import java.util.*;
50
import java.util.concurrent.Executor;
51
import java.util.concurrent.Executor;
50
import junit.framework.*;
52
import junit.framework.*;
51
import org.netbeans.junit.*;
53
import org.netbeans.junit.*;
52
import org.openide.util.Lookup.Result;
54
import org.openide.util.Lookup.Result;
Lines 125-130 implements AbstractLookupBaseHid.Impl { Link Here
125
        
127
        
126
        lookup.setLookups (new Lookup[] { del });
128
        lookup.setLookups (new Lookup[] { del });
127
        
129
        
130
        if (ll.getCount () != 0) {
131
           fail ("Calling setLookups (thesamearray) fired a change");
132
        }
133
    }
134
    
135
    public void testNoListenersProxyListener () {
136
        ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
137
        class E implements Executor {
138
            Runnable r;
139
            public void execute(Runnable command) {
140
                assertNull("NO previous", r);
141
                r = command;
142
            }
143
            public void perform() {
144
                assertNotNull("We shall have a runnable", r);
145
                r.run();
146
                r = null;
147
            }
148
        }
149
        E executor = new E();
150
                
151
152
        final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
153
        final Object[] IGNORE = {
154
            ProxyLookup.ImmutableInternalData.EMPTY,
155
            ProxyLookup.ImmutableInternalData.EMPTY_ARR,
156
            Utilities.activeReferenceQueue(),
157
            Collections.emptyMap(),
158
            Collections.emptyList(),
159
            Collections.emptySet()
160
        };
161
        
162
        assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
163
        
164
        Lookup.Result<Object> res = lookup.lookup (template);
165
166
        assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
167
        
168
        LL ll = new LL ();
169
        res.addLookupListener (ll);
170
        Collection allRes = res.allInstances ();
171
        
172
        lookup.setLookups (executor, new Lookup[0]);
173
        if (ll.getCount () != 0) {
174
           fail ("Calling setLookups (emptyarray) fired a change");
175
        }
176
        
177
        InstanceContent t = new InstanceContent();
178
        Lookup del = new AbstractLookup (t);
179
        t.add("Ahoj");
180
        lookup.setLookups (executor, new Lookup[] { del });
181
        assertEquals("No change yet", 0, ll.getCount());
182
        executor.perform();
183
        if (ll.getCount () != 1) {
184
            fail ("Changing lookups did not generate an event");
185
        }
186
        
187
        lookup.setLookups (executor, new Lookup[] { del });
128
        if (ll.getCount () != 0) {
188
        if (ll.getCount () != 0) {
129
           fail ("Calling setLookups (thesamearray) fired a change");
189
           fail ("Calling setLookups (thesamearray) fired a change");
130
        }
190
        }

Return to bug 134297