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

(-)core/bootstrap/src/org/netbeans/ModuleManager.java (-77 / +34 lines)
Lines 71-77 Link Here
71
71
72
    // for any module, set of known failed dependencies or problems,
72
    // for any module, set of known failed dependencies or problems,
73
    // or null if this has not been computed yet
73
    // or null if this has not been computed yet
74
    private final Map<Module,Set<Union2<Dependency,InvalidException>>> moduleProblems = new HashMap<Module,Set<Union2<Dependency,InvalidException>>>(100);
74
    private final Map<Module,Set<Union2<Dependency,InvalidException>>> moduleProblemsWithoutNeeds = new HashMap<Module,Set<Union2<Dependency,InvalidException>>>(100);
75
    private final Map<Module,Set<Union2<Dependency,InvalidException>>> moduleProblemsWithNeeds = new HashMap<Module,Set<Union2<Dependency,InvalidException>>>(100);
75
76
76
    // modules providing a given requires token; set may never be empty
77
    // modules providing a given requires token; set may never be empty
77
    private final Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>(25);
78
    private final Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>(25);
Lines 696-702 Link Here
696
        // of "soft" problems (interdependencies between modules).
697
        // of "soft" problems (interdependencies between modules).
697
        // Also clear any "hard" problems associated with this module, as they
698
        // Also clear any "hard" problems associated with this module, as they
698
        // may now have been fixed.
699
        // may now have been fixed.
699
        moduleProblems.remove(m);
700
        moduleProblemsWithoutNeeds.remove(m);
701
        moduleProblemsWithNeeds.remove(m);
700
        firer.change(new ChangeFirer.Change(m, Module.PROP_PROBLEMS, null, null));
702
        firer.change(new ChangeFirer.Change(m, Module.PROP_PROBLEMS, null, null));
701
        clearProblemCache();
703
        clearProblemCache();
702
        firer.fire();
704
        firer.fire();
Lines 833-839 Link Here
833
                // Remember that there was a problem with this guy.
835
                // Remember that there was a problem with this guy.
834
                Module bad = ie.getModule();
836
                Module bad = ie.getModule();
835
                if (bad == null) throw new IllegalStateException("Problem with no associated module: " + ie); // NOI18N
837
                if (bad == null) throw new IllegalStateException("Problem with no associated module: " + ie); // NOI18N
836
                Set<Union2<Dependency,InvalidException>> probs = moduleProblems.get(bad);
838
                Set<Union2<Dependency,InvalidException>> probs = moduleProblemsWithNeeds.get(bad);
837
                if (probs == null) throw new IllegalStateException("Were trying to install a module that had never been checked: " + bad); // NOI18N
839
                if (probs == null) throw new IllegalStateException("Were trying to install a module that had never been checked: " + bad); // NOI18N
838
                if (! probs.isEmpty()) throw new IllegalStateException("Were trying to install a module that was known to be bad: " + bad); // NOI18N
840
                if (! probs.isEmpty()) throw new IllegalStateException("Were trying to install a module that was known to be bad: " + bad); // NOI18N
839
                // Record for posterity.
841
                // Record for posterity.
Lines 1104-1112 Link Here
1104
                        // and continue with the others, try to add them too...
1106
                        // and continue with the others, try to add them too...
1105
                    }
1107
                    }
1106
                }
1108
                }
1107
                // XXX sometimes fails, but not reproducible in a unit test.
1108
                // Logic is that missingDependencies(m) should contain dep in this case.
1109
                // Logic is that missingDependencies(m) should contain dep in this case.
1109
                assert foundOne : "Should have found a nonproblematic provider of " + dep + " among " + providers + " with willEnable=" + willEnable + " mightEnable=" + mightEnable;
1110
                assert foundOne || dep.getType() == Dependency.TYPE_RECOMMENDS : "Should have found a nonproblematic provider of " + dep + " among " + providers + " with willEnable=" + willEnable + " mightEnable=" + mightEnable;
1110
            }
1111
            }
1111
            // else some other kind of dependency that does not concern us
1112
            // else some other kind of dependency that does not concern us
1112
        }
1113
        }
Lines 1322-1398 Link Here
1322
    // Access from Module.getProblems, q.v.
1323
    // Access from Module.getProblems, q.v.
1323
    // The probed module must not be currently enabled or fixed.
1324
    // The probed module must not be currently enabled or fixed.
1324
    Set<Union2<Dependency,InvalidException>> missingDependencies(Module probed) {
1325
    Set<Union2<Dependency,InvalidException>> missingDependencies(Module probed) {
1326
        return missingDependencies(probed, true);
1327
    }
1328
    Set<Union2<Dependency,InvalidException>> missingDependencies(Module probed, boolean withNeeds) {
1325
        // We need to synchronize here because though this method may be called
1329
        // We need to synchronize here because though this method may be called
1326
        // only within a read mutex, it can write to moduleProblems. Other places
1330
        // only within a read mutex, it can write to moduleProblems. Other places
1327
        // where moduleProblems are used are write-mutex only and so do not have
1331
        // where moduleProblems are used are write-mutex only and so do not have
1328
        // to worry about contention.
1332
        // to worry about contention.
1329
        synchronized (moduleProblems) {
1333
        synchronized (moduleProblemsWithNeeds) {
1330
            Set<Union2<Dependency,InvalidException>> result;
1334
            Map<Module,Set<Union2<Dependency,InvalidException>>> mP = (withNeeds ? moduleProblemsWithNeeds : moduleProblemsWithoutNeeds);
1331
            ArrayList<NeedsCheck> check = new ArrayList<NeedsCheck>();
1335
            Set<Union2<Dependency,InvalidException>> probs = mP.get(probed);
1332
            result = _missingDependencies(probed, check);
1333
            LOOP: while (result.isEmpty()) {
1334
                for (NeedsCheck needs : check) {
1335
                    String token = needs.dep.getName();
1336
                    Set<Module> providers = providersOf.get(token);
1337
                    if (providers == null) {
1338
                        if (needs.dep.getType() == Dependency.TYPE_NEEDS) {
1339
                            // Nobody provides it. This dep failed.
1340
                            result.add(Union2.<Dependency,InvalidException>createFirst(needs.dep));
1341
                        } else {
1342
                            // TYPE_RECOMMENDS is ok if not present
1343
                            assert needs.dep.getType() == Dependency.TYPE_RECOMMENDS;
1344
                        }
1345
                    } else {
1346
                        // We have some possible providers. Check that at least one is good.
1347
                        boolean foundOne = false;
1348
                        Set<Module> possibleModules = new HashSet<Module>();
1349
                        for (Module other : providers) {
1350
                            if (other.isEnabled()) {
1351
                                foundOne = true;
1352
                                break;
1353
                            }
1354
                        }
1355
                        if (!foundOne) {
1356
                            for (Module m : providers) {
1357
                                ArrayList<NeedsCheck> arr = new ArrayList<NeedsCheck>();
1358
                                if (!_missingDependencies(m, arr).isEmpty()) {
1359
                                    continue;
1360
                                }
1361
                                
1362
                                if (!arr.isEmpty()) {
1363
                                    check.addAll(arr);
1364
                                    // restart the check
1365
                                    continue LOOP;
1366
                                }
1367
                            }
1368
                            
1369
                        }
1370
                    }
1371
                }
1372
                break LOOP;
1373
            }
1374
            return result;
1375
        }
1376
    }
1377
    
1378
    private static class NeedsCheck {
1379
        public final Module module;
1380
        public final Dependency dep;
1381
        public NeedsCheck(Module m, Dependency d) {
1382
            this.module = m;
1383
            this.dep = d;
1384
        }
1385
        public String toString() {
1386
            return "(" + module + "," + dep + ")"; // NOI18N
1387
        }
1388
    }
1389
    
1390
    private Set<Union2<Dependency,InvalidException>> _missingDependencies(Module probed, Collection<NeedsCheck> nonOrderingCheck) {
1391
            Set<Union2<Dependency,InvalidException>> probs = moduleProblems.get(probed);
1392
            if (probs == null) {
1336
            if (probs == null) {
1393
                probs = new HashSet<Union2<Dependency,InvalidException>>(8);
1337
                probs = new HashSet<Union2<Dependency,InvalidException>>(8);
1338
                if (withNeeds) {
1339
                    probs.addAll(missingDependencies(probed, false));
1340
                }
1394
                probs.add(PROBING_IN_PROCESS);
1341
                probs.add(PROBING_IN_PROCESS);
1395
                moduleProblems.put(probed, probs);
1342
                mP.put(probed, probs);
1396
                for (Dependency dep : probed.getDependenciesArray()) {
1343
                for (Dependency dep : probed.getDependenciesArray()) {
1397
                    if (dep.getType() == Dependency.TYPE_PACKAGE) {
1344
                    if (dep.getType() == Dependency.TYPE_PACKAGE) {
1398
                        // Can't check it in advance. Assume it is OK; if not
1345
                        // Can't check it in advance. Assume it is OK; if not
Lines 1457-1463 Link Here
1457
                        if (! other.isEnabled()) {
1404
                        if (! other.isEnabled()) {
1458
                            // Need to make sure the other one is not missing anything either.
1405
                            // Need to make sure the other one is not missing anything either.
1459
                            // Nor that it depends (directly on indirectly) on this one.
1406
                            // Nor that it depends (directly on indirectly) on this one.
1460
                            if (! _missingDependencies(other, nonOrderingCheck).isEmpty()) {
1407
                            if ((!withNeeds && !missingDependencies(other, false).isEmpty()) ||
1408
                                    (withNeeds && !isAlmostEmpty(missingDependencies(other, true)))) {
1461
                                // This is a little subtle. Either the other module had real
1409
                                // This is a little subtle. Either the other module had real
1462
                                // problems, in which case our dependency on it is not legit.
1410
                                // problems, in which case our dependency on it is not legit.
1463
                                // Or, the other actually depends cyclically on this one. In
1411
                                // Or, the other actually depends cyclically on this one. In
Lines 1476-1482 Link Here
1476
                            // on it if we need it.
1424
                            // on it if we need it.
1477
                        }
1425
                        }
1478
                        // Already-installed modules are of course fine.
1426
                        // Already-installed modules are of course fine.
1479
                    } else if (dep.getType() == Dependency.TYPE_REQUIRES) {
1427
                    } else if (dep.getType() == Dependency.TYPE_REQUIRES || (withNeeds && dep.getType() == Dependency.TYPE_NEEDS)) {
1480
                        // Works much like a regular module dependency. However it only
1428
                        // Works much like a regular module dependency. However it only
1481
                        // fails if there are no satisfying modules with no problems.
1429
                        // fails if there are no satisfying modules with no problems.
1482
                        String token = dep.getName();
1430
                        String token = dep.getName();
Lines 1488-1497 Link Here
1488
                            // We have some possible providers. Check that at least one is good.
1436
                            // We have some possible providers. Check that at least one is good.
1489
                            boolean foundOne = false;
1437
                            boolean foundOne = false;
1490
                            for (Module other : providers) {
1438
                            for (Module other : providers) {
1439
                                if (foundOne) {
1440
                                    break;
1441
                                }
1491
                                if (other.isEnabled()) {
1442
                                if (other.isEnabled()) {
1492
                                    foundOne = true;
1443
                                    foundOne = true;
1493
                                } else {
1444
                                } else {
1494
                                    if (_missingDependencies(other, nonOrderingCheck).isEmpty()) {
1445
                                    if ((!withNeeds && missingDependencies(other, false).isEmpty()) ||
1446
                                            (withNeeds && isAlmostEmpty(missingDependencies(other, true)))) {
1495
                                        // See comment above for regular module deps
1447
                                        // See comment above for regular module deps
1496
                                        // re. use of PROBING_IN_PROCESS.
1448
                                        // re. use of PROBING_IN_PROCESS.
1497
                                        foundOne = true;
1449
                                        foundOne = true;
Lines 1503-1512 Link Here
1503
                                probs.add(Union2.<Dependency,InvalidException>createFirst(dep));
1455
                                probs.add(Union2.<Dependency,InvalidException>createFirst(dep));
1504
                            }
1456
                            }
1505
                        }
1457
                        }
1506
                    } else if (dep.getType() == Dependency.TYPE_NEEDS || dep.getType() == Dependency.TYPE_RECOMMENDS) {
1458
                    } else if (dep.getType() == Dependency.TYPE_JAVA) {
1507
                        nonOrderingCheck.add(new NeedsCheck(probed, dep));
1508
                    } else {
1509
                        assert dep.getType() == Dependency.TYPE_JAVA;
1510
                        // Java dependency. Fixed for whole VM session, safe to check once and keep.
1459
                        // Java dependency. Fixed for whole VM session, safe to check once and keep.
1511
                        if (! Util.checkJavaDependency(dep)) {
1460
                        if (! Util.checkJavaDependency(dep)) {
1512
                            // Bad.
1461
                            // Bad.
Lines 1517-1522 Link Here
1517
                probs.remove(PROBING_IN_PROCESS);
1466
                probs.remove(PROBING_IN_PROCESS);
1518
            }
1467
            }
1519
            return probs;
1468
            return probs;
1469
        }
1470
    }
1471
    private static boolean isAlmostEmpty(Set<Union2<Dependency,InvalidException>> probs) {
1472
        return probs.isEmpty() || probs.equals(Collections.singleton(PROBING_IN_PROCESS));
1520
    }
1473
    }
1521
1474
1522
    /** Forget about any possible "soft" problems there might have been.
1475
    /** Forget about any possible "soft" problems there might have been.
Lines 1530-1536 Link Here
1530
     * return a different result).
1483
     * return a different result).
1531
     */
1484
     */
1532
    private void clearProblemCache() {
1485
    private void clearProblemCache() {
1533
        Iterator<Map.Entry<Module,Set<Union2<Dependency,InvalidException>>>> it = moduleProblems.entrySet().iterator();
1486
        clearProblemCache(moduleProblemsWithoutNeeds);
1487
        clearProblemCache(moduleProblemsWithNeeds);
1488
    }
1489
    private void clearProblemCache(Map<Module,Set<Union2<Dependency,InvalidException>>> mP) {
1490
        Iterator<Map.Entry<Module,Set<Union2<Dependency,InvalidException>>>> it = mP.entrySet().iterator();
1534
        while (it.hasNext()) {
1491
        while (it.hasNext()) {
1535
            Map.Entry<Module,Set<Union2<Dependency,InvalidException>>> entry = it.next();
1492
            Map.Entry<Module,Set<Union2<Dependency,InvalidException>>> entry = it.next();
1536
            Module m = entry.getKey();
1493
            Module m = entry.getKey();
(-)core/startup/test/unit/src/org/netbeans/core/startup/ModuleManagerTest.java (-2 / +7 lines)
Lines 1013-1022 Link Here
1013
        mgr.mutexPrivileged().enterWriteAccess();
1013
        mgr.mutexPrivileged().enterWriteAccess();
1014
        Module m1 = createModule(mgr, "OpenIDE-Module: m1\nOpenIDE-Module-Needs: tok\n");
1014
        Module m1 = createModule(mgr, "OpenIDE-Module: m1\nOpenIDE-Module-Needs: tok\n");
1015
        Module m2 = createModule(mgr, "OpenIDE-Module: m2\nOpenIDE-Module-Module-Dependencies: m1\n");
1015
        Module m2 = createModule(mgr, "OpenIDE-Module: m2\nOpenIDE-Module-Module-Dependencies: m1\n");
1016
        //assertEquals(1, m2.getProblems().size());
1017
        assertEquals(Collections.emptyList(), mgr.simulateEnable(Collections.singleton(m2)));
1016
        assertEquals(Collections.emptyList(), mgr.simulateEnable(Collections.singleton(m2)));
1018
        Module m3 = createModule(mgr, "OpenIDE-Module: m3\nOpenIDE-Module-Provides: tok\n");
1017
        Module m3 = createModule(mgr, "OpenIDE-Module: m3\nOpenIDE-Module-Provides: tok\n");
1019
        assertEquals(new HashSet<Module>(Arrays.asList(m1, m2, m3)), new HashSet<Module>(mgr.simulateEnable(Collections.singleton(m2))));
1018
        assertEquals(new HashSet<Module>(Arrays.asList(m1, m2, m3)), new HashSet<Module>(mgr.simulateEnable(Collections.singleton(m2))));
1019
        mgr = new ModuleManager(installer, ev);
1020
        mgr.mutexPrivileged().enterWriteAccess();
1021
        m1 = createModule(mgr, "OpenIDE-Module: m1\nOpenIDE-Module-Requires: tok\n");
1022
        m2 = createModule(mgr, "OpenIDE-Module: m2\nOpenIDE-Module-Module-Dependencies: m1\nOpenIDE-Module-Provides: tok\n");
1023
        assertEquals(Collections.emptyList(), mgr.simulateEnable(Collections.singleton(m2)));
1020
    }
1024
    }
1021
    
1025
    
1022
    public void testSimpleProvNeeds() throws Exception {
1026
    public void testSimpleProvNeeds() throws Exception {
Lines 1339-1344 Link Here
1339
    }
1343
    }
1340
1344
1341
    private void doRecommendsWithAProviderWithoutAProvider(boolean recommends) throws Exception {
1345
    private void doRecommendsWithAProviderWithoutAProvider(boolean recommends) throws Exception {
1346
        // ========= XXX recommends parameter is unused! ===========
1342
        FakeModuleInstaller installer = new FakeModuleInstaller();
1347
        FakeModuleInstaller installer = new FakeModuleInstaller();
1343
        FakeEvents ev = new FakeEvents();
1348
        FakeEvents ev = new FakeEvents();
1344
        ModuleManager mgr = new ModuleManager(installer, ev);
1349
        ModuleManager mgr = new ModuleManager(installer, ev);
Lines 1366-1372 Link Here
1366
            assertEquals(null, deps.get(m2));
1371
            assertEquals(null, deps.get(m2));
1367
1372
1368
            List<Module> toEnable = mgr.simulateEnable(new HashSet<Module>(m2List));
1373
            List<Module> toEnable = mgr.simulateEnable(new HashSet<Module>(m2List));
1369
            assertEquals("cannot enable while provider of bla is missing", Collections.emptyList(), toEnable);
1374
            assertEquals("cannot enable while provider of bla is missing", Collections.singletonList(m2), toEnable);
1370
1375
1371
1376
1372
//            try {
1377
//            try {

Return to bug 80702