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

(-)core/src/org/netbeans/core/modules/ModuleManager.java (+36 lines)
Lines 65-70 Link Here
65
    public ModuleManager(ModuleInstaller installer, Events ev) {
65
    public ModuleManager(ModuleInstaller installer, Events ev) {
66
        this.installer = installer;
66
        this.installer = installer;
67
        this.ev = ev;
67
        this.ev = ev;
68
        updateContextClassLoaders(classLoader, true);
68
    }
69
    }
69
    
70
    
70
    /** Access for ManifestSection. */
71
    /** Access for ManifestSection. */
Lines 239-246 Link Here
239
        }
240
        }
240
        synchronized (classLoaderLock) {
241
        synchronized (classLoaderLock) {
241
            classLoader = nue;
242
            classLoader = nue;
243
            updateContextClassLoaders(classLoader, false);
242
        }
244
        }
243
        firer.change(new ChangeFirer.Change(this, PROP_CLASS_LOADER, null, null));
245
        firer.change(new ChangeFirer.Change(this, PROP_CLASS_LOADER, null, null));
246
    }
247
    private static void updateContextClassLoaders(ClassLoader l, boolean force) {
248
        // See #20663.
249
        ThreadGroup g = Thread.currentThread().getThreadGroup();
250
        while (g.getParent() != null) g = g.getParent();
251
        // Now g is the master thread group, hopefully.
252
        // See #4097747 for an explanation of the convoluted logic.
253
        while (true) {
254
            int s = g.activeCount() + 1;
255
            Thread[] ts = new Thread[s];
256
            int x = g.enumerate(ts, true);
257
            if (x < s) {
258
                // We got all of the threads, good.
259
                for (int i = 0; i < x; i++) {
260
                    // The first time when we make the manager, set all of the
261
                    // threads to have this context classloader. Let's hope no
262
                    // threads needing a special context loader have been started
263
                    // yet! On subsequent occasions, when the classloader
264
                    // changes, we update all threads for which setContextClassLoader
265
                    // has not been called with some other special classloader.
266
                    if (force || (ts[i].getContextClassLoader() instanceof SystemClassLoader)) {
267
                        //Util.err.log("Setting ctxt CL on " + ts[i].getName() + " to " + l);
268
                        ts[i].setContextClassLoader(l);
269
                    } else {
270
                        Util.err.log("Not touching context class loader " + ts[i].getContextClassLoader() + " on thread " + ts[i].getName());
271
                    }
272
                }
273
                Util.err.log("Set context class loader on " + x + " threads");
274
                break;
275
            } else {
276
                Util.err.log("Race condition getting all threads, restarting...");
277
                continue;
278
            }
279
        }
244
    }
280
    }
245
    
281
    
246
    /** A classloader giving access to all the module classloaders at once. */
282
    /** A classloader giving access to all the module classloaders at once. */
(-)core/test/unit/src/org/netbeans/core/modules/ModuleManagerTest.java (+111 lines)
Lines 21-26 Link Here
21
import java.lang.reflect.*;
21
import java.lang.reflect.*;
22
import org.openide.util.*;
22
import org.openide.util.*;
23
import org.openide.modules.*;
23
import org.openide.modules.*;
24
import java.net.*;
24
25
25
/** Test the module manager as well as the Module class.
26
/** Test the module manager as well as the Module class.
26
 * This means creating modules from JAR as well as from "classpath"
27
 * This means creating modules from JAR as well as from "classpath"
Lines 424-429 Link Here
424
            Object o = c.newInstance();
425
            Object o = c.newInstance();
425
            assertEquals(25, f.getInt(o));
426
            assertEquals(25, f.getInt(o));
426
        } finally {
427
        } finally {
428
            mgr.mutexPrivileged().exitWriteAccess();
429
        }
430
    }
431
    
432
    /** Test #20663: the context classloader is set on all threads
433
     * according to the system classloader.
434
     */
435
    public void testContextClassLoader() throws Exception {
436
        FakeModuleInstaller installer = new FakeModuleInstaller();
437
        FakeEvents ev = new FakeEvents();
438
        final ModuleManager mgr = new ModuleManager(installer, ev);
439
        mgr.mutexPrivileged().enterWriteAccess();
440
        // Make sure created threads do not die.
441
        final Object sleepForever = "sleepForever";
442
        try {
443
            final Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false);
444
            Module m2 = mgr.create(new File(jars, "depends-on-simple-module.jar"), null, false, false);
445
            ClassLoader l1 = mgr.getClassLoader();
446
            assertEquals(l1, Thread.currentThread().getContextClassLoader());
447
            mgr.enable(m1);
448
            ClassLoader l2 = mgr.getClassLoader();
449
            assertTrue(l1 == l2);
450
            assertEquals(l2, Thread.currentThread().getContextClassLoader());
451
            mgr.enable(m2);
452
            ClassLoader l3 = mgr.getClassLoader();
453
            assertTrue(l1 == l3);
454
            assertEquals(l3, Thread.currentThread().getContextClassLoader());
455
            mgr.disable(m2);
456
            ClassLoader l4 = mgr.getClassLoader();
457
            assertTrue(l1 != l4);
458
            assertEquals(l4, Thread.currentThread().getContextClassLoader());
459
            final Thread[] t23 = new Thread[2];
460
            final ClassLoader[] lx = new ClassLoader[] {new URLClassLoader(new URL[0])};
461
            // Make sure t1 runs to completion, though.
462
            final Object finishT1 = "finishT1";
463
            Thread t1 = new Thread("custom thread #1") {
464
                public void run() {
465
                    synchronized (finishT1) {
466
                        t23[0] = new Thread("custom thread #2") {
467
                            public void run() {
468
                                synchronized (sleepForever) {
469
                                    try {
470
                                        sleepForever.wait();
471
                                    } catch (InterruptedException ie) {
472
                                        throw new Error(ie.toString());
473
                                    }
474
                                }
475
                            }
476
                        };
477
                        t23[0].start();
478
                        Thread.currentThread().setContextClassLoader(lx[0]);
479
                        mgr.disable(m1);
480
                        t23[1] = new Thread("custom thread #3") {
481
                            public void run() {
482
                                synchronized (sleepForever) {
483
                                    try {
484
                                        sleepForever.wait();
485
                                    } catch (InterruptedException ie) {
486
                                        throw new Error(ie.toString());
487
                                    }
488
                                }
489
                            }
490
                        };
491
                        t23[1].start();
492
                        finishT1.notify();
493
                    }
494
                    synchronized (sleepForever) {
495
                        try {
496
                            sleepForever.wait();
497
                        } catch (InterruptedException ie) {
498
                            throw new Error(ie.toString());
499
                        }
500
                    }
501
                }
502
            };
503
            t1.start();
504
            synchronized (finishT1) {
505
                if (t23[1] == null) {
506
                    finishT1.wait();
507
                    assertNotNull(t23[1]);
508
                }
509
            }
510
            assertTrue(!m1.isEnabled());
511
            ClassLoader l5 = mgr.getClassLoader();
512
            assertTrue(l1 != l5);
513
            assertTrue(l4 != l5);
514
            assertEquals(l5, Thread.currentThread().getContextClassLoader());
515
            // It had a special classloader when we changed modules.
516
            assertTrue(t1.isAlive());
517
            assertEquals(lx[0], t1.getContextClassLoader());
518
            // It was created before the special classloader.
519
            assertTrue(t23[0].isAlive());
520
            assertEquals(l5, t23[0].getContextClassLoader());
521
            // It was created after and should have inherited the special classloader.
522
            assertTrue(t23[1].isAlive());
523
            assertEquals(lx[0], t23[1].getContextClassLoader());
524
            mgr.enable(m1);
525
            mgr.disable(m1);
526
            ClassLoader l6 = mgr.getClassLoader();
527
            assertTrue(l1 != l6);
528
            assertTrue(l4 != l6);
529
            assertTrue(l5 != l6);
530
            assertEquals(l6, Thread.currentThread().getContextClassLoader());
531
            assertEquals(lx[0], t1.getContextClassLoader());
532
            assertEquals(l6, t23[0].getContextClassLoader());
533
            assertEquals(lx[0], t23[1].getContextClassLoader());
534
        } finally {
535
            synchronized (sleepForever) {
536
                sleepForever.notifyAll();
537
            }
427
            mgr.mutexPrivileged().exitWriteAccess();
538
            mgr.mutexPrivileged().exitWriteAccess();
428
        }
539
        }
429
    }
540
    }
(-)openide/openide-spec-vers.properties (-1 / +1 lines)
Lines 5-8 Link Here
5
# Must always be numeric (numbers separated by '.', e.g. 1.11.3).
5
# Must always be numeric (numbers separated by '.', e.g. 1.11.3).
6
# See http://openide.netbeans.org/versioning-policy.html for more.
6
# See http://openide.netbeans.org/versioning-policy.html for more.
7
7
8
org.openide.specification.version=1.43.3
8
org.openide.specification.version=1.43.3.1

Return to bug 20663