Source Code Cross Referenced for ModuleManager.java in  » IDE-Netbeans » library » org » netbeans » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » library » org.netbeans 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans;
0043:
0044:        import java.beans.PropertyChangeListener;
0045:        import java.beans.PropertyChangeSupport;
0046:        import java.io.File;
0047:        import java.io.IOException;
0048:        import java.security.AllPermission;
0049:        import java.security.CodeSource;
0050:        import java.security.PermissionCollection;
0051:        import java.security.Permissions;
0052:        import java.util.ArrayList;
0053:        import java.util.Collection;
0054:        import java.util.Collections;
0055:        import java.util.HashMap;
0056:        import java.util.HashSet;
0057:        import java.util.Iterator;
0058:        import java.util.LinkedList;
0059:        import java.util.List;
0060:        import java.util.Map;
0061:        import java.util.Set;
0062:        import java.util.StringTokenizer;
0063:        import java.util.jar.Manifest;
0064:        import java.util.logging.Level;
0065:        import org.openide.modules.Dependency;
0066:        import org.openide.modules.ModuleInfo;
0067:        import org.openide.modules.SpecificationVersion;
0068:        import org.openide.util.Lookup;
0069:        import org.openide.util.Mutex;
0070:        import org.openide.util.TopologicalSortException;
0071:        import org.openide.util.Union2;
0072:        import org.openide.util.Utilities;
0073:
0074:        /** Manages a collection of modules.
0075:         * Must use {@link #mutex} to access its important methods.
0076:         * @author Jesse Glick
0077:         */
0078:        public final class ModuleManager {
0079:
0080:            public static final String PROP_MODULES = "modules"; // NOI18N
0081:            public static final String PROP_ENABLED_MODULES = "enabledModules"; // NOI18N
0082:            public static final String PROP_CLASS_LOADER = "classLoader"; // NOI18N
0083:
0084:            // JST-PENDING: Document in arch. used in org.netbeans.core.startup tests
0085:            // For unit testing only:
0086:            static boolean PRINT_TOPOLOGICAL_EXCEPTION_STACK_TRACES = !Boolean
0087:                    .getBoolean("suppress.topological.exception"); // NOI18N
0088:
0089:            // the modules being managed (not all need be installed)
0090:            private final Set<Module> modules = new HashSet<Module>(100);
0091:            // the same, indexed by code name base
0092:            private final Map<String, Module> modulesByName = new HashMap<String, Module>(
0093:                    100);
0094:
0095:            // for any module, set of known failed dependencies or problems,
0096:            // or null if this has not been computed yet
0097:            private final Map<Module, Set<Union2<Dependency, InvalidException>>> moduleProblemsWithoutNeeds = new HashMap<Module, Set<Union2<Dependency, InvalidException>>>(
0098:                    100);
0099:            private final Map<Module, Set<Union2<Dependency, InvalidException>>> moduleProblemsWithNeeds = new HashMap<Module, Set<Union2<Dependency, InvalidException>>>(
0100:                    100);
0101:
0102:            // modules providing a given requires token; set may never be empty
0103:            private final Map<String, Set<Module>> providersOf = new HashMap<String, Set<Module>>(
0104:                    25);
0105:
0106:            private final ModuleInstaller installer;
0107:            private ModuleFactory moduleFactory;
0108:
0109:            private SystemClassLoader classLoader;
0110:            private List<File> classLoaderPatches;
0111:            private final Object classLoaderLock = new String(
0112:                    "ModuleManager.classLoaderLock"); // NOI18N
0113:
0114:            private final Events ev;
0115:
0116:            /** Create a manager, initially with no managed modules.
0117:             * The handler for installing modules is given.
0118:             * Also the sink for event messages must be given.
0119:             */
0120:            public ModuleManager(ModuleInstaller installer, Events ev) {
0121:                this .installer = installer;
0122:                this .ev = ev;
0123:                String patches = System
0124:                        .getProperty("netbeans.systemclassloader.patches");
0125:                if (patches != null) {
0126:                    // Probably temporary helper for XTest. By setting this system property
0127:                    // to a classpath (list of directories and JARs separated by the normal
0128:                    // path separator) you may append to the system class loader.
0129:                    System.err.println("System class loader patches: "
0130:                            + patches); // NOI18N
0131:                    classLoaderPatches = new ArrayList<File>();
0132:                    StringTokenizer tok = new StringTokenizer(patches,
0133:                            File.pathSeparator);
0134:                    while (tok.hasMoreTokens()) {
0135:                        classLoaderPatches.add(new File(tok.nextToken()));
0136:                    }
0137:                } else {
0138:                    // Normal case.
0139:                    classLoaderPatches = Collections.emptyList();
0140:                }
0141:                classLoader = new SystemClassLoader(classLoaderPatches,
0142:                        new ClassLoader[] { installer.getClass()
0143:                                .getClassLoader() }, Collections
0144:                                .<Module> emptySet());
0145:                updateContextClassLoaders(classLoader, true);
0146:
0147:                moduleFactory = Lookup.getDefault().lookup(ModuleFactory.class);
0148:                if (moduleFactory == null) {
0149:                    moduleFactory = new ModuleFactory();
0150:                } else {
0151:                    // Custom module factory might want to replace
0152:                    // the system classloader by its own.
0153:                    // If it does not want to replace it the following
0154:                    // call should not change anything since the system classloader
0155:                    // should still be set to ClassLoader.getSystemClassLoader() so
0156:                    // the following call will set it to the same value.
0157:                    classLoader.setSystemClassLoader(moduleFactory
0158:                            .getClasspathDelegateClassLoader(this , ClassLoader
0159:                                    .getSystemClassLoader()));
0160:                }
0161:            }
0162:
0163:            /** Access for ManifestSection.
0164:             * @since JST-PENDING needed by ManifestSection
0165:             */
0166:            public final Events getEvents() {
0167:                return ev;
0168:            }
0169:
0170:            private final Mutex.Privileged MUTEX_PRIVILEGED = new Mutex.Privileged();
0171:            private final Mutex MUTEX = new Mutex(MUTEX_PRIVILEGED);
0172:
0173:            /** Get a locking mutex for this module installer.
0174:             * All calls other than adding or removing property change
0175:             * listeners, or getting the module lookup, called on this
0176:             * class must be done within the scope of this mutex
0177:             * (with read or write access as appropriate). Methods
0178:             * on ModuleInfo need not be called within it; methods
0179:             * specifically on Module do need to be called within it
0180:             * (read access is sufficient). Note that property changes
0181:             * are fired with read access already held for convenience.
0182:             * Please avoid entering the mutex from "sensitive" threads
0183:             * such as the event thread, the folder recognizer/lookup
0184:             * thread, etc., or with other locks held (such as the Children
0185:             * mutex), especially when entering the mutex as a writer:
0186:             * actions such as enabling modules in particular can call
0187:             * arbitrary foreign module code which may do a number of
0188:             * strange things (including consuming a significant amount of
0189:             * time and waiting for other tasks such as lookup or data
0190:             * object recognition). Use the request processor or the IDE's
0191:             * main startup thread or the execution engine to be safe.
0192:             */
0193:            public final Mutex mutex() {
0194:                return MUTEX;
0195:            }
0196:
0197:            /** Classes in this package can, if careful, use the privileged form.
0198:             * @since JST-PENDING this had to be made public as the package is now split in two
0199:             */
0200:            public final Mutex.Privileged mutexPrivileged() {
0201:                return MUTEX_PRIVILEGED;
0202:            }
0203:
0204:            // [PENDING] with improved API for Mutex, could throw
0205:            // IllegalStateException if any thread attempts to call
0206:            // a controlled method without holding the proper mutex lock
0207:
0208:            /** Manages changes accumulating in this manager and fires them when ready.
0209:             */
0210:            private ChangeFirer firer = new ChangeFirer(this );
0211:            /** True while firer is firing changes.
0212:             */
0213:            private boolean readOnly = false;
0214:
0215:            /**
0216:             * Release storage for all module manifests.
0217:             * @see Module#releaseManifest
0218:             */
0219:            public void releaseModuleManifests() {
0220:                for (Module m : modules) {
0221:                    m.releaseManifest();
0222:                }
0223:            }
0224:
0225:            /** Sets the r/o flag. Access from ChangeFirer.
0226:             * @param ro if true, cannot make any changes until set to false again
0227:             */
0228:            void readOnly(boolean ro) {
0229:                readOnly = ro;
0230:            }
0231:
0232:            /** Assert that the current thread state permits writing.
0233:             * Currently does not check that there is a write mutex!
0234:             * (Pending #13352.)
0235:             * But does check that I am not firing changes.
0236:             * @throws IllegalThreadStateException if currently firing changes
0237:             */
0238:            void assertWritable() throws IllegalThreadStateException {
0239:                if (readOnly) {
0240:                    throw new IllegalThreadStateException(
0241:                            "You are attempting to make changes to "
0242:                                    + this 
0243:                                    + " in a property change callback. This is illegal. You may only make module system changes while holding a write mutex and not inside a change callback. See #16328."); // NOI18N
0244:                }
0245:            }
0246:
0247:            private PropertyChangeSupport changeSupport;
0248:
0249:            /** Add a change listener.
0250:             * Only the declared properties will be fired, and they are
0251:             * not guaranteed to be fired synchronously with the change
0252:             * (currently they are not in fact, for safety). The change
0253:             * events are not guaranteed to provide an old and new value,
0254:             * so you will need to use the proper
0255:             * getter methods. When the changes are fired, you are inside
0256:             * the mutex with read access.
0257:             */
0258:            public final void addPropertyChangeListener(PropertyChangeListener l) {
0259:                synchronized (this ) {
0260:                    if (changeSupport == null)
0261:                        changeSupport = new PropertyChangeSupport(this );
0262:                }
0263:                changeSupport.addPropertyChangeListener(l);
0264:            }
0265:
0266:            /** Remove a change listener. */
0267:            public final void removePropertyChangeListener(
0268:                    PropertyChangeListener l) {
0269:                if (changeSupport != null)
0270:                    changeSupport.removePropertyChangeListener(l);
0271:            }
0272:
0273:            // Access from ChangeFirer:
0274:            final void firePropertyChange(String prop, Object old, Object nue) {
0275:                if (Util.err.isLoggable(Level.FINE)) {
0276:                    Util.err.fine("ModuleManager.propertyChange: " + prop
0277:                            + ": " + old + " -> " + nue);
0278:                }
0279:                if (changeSupport != null)
0280:                    changeSupport.firePropertyChange(prop, old, nue);
0281:            }
0282:
0283:            /** For access from Module. */
0284:            final void fireReloadable(Module m) {
0285:                firer.change(new ChangeFirer.Change(m, Module.PROP_RELOADABLE,
0286:                        null, null));
0287:                firer.fire();
0288:            }
0289:
0290:            private final Util.ModuleLookup lookup = new Util.ModuleLookup();
0291:
0292:            /** Retrieve set of modules in Lookup form.
0293:             * The core top manager should install this into the set of
0294:             * available lookups. Will fire lookup events when the
0295:             * set of modules changes (not for enabling/disabling/etc.).
0296:             * No other subsystem should make any attempt to provide an instance of
0297:             * ModuleInfo via lookup, so an optimization could be to jump
0298:             * straight to this lookup when ModuleInfo/Module is requested.
0299:             */
0300:            public Lookup getModuleLookup() {
0301:                return lookup;
0302:            }
0303:
0304:            // Access from ChangeFirer:
0305:            final void fireModulesCreatedDeleted(Set created, Set deleted) {
0306:                Util.err.fine("lookup created: " + created + " deleted: "
0307:                        + deleted);
0308:                lookup.changed();
0309:            }
0310:
0311:            /** Get a set of {@link Module}s being managed.
0312:             * No two contained modules may at any time share the same code name base.
0313:             * @see #PROP_MODULES
0314:             */
0315:            public Set<Module> getModules() {
0316:                return new HashSet<Module>(modules);
0317:            }
0318:
0319:            /** Get a set of modules managed which are currently enabled.
0320:             * Convenience method only.
0321:             * @see #PROP_ENABLED_MODULES
0322:             */
0323:            public final Set<Module> getEnabledModules() {
0324:                Set<Module> s = new HashSet<Module>(modules);
0325:                Iterator<Module> it = s.iterator();
0326:                while (it.hasNext()) {
0327:                    Module m = it.next();
0328:                    if (!m.isEnabled()) {
0329:                        it.remove();
0330:                    }
0331:                }
0332:                return s;
0333:            }
0334:
0335:            /** Convenience method to find a module by name.
0336:             * Returns null if there is no such managed module.
0337:             */
0338:            public final Module get(String codeNameBase) {
0339:                return modulesByName.get(codeNameBase);
0340:            }
0341:
0342:            /**
0343:             * Get a set of modules depended upon or depending on this module.
0344:             * <p>Note that provide-require/need dependencies are listed alongside direct
0345:             * dependencies; a module with a required token is considered to depend on
0346:             * <em>all</em> modules providing that token (though in fact only one is needed
0347:             * to enable it).
0348:             * <p>Illegal cyclic dependencies are omitted.
0349:             * @param m a module to start from; may be enabled or not, but must be owned by this manager
0350:             * @param reverse if true, find modules depending on this module; if false, find
0351:             *                modules this module depends upon
0352:             * @param transitive if true, these dependencies are considered transitively as well
0353:             * @return a set (possibly empty) of modules managed by this manager, never including m
0354:             * @since org.netbeans.core/1 > 1.17
0355:             */
0356:            public Set<Module> getModuleInterdependencies(Module m,
0357:                    boolean reverse, boolean transitive) {
0358:                return Util.moduleInterdependencies(m, reverse, transitive,
0359:                        modules, modulesByName, providersOf);
0360:            }
0361:
0362:            /** Get a classloader capable of loading from any
0363:             * of the enabled modules or their declared extensions.
0364:             * Should be used as the result of TopManager.systemClassLoader.
0365:             * Thread-safe.
0366:             * @see #PROP_CLASS_LOADER
0367:             */
0368:            public ClassLoader getClassLoader() {
0369:                // #16265: should not require mutex to get at. Many pieces of the IDE
0370:                // require the correct result immediately.
0371:                synchronized (classLoaderLock) {
0372:                    return classLoader;
0373:                }
0374:            }
0375:
0376:            /** Mark the current class loader as invalid and make a new one. */
0377:            private void invalidateClassLoader() {
0378:                synchronized (classLoaderLock) {
0379:                    classLoader.destroy(); // probably has no effect, but just in case...
0380:                }
0381:                // Set, not List, because if we have >1 bootstrap module (using Plain),
0382:                // it is likely that some of these classloaders will overlap.
0383:                Set<ClassLoader> foundParents = new HashSet<ClassLoader>(
0384:                        modules.size() * 4 / 3 + 2);
0385:                List<ClassLoader> parents = new ArrayList<ClassLoader>(modules
0386:                        .size() + 1);
0387:                ClassLoader base = ModuleManager.class.getClassLoader();
0388:                foundParents.add(base);
0389:                parents.add(base);
0390:                for (Module m : modules) {
0391:                    if (!m.isEnabled()) {
0392:                        continue;
0393:                    }
0394:                    if (foundParents.add(m.getClassLoader())) {
0395:                        parents.add(m.getClassLoader());
0396:                    }
0397:                }
0398:                if (moduleFactory.removeBaseClassLoader()) {
0399:                    parents.remove(base);
0400:                }
0401:                ClassLoader[] parentCLs = parents
0402:                        .toArray(new ClassLoader[parents.size()]);
0403:                SystemClassLoader nue;
0404:                try {
0405:                    nue = new SystemClassLoader(classLoaderPatches, parentCLs,
0406:                            modules);
0407:                } catch (IllegalArgumentException iae) {
0408:                    Util.err.log(Level.WARNING, null, iae);
0409:                    nue = new SystemClassLoader(classLoaderPatches,
0410:                            new ClassLoader[] { ModuleManager.class
0411:                                    .getClassLoader() }, Collections
0412:                                    .<Module> emptySet());
0413:                }
0414:                synchronized (classLoaderLock) {
0415:                    classLoader = nue;
0416:                    updateContextClassLoaders(classLoader, false);
0417:                }
0418:                firer.change(new ChangeFirer.Change(this , PROP_CLASS_LOADER,
0419:                        null, null));
0420:            }
0421:
0422:            private static void updateContextClassLoaders(ClassLoader l,
0423:                    boolean force) {
0424:                // See #20663.
0425:                ThreadGroup g = Thread.currentThread().getThreadGroup();
0426:                while (g.getParent() != null)
0427:                    g = g.getParent();
0428:                // Now g is the master thread group, hopefully.
0429:                // See #4097747 for an explanation of the convoluted logic.
0430:                while (true) {
0431:                    int s = g.activeCount() + 1;
0432:                    Thread[] ts = new Thread[s];
0433:                    int x = g.enumerate(ts, true);
0434:                    if (x < s) {
0435:                        // We got all of the threads, good.
0436:                        for (int i = 0; i < x; i++) {
0437:                            // The first time when we make the manager, set all of the
0438:                            // threads to have this context classloader. Let's hope no
0439:                            // threads needing a special context loader have been started
0440:                            // yet! On subsequent occasions, when the classloader
0441:                            // changes, we update all threads for which setContextClassLoader
0442:                            // has not been called with some other special classloader.
0443:                            if (force
0444:                                    || (ts[i].getContextClassLoader() instanceof  SystemClassLoader)) {
0445:                                //Util.err.fine("Setting ctxt CL on " + ts[i].getName() + " to " + l);
0446:                                ts[i].setContextClassLoader(l);
0447:                            } else {
0448:                                Util.err
0449:                                        .fine("Not touching context class loader "
0450:                                                + ts[i].getContextClassLoader()
0451:                                                + " on thread "
0452:                                                + ts[i].getName());
0453:                            }
0454:                        }
0455:                        Util.err.fine("Set context class loader on " + x
0456:                                + " threads");
0457:                        break;
0458:                    } else {
0459:                        Util.err
0460:                                .fine("Race condition getting all threads, restarting...");
0461:                        continue;
0462:                    }
0463:                }
0464:            }
0465:
0466:            /** A classloader giving access to all the module classloaders at once. */
0467:            private static final class SystemClassLoader extends JarClassLoader {
0468:
0469:                private final PermissionCollection allPermissions;
0470:                private final StringBuffer debugme;
0471:                private boolean empty = true;
0472:
0473:                public SystemClassLoader(List<File> files,
0474:                        ClassLoader[] parents, Set<Module> modules)
0475:                        throws IllegalArgumentException {
0476:                    super (files, parents, false);
0477:                    allPermissions = new Permissions();
0478:                    allPermissions.add(new AllPermission());
0479:                    allPermissions.setReadOnly();
0480:                    debugme = new StringBuffer(100 + 50 * modules.size());
0481:                    debugme.append("SystemClassLoader["); // NOI18N
0482:                    for (File file : files) {
0483:                        if (empty) {
0484:                            empty = false;
0485:                        } else {
0486:                            debugme.append(','); // NOI18N
0487:                        }
0488:                        debugme.append(file.getAbsolutePath());
0489:                    }
0490:                    record(modules);
0491:                    debugme.append(']'); // NOI18N
0492:                }
0493:
0494:                private void record(Collection<Module> modules) {
0495:                    for (Module m : modules) {
0496:                        if (empty) {
0497:                            empty = false;
0498:                        } else {
0499:                            debugme.append(','); // NOI18N
0500:                        }
0501:                        debugme.append(m.getCodeNameBase());
0502:                    }
0503:                }
0504:
0505:                public void append(ClassLoader[] ls, List<Module> modules)
0506:                        throws IllegalArgumentException {
0507:                    super .append(ls);
0508:                    debugme.deleteCharAt(debugme.length() - 1);
0509:                    record(modules);
0510:                    debugme.append(']'); // NOI18N
0511:                }
0512:
0513:                protected @Override
0514:                void finalize() throws Throwable {
0515:                    super .finalize();
0516:                    Util.err.fine("Collected system class loader");
0517:                }
0518:
0519:                public @Override
0520:                String toString() {
0521:                    if (debugme == null) {
0522:                        return "SystemClassLoader";
0523:                    }
0524:                    return debugme.toString();
0525:                }
0526:
0527:                /** Provide all permissions for any code loaded from the files list
0528:                 * (i.e. with netbeans.systemclassloader.patches).
0529:                 */
0530:                protected @Override
0531:                PermissionCollection getPermissions(CodeSource cs) {
0532:                    return allPermissions;
0533:                }
0534:
0535:            }
0536:
0537:            /** @see #create(File,Object,boolean,boolean,boolean)
0538:             * @deprecated since org.netbeans.core/1 1.3
0539:             */
0540:            @Deprecated
0541:            public Module create(File jar, Object history, boolean reloadable,
0542:                    boolean autoload) throws IOException, DuplicateException {
0543:                return create(jar, history, reloadable, autoload, false);
0544:            }
0545:
0546:            /** Create a module from a JAR and add it to the managed set.
0547:             * Will initially be disabled, unless it is eager and can
0548:             * be enabled immediately.
0549:             * May throw an IOException if the JAR file cannot be opened
0550:             * for some reason, or is malformed.
0551:             * If there is already a module of the same name managed,
0552:             * throws a duplicate exception. In this case you may wish
0553:             * to delete the original and try again.
0554:             * You must give it some history object which can be used
0555:             * to provide context for where the module came from and
0556:             * whether it has been here before.
0557:             * You cannot request that a module be both autoload and eager.
0558:             */
0559:            public Module create(File jar, Object history, boolean reloadable,
0560:                    boolean autoload, boolean eager) throws IOException,
0561:                    DuplicateException {
0562:                assertWritable();
0563:                ev.log(Events.START_CREATE_REGULAR_MODULE, jar);
0564:                Module m = moduleFactory.create(jar.getAbsoluteFile(), history,
0565:                        reloadable, autoload, eager, this , ev);
0566:                ev.log(Events.FINISH_CREATE_REGULAR_MODULE, jar);
0567:                subCreate(m);
0568:                if (m.isEager()) {
0569:                    List<Module> immediate = simulateEnable(Collections
0570:                            .<Module> emptySet());
0571:                    if (!immediate.isEmpty()) {
0572:                        if (!immediate.contains(m)) {
0573:                            throw new IllegalStateException(
0574:                                    "Can immediately enable modules "
0575:                                            + immediate
0576:                                            + ", but not including " + m
0577:                                            + "; its problems: "
0578:                                            + m.getProblems()); // NOI18N
0579:                        }
0580:                        boolean ok = true;
0581:                        for (Module other : immediate) {
0582:                            if (!other.isAutoload() && !other.isEager()) {
0583:                                // Nope, would require a real module to be turned on first.
0584:                                ok = false;
0585:                                break;
0586:                            }
0587:                        }
0588:                        if (ok) {
0589:                            Util.err.fine("Enabling " + m + " immediately");
0590:                            enable(Collections.<Module> emptySet());
0591:                        }
0592:                    }
0593:                }
0594:                return m;
0595:            }
0596:
0597:            /** Create a fixed module (e.g. from classpath).
0598:             * Will initially be disabled.
0599:             */
0600:            public Module createFixed(Manifest mani, Object history,
0601:                    ClassLoader loader) throws InvalidException,
0602:                    DuplicateException {
0603:                return createFixed(mani, history, loader, false, false);
0604:            }
0605:
0606:            /**
0607:             * Create a fixed module (e.g. from classpath) with optional autoload and eager flags.
0608:             * Will initially be disabled.
0609:             * @since 2.7
0610:             */
0611:            public Module createFixed(Manifest mani, Object history,
0612:                    ClassLoader loader, boolean autoload, boolean eager)
0613:                    throws InvalidException, DuplicateException {
0614:                assertWritable();
0615:                if (mani == null || loader == null)
0616:                    throw new IllegalArgumentException(
0617:                            "null manifest or loader"); // NOI18N
0618:                ev.log(Events.START_CREATE_BOOT_MODULE, history);
0619:                Module m = moduleFactory.createFixed(mani, history, loader,
0620:                        autoload, eager, this , ev);
0621:                ev.log(Events.FINISH_CREATE_BOOT_MODULE, history);
0622:                subCreate(m);
0623:                return m;
0624:            }
0625:
0626:            /** Used by Module to communicate with the ModuleInstaller re. dependencies. */
0627:            void refineDependencies(Module m, Set<Dependency> dependencies) {
0628:                installer.refineDependencies(m, dependencies);
0629:            }
0630:
0631:            /** Allows the installer to add provides (used to provide name of platform we run on)
0632:             */
0633:            String[] refineProvides(Module m) {
0634:                return installer.refineProvides(m);
0635:            }
0636:
0637:            /** Used by Module to communicate with the ModuleInstaller re. classloader. */
0638:            public void refineClassLoader(Module m, List parents) {
0639:                // #27853:
0640:                installer.refineClassLoader(m, parents);
0641:            }
0642:
0643:            /** Use by OneModuleClassLoader to communicate with the ModuleInstaller re. masking. */
0644:            public boolean shouldDelegateResource(Module m, Module parent,
0645:                    String pkg) {
0646:                // Cf. #19621:
0647:                Module.PackageExport[] exports = (parent == null) ? null
0648:                        : parent.getPublicPackages();
0649:                if (exports != null) {
0650:                    //Util.err.fine("exports=" + Arrays.asList(exports));
0651:                    // Packages from parent are restricted: #19621.
0652:                    boolean exported = false;
0653:                    if (parent.isDeclaredAsFriend(m)) { // meaning public to all, or at least to me
0654:                        for (int i = 0; i < exports.length; i++) {
0655:                            if (exports[i].recursive ? pkg
0656:                                    .startsWith(exports[i].pkg) : pkg
0657:                                    .equals(exports[i].pkg)) {
0658:                                //Util.err.fine("matches " + exports[i]);
0659:                                exported = true;
0660:                                break;
0661:                            }
0662:                        }
0663:                    }
0664:                    if (!exported) {
0665:                        // This package is not public. m must have a direct impl-version
0666:                        // dependency on parent or it has no right to use this package.
0667:                        boolean impldep = false;
0668:                        Dependency[] deps = m.getDependenciesArray();
0669:                        for (int i = 0; i < deps.length; i++) {
0670:                            if (deps[i].getType() == Dependency.TYPE_MODULE
0671:                                    && deps[i].getComparison() == Dependency.COMPARE_IMPL
0672:                                    && deps[i].getName().equals(
0673:                                            parent.getCodeName())) {
0674:                                impldep = true;
0675:                                //Util.err.fine("impldep in " + deps[i]);
0676:                                break;
0677:                            }
0678:                        }
0679:                        if (!impldep) {
0680:                            // This module cannot use the package, sorry! It's private.
0681:                            //Util.err.fine("forbidden");
0682:                            if (Util.err.isLoggable(Level.FINE)) {
0683:                                // Note that this is usually harmless. Typical case: Introspector.getBeanInfo
0684:                                // is called on some module-supplied class; this looks in the module's classloader
0685:                                // for org.netbeans.beaninfo.ModuleClassBeanInfo, which of course would not be
0686:                                // found anyway.
0687:                                Util.err
0688:                                        .fine("Refusing to load non-public package "
0689:                                                + pkg
0690:                                                + " for "
0691:                                                + m
0692:                                                + " from parent module "
0693:                                                + parent
0694:                                                + " without an impl dependency");
0695:                            }
0696:                            return false;
0697:                        }
0698:                        //Util.err.fine("impl dep");
0699:                    }
0700:                    //Util.err.fine("exported");
0701:                }
0702:                if (pkg.startsWith("META-INF/")) { // NOI18N
0703:                    // Modules should not make direct reference to metainfo dirs of
0704:                    // other modules. Don't bother logging it, however.
0705:                    return false;
0706:                }
0707:                // The installer can perform additional checks:
0708:                return installer.shouldDelegateResource(m, parent, pkg);
0709:            }
0710:
0711:            // Again, access from Module to ModuleInstaller:
0712:            Manifest loadManifest(File jar) throws IOException {
0713:                return installer.loadManifest(jar);
0714:            }
0715:
0716:            private void subCreate(Module m) throws DuplicateException {
0717:                Util.err.fine("created: " + m);
0718:                Module old = get(m.getCodeNameBase());
0719:                if (old != null) {
0720:                    throw new DuplicateException(old, m);
0721:                }
0722:                modules.add(m);
0723:                modulesByName.put(m.getCodeNameBase(), m);
0724:                possibleProviderAdded(m);
0725:                lookup.add(m);
0726:                firer.created(m);
0727:                firer.change(new ChangeFirer.Change(this , PROP_MODULES, null,
0728:                        null));
0729:                // It might have been that some other modules were thought to be missing
0730:                // dependencies only because they needed this one. And other modules still
0731:                // might have depended on this one, etc. So forget any cached info about
0732:                // problems arising from inter-module dependencies.
0733:                clearProblemCache();
0734:                firer.fire();
0735:            }
0736:
0737:            private void possibleProviderAdded(Module m) {
0738:                String[] provides = m.getProvides();
0739:                for (int i = 0; i < provides.length; i++) {
0740:                    Set<Module> providing = providersOf.get(provides[i]);
0741:                    if (providing == null) {
0742:                        providing = new HashSet<Module>(16);
0743:                        providersOf.put(provides[i], providing);
0744:                    }
0745:                    providing.add(m);
0746:                }
0747:            }
0748:
0749:            /** Remove a module from the managed set.
0750:             * Must be disabled first.
0751:             * Must not be a "fixed" module.
0752:             */
0753:            public void delete(Module m) throws IllegalArgumentException {
0754:                assertWritable();
0755:                if (m.isFixed())
0756:                    throw new IllegalArgumentException("fixed module: " + m); // NOI18N
0757:                if (m.isEnabled())
0758:                    throw new IllegalArgumentException("enabled module: " + m); // NOI18N
0759:                ev.log(Events.DELETE_MODULE, m);
0760:                modules.remove(m);
0761:                modulesByName.remove(m.getCodeNameBase());
0762:                possibleProviderRemoved(m);
0763:                lookup.remove(m);
0764:                firer.deleted(m);
0765:                firer.change(new ChangeFirer.Change(this , PROP_MODULES, null,
0766:                        null));
0767:                firer.change(new ChangeFirer.Change(m, Module.PROP_VALID,
0768:                        Boolean.TRUE, Boolean.FALSE));
0769:                // #14561: some other module might now be uninstallable as a result.
0770:                clearProblemCache();
0771:                m.destroy();
0772:                firer.fire();
0773:            }
0774:
0775:            private void possibleProviderRemoved(Module m) {
0776:                for (String token : m.getProvides()) {
0777:                    Set<Module> providing = providersOf.get(token);
0778:                    if (providing != null) {
0779:                        providing.remove(m);
0780:                        if (providing.isEmpty()) {
0781:                            providersOf.remove(token);
0782:                        }
0783:                    } else {
0784:                        // Else we called reload and m.reload threw IOException, so
0785:                        // it has already removed its provider list
0786:                    }
0787:                }
0788:            }
0789:
0790:            /** Reload a module.
0791:             * This could make a fresh copy of its JAR file preparing
0792:             * to enable it with different contents; at least it will
0793:             * rescan the manifest.
0794:             * It must currently be disabled and not "fixed", and it will
0795:             * stay disabled after this call; to actually reinstall it
0796:             * requires a separate call.
0797:             * It may or may not actually be marked "reloadable", but
0798:             * for greatest reliability it should be.
0799:             * Besides actually reloading the contents, any cached information
0800:             * about failed dependencies or runtime problems with the module
0801:             * is cleared so it may be tried again.
0802:             */
0803:            public void reload(Module m) throws IllegalArgumentException,
0804:                    IOException {
0805:                assertWritable();
0806:                // No Events, not a user- nor performance-interesting action.
0807:                Util.err.fine("reload: " + m);
0808:                if (m.isFixed())
0809:                    throw new IllegalArgumentException("reload fixed module: "
0810:                            + m); // NOI18N
0811:                if (m.isEnabled())
0812:                    throw new IllegalArgumentException(
0813:                            "reload enabled module: " + m); // NOI18N
0814:                possibleProviderRemoved(m);
0815:                try {
0816:                    m.reload();
0817:                } catch (IOException ioe) {
0818:                    // Module is trash, remove it from our list and pass on the exception.
0819:                    delete(m);
0820:                    throw ioe;
0821:                }
0822:                possibleProviderAdded(m);
0823:                firer.change(new ChangeFirer.Change(m, Module.PROP_MANIFEST,
0824:                        null, null));
0825:                // Some problem with this module may now have gone away. In turn, some
0826:                // other modules may now no longer have problems. So clear the cache
0827:                // of "soft" problems (interdependencies between modules).
0828:                // Also clear any "hard" problems associated with this module, as they
0829:                // may now have been fixed.
0830:                moduleProblemsWithoutNeeds.remove(m);
0831:                moduleProblemsWithNeeds.remove(m);
0832:                firer.change(new ChangeFirer.Change(m, Module.PROP_PROBLEMS,
0833:                        null, null));
0834:                clearProblemCache();
0835:                firer.fire();
0836:            }
0837:
0838:            /** Enable a single module.
0839:             * Must have satisfied its dependencies.
0840:             * Must not be an autoload module, when supported.
0841:             */
0842:            public final void enable(Module m) throws IllegalArgumentException,
0843:                    InvalidException {
0844:                enable(Collections.singleton(m));
0845:            }
0846:
0847:            /** Disable a single module.
0848:             * Must not be required by any enabled modules.
0849:             * Must not be an autoload module, when supported.
0850:             */
0851:            public final void disable(Module m) throws IllegalArgumentException {
0852:                disable(Collections.singleton(m));
0853:            }
0854:
0855:            /** Enable a set of modules together.
0856:             * Must have satisfied their dependencies
0857:             * (possibly with one another).
0858:             * Must not contain autoload nor eager modules.
0859:             * Might contain fixed modules (they can only be installed once of course).
0860:             * It is permissible to pass in modules which in fact at runtime cannot
0861:             * satisfy their package dependencies, or which {@link ModuleInstaller#prepare}
0862:             * rejects on the basis of missing contents. In such a case InvalidException
0863:             * will be thrown and nothing will be installed. The InvalidException in such
0864:             * a case should contain a reference to the offending module.
0865:             */
0866:            public void enable(Set<Module> modules)
0867:                    throws IllegalArgumentException, InvalidException {
0868:                assertWritable();
0869:                Util.err.fine("enable: " + modules);
0870:                /* Consider eager modules:
0871:                if (modules.isEmpty()) {
0872:                    return;
0873:                }
0874:                 */
0875:                ev.log(Events.PERF_START, "ModuleManager.enable"); // NOI18N
0876:                // Basic problems will be caught here, and we also get the autoloads:
0877:                List<Module> toEnable = simulateEnable(modules);
0878:                ev.log(Events.PERF_TICK,
0879:                        "checked the required ordering and autoloads"); // NOI18N
0880:
0881:                Util.err.fine("enable: toEnable=" + toEnable); // NOI18N
0882:                {
0883:                    // Verify that we are cool as far as basic dependencies go.
0884:                    Set<Module> testing = new HashSet<Module>(toEnable);
0885:                    if (!testing.containsAll(modules)) {
0886:                        Set<Module> bogus = new HashSet<Module>(modules);
0887:                        bogus.removeAll(testing);
0888:                        throw new IllegalArgumentException(
0889:                                "Not all requested modules can be enabled: "
0890:                                        + bogus); // NOI18N
0891:                    }
0892:                    for (Module m : testing) {
0893:                        if (!modules.contains(m) && !m.isAutoload()
0894:                                && !m.isEager()) {
0895:                            throw new IllegalArgumentException(
0896:                                    "Would also need to enable " + m); // NOI18N
0897:                        }
0898:                    }
0899:                }
0900:                Util.err.fine("enable: verified dependencies");
0901:                ev.log(Events.PERF_TICK, "verified dependencies"); // NOI18N
0902:
0903:                ev.log(Events.START_ENABLE_MODULES, toEnable);
0904:                {
0905:                    // Actually turn on the listed modules.
0906:                    // List of modules that need to be "rolled back".
0907:                    LinkedList<Module> fallback = new LinkedList<Module>();
0908:                    // Whether we were attempting to bring a classloader up.
0909:                    // This affects whether we need to rollback that change on the
0910:                    // problem module or not.
0911:                    boolean tryingClassLoaderUp = false;
0912:                    // If a failure due to package dep occurs, store it here.
0913:                    Dependency failedPackageDep = null;
0914:                    try {
0915:                        ev.log(Events.PERF_START, "module preparation"); // NOI18N
0916:                        for (Module m : toEnable) {
0917:                            fallback.addFirst(m);
0918:                            Util.err.fine("enable: bringing up: " + m);
0919:                            ev.log(Events.PERF_START,
0920:                                    "bringing up classloader on "
0921:                                            + m.getCodeName()); // NOI18N
0922:                            try {
0923:                                // Calculate the parents to initialize the classloader with.
0924:                                Dependency[] dependencies = m
0925:                                        .getDependenciesArray();
0926:                                Set<Module> parents = new HashSet<Module>(
0927:                                        dependencies.length * 4 / 3 + 1);
0928:                                for (int i = 0; i < dependencies.length; i++) {
0929:                                    Dependency dep = dependencies[i];
0930:                                    if (dep.getType() != Dependency.TYPE_MODULE) {
0931:                                        // Token providers do *not* go into the parent classloader
0932:                                        // list. The providing module must have been turned on first.
0933:                                        // But you cannot automatically access classes from it.
0934:                                        continue;
0935:                                    }
0936:                                    String name = (String) Util
0937:                                            .parseCodeName(dep.getName())[0];
0938:                                    Module parent = get(name);
0939:                                    // Should not happen:
0940:                                    if (parent == null)
0941:                                        throw new IOException("Parent " + name
0942:                                                + " not found!"); // NOI18N
0943:                                    parents.add(parent);
0944:                                }
0945:                                m.classLoaderUp(parents);
0946:                            } catch (IOException ioe) {
0947:                                tryingClassLoaderUp = true;
0948:                                InvalidException ie = new InvalidException(m,
0949:                                        ioe.toString());
0950:                                ie.initCause(ioe);
0951:                                throw ie;
0952:                            }
0953:                            m.setEnabled(true);
0954:                            ev.log(Events.PERF_END,
0955:                                    "bringing up classloader on "
0956:                                            + m.getCodeName()); // NOI18N
0957:                            // Check package dependencies.
0958:                            //                    ev.log(Events.PERF_START, "package dependency check on " + m.getCodeName() ); // NOI18N
0959:                            Util.err
0960:                                    .fine("enable: checking package dependencies for "
0961:                                            + m);
0962:                            Dependency[] dependencies = m
0963:                                    .getDependenciesArray();
0964:                            for (int i = 0; i < dependencies.length; i++) {
0965:                                Dependency dep = dependencies[i];
0966:                                if (dep.getType() != Dependency.TYPE_PACKAGE) {
0967:                                    continue;
0968:                                }
0969:                                if (!Util.checkPackageDependency(dep, m
0970:                                        .getClassLoader())) {
0971:                                    failedPackageDep = dep;
0972:                                    throw new InvalidException(m,
0973:                                            "Dependency failed on " + dep); // NOI18N
0974:                                }
0975:                                Util.err.fine("Successful check for: " + dep);
0976:                            }
0977:                            //                    ev.log(Events.PERF_END, "package dependency check on " + m.getCodeName() ); // NOI18N
0978:                            // Prepare to load it.
0979:                            ev.log(Events.PERF_START,
0980:                                    "ModuleInstaller.prepare "
0981:                                            + m.getCodeName()); // NOI18N
0982:                            installer.prepare(m);
0983:                            ev.log(Events.PERF_END, "ModuleInstaller.prepare "
0984:                                    + m.getCodeName()); // NOI18N
0985:                        }
0986:                        ev.log(Events.PERF_END, "module preparation"); // NOI18N
0987:
0988:                    } catch (InvalidException ie) {
0989:                        // Remember that there was a problem with this guy.
0990:                        Module bad = ie.getModule();
0991:                        if (bad == null)
0992:                            throw new IllegalStateException(
0993:                                    "Problem with no associated module: " + ie); // NOI18N
0994:                        Set<Union2<Dependency, InvalidException>> probs = moduleProblemsWithNeeds
0995:                                .get(bad);
0996:                        if (probs == null)
0997:                            throw new IllegalStateException(
0998:                                    "Were trying to install a module that had never been checked: "
0999:                                            + bad); // NOI18N
1000:                        if (!probs.isEmpty())
1001:                            throw new IllegalStateException(
1002:                                    "Were trying to install a module that was known to be bad: "
1003:                                            + bad); // NOI18N
1004:                        // Record for posterity.
1005:                        if (failedPackageDep != null) {
1006:                            // Structured package dependency failed, track this.
1007:                            probs
1008:                                    .add(Union2
1009:                                            .<Dependency, InvalidException> createFirst(failedPackageDep));
1010:                        } else {
1011:                            // Some other problem (exception).
1012:                            probs
1013:                                    .add(Union2
1014:                                            .<Dependency, InvalidException> createSecond(ie));
1015:                        }
1016:                        // Other modules may have depended on this one and now will not be OK.
1017:                        // So clear all "soft" problems from the cache.
1018:                        // Remember, the problem we just added will be left alone, only
1019:                        // inter-module dependencies will be cleared.
1020:                        clearProblemCache();
1021:                        // #14560: this one definitely changed its set of problems.
1022:                        firer.change(new ChangeFirer.Change(bad,
1023:                                Module.PROP_PROBLEMS, Collections.EMPTY_SET,
1024:                                Collections.singleton("something"))); // NOI18N
1025:                        // Rollback changes made so far before rethrowing.
1026:                        Util.err.fine("enable: will roll back from: " + ie);
1027:                        for (Module m : fallback) {
1028:                            if (m.isFixed()) {
1029:                                // cannot disable fixed modules
1030:                                continue;
1031:                            }
1032:                            m.setEnabled(false);
1033:                            if (tryingClassLoaderUp) {
1034:                                // OK, taken into account for first module, others are up.
1035:                                tryingClassLoaderUp = false;
1036:                            } else {
1037:                                m.classLoaderDown();
1038:                                System.gc();
1039:                                System.runFinalization();
1040:                                m.cleanup();
1041:                            }
1042:                        }
1043:                        firer.fire();
1044:                        throw ie;
1045:                    }
1046:                    // They all were OK so far; add to system classloader and install them.
1047:                    if (classLoader != null) {
1048:                        Util.err.fine("enable: adding to system classloader");
1049:                        LinkedList<ClassLoader> nueclassloaders = new LinkedList<ClassLoader>();
1050:                        if (moduleFactory.removeBaseClassLoader()) {
1051:                            ClassLoader base = ModuleManager.class
1052:                                    .getClassLoader();
1053:                            nueclassloaders
1054:                                    .add(moduleFactory
1055:                                            .getClasspathDelegateClassLoader(
1056:                                                    this , base));
1057:                            for (Module m : toEnable) {
1058:                                ClassLoader c1 = m.getClassLoader();
1059:                                if (c1 != base) {
1060:                                    nueclassloaders.add(c1);
1061:                                }
1062:                            }
1063:                        } else {
1064:                            for (Module m : toEnable) {
1065:                                if (m.getClassLoader() == ClassLoader
1066:                                        .getSystemClassLoader()) {
1067:                                    nueclassloaders
1068:                                            .addFirst(m.getClassLoader());
1069:                                } else {
1070:                                    nueclassloaders.add(m.getClassLoader());
1071:                                }
1072:                            }
1073:                        }
1074:                        classLoader
1075:                                .append(
1076:                                        (nueclassloaders
1077:                                                .toArray(new ClassLoader[nueclassloaders
1078:                                                        .size()])), toEnable);
1079:                    } else {
1080:                        Util.err
1081:                                .fine("enable: no class loader yet, not appending");
1082:                    }
1083:                    Util.err.fine("enable: continuing to installation");
1084:                    installer.load(toEnable);
1085:                }
1086:                {
1087:                    // Take care of notifying various changes.
1088:                    Util.err.fine("enable: firing changes");
1089:                    firer.change(new ChangeFirer.Change(this ,
1090:                            PROP_ENABLED_MODULES, null, null));
1091:                    // The class loader does not actually change as a result of this.
1092:                    for (Module m : toEnable) {
1093:                        firer.change(new ChangeFirer.Change(m,
1094:                                ModuleInfo.PROP_ENABLED, Boolean.FALSE,
1095:                                Boolean.TRUE));
1096:                        if (!m.isFixed()) {
1097:                            firer.change(new ChangeFirer.Change(m,
1098:                                    Module.PROP_CLASS_LOADER, null, null));
1099:                        }
1100:                    }
1101:                }
1102:                ev.log(Events.FINISH_ENABLE_MODULES, toEnable);
1103:                firer.fire();
1104:            }
1105:
1106:            /** Disable a set of modules together.
1107:             * Must not be required by any enabled
1108:             * modules (except one another).
1109:             * Must not contain autoload nor eager modules.
1110:             * Must not contain fixed modules.
1111:             */
1112:            public void disable(Set<Module> modules)
1113:                    throws IllegalArgumentException {
1114:                assertWritable();
1115:                Util.err.fine("disable: " + modules);
1116:                if (modules.isEmpty()) {
1117:                    return;
1118:                }
1119:                // Checks for invalid items, plus includes autoloads to turn off.
1120:                List<Module> toDisable = simulateDisable(modules);
1121:                Util.err.fine("disable: toDisable=" + toDisable);
1122:                {
1123:                    // Verify that dependencies are OK.
1124:                    for (Module m : toDisable) {
1125:                        if (!modules.contains(m) && !m.isAutoload()
1126:                                && !m.isEager()) {
1127:                            throw new IllegalArgumentException(
1128:                                    "Would also need to disable: " + m); // NOI18N
1129:                        }
1130:                    }
1131:                }
1132:                Util.err.fine("disable: verified dependencies");
1133:                ev.log(Events.START_DISABLE_MODULES, toDisable);
1134:                {
1135:                    // Actually turn off all modules.
1136:                    installer.unload(toDisable);
1137:                    for (Module m : toDisable) {
1138:                        installer.dispose(m);
1139:                        m.setEnabled(false);
1140:                        m.classLoaderDown();
1141:                    }
1142:                    System.gc(); // hope OneModuleClassLoader.finalize() is called...
1143:                    System.runFinalization();
1144:                    // but probably it won't be. See #4405807.
1145:                    for (Module m : toDisable) {
1146:                        m.cleanup();
1147:                    }
1148:                }
1149:                Util.err.fine("disable: finished, will notify changes");
1150:                {
1151:                    // Notify various changes.
1152:                    firer.change(new ChangeFirer.Change(this ,
1153:                            PROP_ENABLED_MODULES, null, null));
1154:                    // Class loader will change as a result.
1155:                    invalidateClassLoader();
1156:                    for (Module m : toDisable) {
1157:                        firer.change(new ChangeFirer.Change(m,
1158:                                ModuleInfo.PROP_ENABLED, Boolean.TRUE,
1159:                                Boolean.FALSE));
1160:                        firer.change(new ChangeFirer.Change(m,
1161:                                Module.PROP_CLASS_LOADER, null, null));
1162:                    }
1163:                }
1164:                ev.log(Events.FINISH_DISABLE_MODULES, toDisable);
1165:                firer.fire();
1166:            }
1167:
1168:            /** Simulate what would happen if a set of modules were to be enabled.
1169:             * None of the listed modules may be autoload modules, nor eager, nor currently enabled,
1170:             * though they may be fixed (if they have not yet been enabled).
1171:             * It may happen that some of them do not satisfy their dependencies.
1172:             * It may also happen that some of them require other, currently disabled,
1173:             * modules to be enabled in order for them to be enabled.
1174:             * It may further happen that some currently disabled eager modules could
1175:             * be enabled as a result of these modules being enabled.
1176:             * The returned set is the set of all modules that actually could be enabled.
1177:             * It will include the requested modules, minus any that cannot satisfy
1178:             * their dependencies (even on each other), plus any managed but currently
1179:             * disabled modules that would need to be enabled (including autoload modules
1180:             * required by some listed module but not by any currently enabled module),
1181:             * plus any eager modules which can be enabled with the other enablements
1182:             * (and possibly any autoloads needed by those eager modules).
1183:             * Where a requested module requires some token, either it will not be included
1184:             * in the result (in case the dependency cannot be satisfied), or it will, and
1185:             * all modules providing that token which can be included will be included, even
1186:             * if it would suffice to choose only one - unless a module providing that token
1187:             * is already enabled or in the requested list,
1188:             * in which case just the requested module will be listed.
1189:             * Modules are returned in an order in which they could be enabled (where
1190:             * base modules are always enabled before dependent modules).
1191:             * Note that the returned list might include modules which in fact cannot be
1192:             * enabled either because some package dependencies (which are checked only
1193:             * on a live classloader) cannot be met; or {@link ModuleInstaller#prepare}
1194:             * indicates that the modules are not in a valid format to install; or
1195:             * creating the module classloader fails unexpectedly.
1196:             */
1197:            public List<Module> simulateEnable(Set<Module> modules)
1198:                    throws IllegalArgumentException {
1199:                /* Not quite, eager modules may change this:
1200:                if (modules.isEmpty()) {
1201:                    return Collections.EMPTY_LIST;
1202:                }
1203:                 */
1204:                // XXX also optimize for modules.size == 1
1205:                Set<Module> willEnable = new HashSet<Module>(
1206:                        modules.size() * 2 + 1);
1207:                for (Module m : modules) {
1208:                    if (m.isAutoload())
1209:                        throw new IllegalArgumentException(
1210:                                "Cannot simulate enabling an autoload: " + m); // NOI18N
1211:                    if (m.isEager())
1212:                        throw new IllegalArgumentException(
1213:                                "Cannot simulate enabling an eager module: "
1214:                                        + m); // NOI18N
1215:                    if (m.isEnabled())
1216:                        throw new IllegalArgumentException("Already enabled: "
1217:                                + m); // NOI18N
1218:                    if (!m.isValid())
1219:                        throw new IllegalArgumentException(
1220:                                "Not managed by me: " + m + " in " + m); // NOI18N
1221:                    maybeAddToEnableList(willEnable, modules, m, true);
1222:                }
1223:                // XXX clumsy but should work:
1224:                Set<Module> stillDisabled = new HashSet<Module>(this .modules);
1225:                Iterator<Module> it = stillDisabled.iterator();
1226:                while (it.hasNext()) {
1227:                    Module m = it.next();
1228:                    if (m.isEnabled() || willEnable.contains(m)) {
1229:                        it.remove();
1230:                    }
1231:                }
1232:                while (searchForPossibleEager(willEnable, stillDisabled,
1233:                        modules)) {/* search again */
1234:                }
1235:                Map<Module, List<Module>> deps = Util.moduleDependencies(
1236:                        willEnable, modulesByName, providersOf);
1237:                try {
1238:                    List<Module> l = Utilities
1239:                            .topologicalSort(willEnable, deps);
1240:                    Collections.reverse(l);
1241:                    return l;
1242:                } catch (TopologicalSortException ex) {
1243:                    // Some kind of cycle involving prov-req deps. Should be extremely rare.
1244:                    // Example (from random failures of MMT.testProvReqCycles):
1245:                    // m1 => {m2 | m3}
1246:                    // m2 => {m1 | m4}
1247:                    // m3 => {m1}
1248:                    // m4 => {}
1249:                    // Now consider:
1250:                    // sE(m2) = ?
1251:                    // [m4, m2] is fine.
1252:                    // [m4, m2, m1] would be OK too, but will result in TSE.
1253:                    // Do not know what to do here, actually, so give up.
1254:                    if (PRINT_TOPOLOGICAL_EXCEPTION_STACK_TRACES) {
1255:                        Util.err.log(Level.WARNING, null, ex);
1256:                    }
1257:                    Util.err
1258:                            .warning("Cyclic module dependencies, will refuse to enable: "
1259:                                    + deps); // NOI18N
1260:                    return Collections.<Module> emptyList();
1261:                }
1262:            }
1263:
1264:            private void maybeAddToEnableList(Set<Module> willEnable,
1265:                    Set<Module> mightEnable, Module m, boolean okToFail) {
1266:                if (!missingDependencies(m).isEmpty()) {
1267:                    assert okToFail : "Module " + m
1268:                            + " had unexpected problems: "
1269:                            + missingDependencies(m) + " (willEnable: "
1270:                            + willEnable + " mightEnable: " + mightEnable + ")";
1271:                    // Cannot satisfy its dependencies, exclude it.
1272:                    return;
1273:                }
1274:                if (!willEnable.add(m)) {
1275:                    // Already there, done.
1276:                    return;
1277:                }
1278:                // Also add anything it depends on, if not already there,
1279:                // or already enabled.
1280:                for (Dependency dep : m.getDependenciesArray()) {
1281:                    if (dep.getType() == Dependency.TYPE_MODULE) {
1282:                        String codeNameBase = (String) Util.parseCodeName(dep
1283:                                .getName())[0];
1284:                        Module other = get(codeNameBase);
1285:                        // Should never happen:
1286:                        if (other == null)
1287:                            throw new IllegalStateException(
1288:                                    "Should have found module: " + codeNameBase); // NOI18N
1289:                        if (!other.isEnabled()) {
1290:                            maybeAddToEnableList(willEnable, mightEnable,
1291:                                    other, false);
1292:                        }
1293:                    } else if (dep.getType() == Dependency.TYPE_REQUIRES
1294:                            || dep.getType() == Dependency.TYPE_NEEDS
1295:                            || dep.getType() == Dependency.TYPE_RECOMMENDS) {
1296:                        Set<Module> providers = providersOf.get(dep.getName());
1297:                        if (providers == null) {
1298:                            assert dep.getType() == Dependency.TYPE_RECOMMENDS : "Should have found a provider of "
1299:                                    + dep;
1300:                            continue;
1301:                        }
1302:                        // First check if >= 1 is already enabled or will be soon. If so, great.
1303:                        boolean foundOne = false;
1304:                        for (Module other : providers) {
1305:                            if (other.isEnabled()
1306:                                    || (other.getProblems().isEmpty() && mightEnable
1307:                                            .contains(other))) {
1308:                                foundOne = true;
1309:                                break;
1310:                            }
1311:                        }
1312:                        if (foundOne) {
1313:                            // OK, we are satisfied.
1314:                            continue;
1315:                        }
1316:                        // All disabled. So add them all to the enable list.
1317:                        for (Module other : providers) {
1318:                            // It is OK if one of them fails.
1319:                            maybeAddToEnableList(willEnable, mightEnable,
1320:                                    other, true);
1321:                            // But we still check to ensure that at least one did not!
1322:                            if (!foundOne && willEnable.contains(other)) {
1323:                                foundOne = true;
1324:                                // and continue with the others, try to add them too...
1325:                            }
1326:                        }
1327:                        // Logic is that missingDependencies(m) should contain dep in this case.
1328:                        assert foundOne
1329:                                || dep.getType() == Dependency.TYPE_RECOMMENDS : "Should have found a nonproblematic provider of "
1330:                                + dep
1331:                                + " among "
1332:                                + providers
1333:                                + " with willEnable="
1334:                                + willEnable
1335:                                + " mightEnable=" + mightEnable;
1336:                    }
1337:                    // else some other kind of dependency that does not concern us
1338:                }
1339:            }
1340:
1341:            private boolean searchForPossibleEager(Set<Module> willEnable,
1342:                    Set<Module> stillDisabled, Set<Module> mightEnable) {
1343:                // Check for any eagers in stillDisabled which could be enabled based
1344:                // on currently enabled modules and willEnable. For any such, remove from
1345:                // stillDisabled and add to willEnable (using maybeAddToEnableList, so that
1346:                // autoloads needed by them are picked up too). If any were found, return true.
1347:                boolean found = false;
1348:                Iterator<Module> it = stillDisabled.iterator();
1349:                FIND_EAGER: while (it.hasNext()) {
1350:                    Module m = it.next();
1351:                    if (willEnable.contains(m)) {
1352:                        // Presumably real module M1, eager M2 dep. on M1, eager M3 dep.
1353:                        // on M2; already called couldBeEnabledWithEagers(M3) and it
1354:                        // added M3 to willEnable (thus M2 also) but only removed M3
1355:                        // from willEnable, so we should skip it now.
1356:                        it.remove();
1357:                        continue;
1358:                    }
1359:                    if (m.isEager()) {
1360:                        if (couldBeEnabledWithEagers(m, willEnable,
1361:                                new HashSet<Module>())) {
1362:                            // Go for it!
1363:                            found = true;
1364:                            it.remove();
1365:                            maybeAddToEnableList(willEnable, mightEnable, m,
1366:                                    false);
1367:                        }
1368:                    }
1369:                }
1370:                return found;
1371:            }
1372:
1373:            private boolean couldBeEnabledWithEagers(Module m,
1374:                    Set<Module> willEnable, Set<Module> recursion) {
1375:                // True if a search of the dependencies of this module reveals
1376:                // only modules which are currently enabled; in the willEnable
1377:                // list; or are autoloads or eager modules for which this predicate
1378:                // is recursively true.
1379:                if (m.isEnabled() || willEnable.contains(m))
1380:                    return true;
1381:                if (!m.isAutoload() && !m.isEager())
1382:                    return false;
1383:                if (!m.getProblems().isEmpty())
1384:                    return false;
1385:                if (!recursion.add(m)) {
1386:                    // A cycle, they can enable one another...
1387:                    return true;
1388:                }
1389:                Dependency[] dependencies = m.getDependenciesArray();
1390:                for (int i = 0; i < dependencies.length; i++) {
1391:                    Dependency dep = dependencies[i];
1392:                    if (dep.getType() == Dependency.TYPE_MODULE) {
1393:                        String codeNameBase = (String) Util.parseCodeName(dep
1394:                                .getName())[0];
1395:                        Module other = get(codeNameBase);
1396:                        // Should never happen:
1397:                        if (other == null)
1398:                            throw new IllegalStateException(
1399:                                    "Should have found module: " + codeNameBase); // NOI18N
1400:                        if (!couldBeEnabledWithEagers(other, willEnable,
1401:                                recursion))
1402:                            return false;
1403:                    } else if (dep.getType() == Dependency.TYPE_REQUIRES) {
1404:                        Set<Module> providers = providersOf.get(dep.getName());
1405:                        if (providers == null)
1406:                            throw new IllegalStateException(
1407:                                    "Should have found a provider of: "
1408:                                            + dep.getName()); // NOI18N
1409:                        // Just need *one* to match.
1410:                        boolean foundOne = false;
1411:                        for (Module other : providers) {
1412:                            if (couldBeEnabledWithEagers(other, willEnable,
1413:                                    recursion)) {
1414:                                foundOne = true;
1415:                                break;
1416:                            }
1417:                        }
1418:                        if (!foundOne)
1419:                            return false;
1420:                    }
1421:                    // else some other dep type
1422:                }
1423:                return true;
1424:            }
1425:
1426:            /** Simulate what would happen if a set of modules were to be disabled.
1427:             * None of the listed modules may be autoload modules, nor eager, nor currently disabled, nor fixed.
1428:             * The returned set will list all modules that would actually be disabled,
1429:             * meaning the listed modules, plus any currently enabled but unlisted modules
1430:             * (including autoloads) that require some listed modules, plus any autoloads
1431:             * which would no longer be needed as they were only required by modules
1432:             * otherwise disabled.
1433:             * Provide-require pairs count for purposes of disablement: if the set of
1434:             * requested modules includes all remaining enabled providers of some token,
1435:             * and modules requiring that token will need to be disabled as well.
1436:             * Modules are returned in an order in which they could be disabled (where
1437:             * dependent modules are always disabled before base modules).
1438:             */
1439:            public List<Module> simulateDisable(Set<Module> modules)
1440:                    throws IllegalArgumentException {
1441:                if (modules.isEmpty()) {
1442:                    return Collections.<Module> emptyList();
1443:                }
1444:                // XXX also optimize for modules.size == 1
1445:                // Probably not a very efficient algorithm. But it probably does not need to be.
1446:                Set<Module> willDisable = new HashSet<Module>(20);
1447:                for (Module m : modules) {
1448:                    if (m.isAutoload())
1449:                        throw new IllegalArgumentException(
1450:                                "Cannot disable autoload: " + m); // NOI18N
1451:                    if (m.isEager())
1452:                        throw new IllegalArgumentException(
1453:                                "Cannot disable eager module: " + m); // NOI18N
1454:                    if (m.isFixed())
1455:                        throw new IllegalArgumentException(
1456:                                "Cannot disable fixed module: " + m); // NOI18N
1457:                    if (!m.isEnabled())
1458:                        throw new IllegalArgumentException("Already disabled: "
1459:                                + m); // NOI18N
1460:                    addToDisableList(willDisable, m);
1461:                }
1462:                Set<Module> stillEnabled = new HashSet<Module>(
1463:                        getEnabledModules());
1464:                stillEnabled.removeAll(willDisable);
1465:                while (searchForUnusedAutoloads(willDisable, stillEnabled)) {/* search again */
1466:                }
1467:                Map<Module, List<Module>> deps = Util.moduleDependencies(
1468:                        willDisable, modulesByName, providersOf);
1469:                try {
1470:                    return Utilities.topologicalSort(willDisable, deps);
1471:                } catch (TopologicalSortException ex) {
1472:                    // Again, don't know what to do exactly, so give up and just turn them off.
1473:                    if (PRINT_TOPOLOGICAL_EXCEPTION_STACK_TRACES) {
1474:                        Util.err.log(Level.WARNING, null, ex);
1475:                    }
1476:                    Util.err
1477:                            .warning("Cyclic module dependencies, will turn them off in a random order: "
1478:                                    + deps); // NOI18N
1479:                    return new ArrayList<Module>(willDisable);
1480:                }
1481:            }
1482:
1483:            private void addToDisableList(Set<Module> willDisable, Module m) {
1484:                if (willDisable.contains(m)) {
1485:                    // E.g. if original set had A then B, B depends on A.
1486:                    return;
1487:                }
1488:                willDisable.add(m);
1489:                // Find any modules depending on this one which are currently enabled.
1490:                // (And not already here.)
1491:                // If there are any, add them.
1492:                for (Module other : modules) {
1493:                    if (other.isFixed() || !other.isEnabled()
1494:                            || willDisable.contains(other)) {
1495:                        continue;
1496:                    }
1497:                    Dependency[] depenencies = other.getDependenciesArray();
1498:                    for (int i = 0; i < depenencies.length; i++) {
1499:                        Dependency dep = depenencies[i];
1500:                        if (dep.getType() == Dependency.TYPE_MODULE) {
1501:                            if (dep.getName().equals(m.getCodeName())) {
1502:                                // Need to disable this one too.
1503:                                addToDisableList(willDisable, other);
1504:                                // No need to scan the rest of its dependencies.
1505:                                break;
1506:                            }
1507:                        } else if (dep.getType() == Dependency.TYPE_REQUIRES
1508:                                || dep.getType() == Dependency.TYPE_NEEDS) {
1509:                            if (m.provides(dep.getName())) {
1510:                                // Careful. There may be some third module still enabled which
1511:                                // provides this same token too.
1512:                                boolean foundOne = false;
1513:                                for (Module third : getEnabledModules()) {
1514:                                    if (third.isEnabled()
1515:                                            && !willDisable.contains(third)
1516:                                            && third.provides(dep.getName())) {
1517:                                        foundOne = true;
1518:                                        break;
1519:                                    }
1520:                                }
1521:                                if (!foundOne) {
1522:                                    // Nope, we were the only/last one to provide it.
1523:                                    addToDisableList(willDisable, other);
1524:                                    break;
1525:                                }
1526:                            }
1527:                        }
1528:                        // else some other kind of dependency, we do not care
1529:                    }
1530:                }
1531:            }
1532:
1533:            private boolean searchForUnusedAutoloads(Set<Module> willDisable,
1534:                    Set<Module> stillEnabled) {
1535:                // Check for any autoloads in stillEnabled which are not used by anything else
1536:                // in stillEnabled. For each such, remove it from stillEnabled and add
1537:                // to willDisable. If any were found, return true.
1538:                boolean found = false;
1539:                Iterator<Module> it = stillEnabled.iterator();
1540:                FIND_AUTOLOADS: while (it.hasNext()) {
1541:                    Module m = it.next();
1542:                    if (m.isAutoload()) {
1543:                        for (Module other : stillEnabled) {
1544:                            Dependency[] dependencies = other
1545:                                    .getDependenciesArray();
1546:                            for (int i = 0; i < dependencies.length; i++) {
1547:                                Dependency dep = dependencies[i];
1548:                                if (dep.getType() == Dependency.TYPE_MODULE) {
1549:                                    if (Util.parseCodeName(dep.getName())[0]
1550:                                            .equals(m.getCodeNameBase())) {
1551:                                        // Still used, skip it.
1552:                                        continue FIND_AUTOLOADS;
1553:                                    }
1554:                                } else if (dep.getType() == Dependency.TYPE_REQUIRES
1555:                                        || dep.getType() == Dependency.TYPE_NEEDS
1556:                                        || dep.getType() == Dependency.TYPE_RECOMMENDS) {
1557:                                    // Here we play it safe and leave autoloads on if they provide
1558:                                    // something used by some module - even if technically it would
1559:                                    // be possible to turn off the autoload because there is another
1560:                                    // enabled module providing the same thing. Leave it on anyway.
1561:                                    if (m.provides(dep.getName())) {
1562:                                        continue FIND_AUTOLOADS;
1563:                                    }
1564:                                }
1565:                                // else some other type
1566:                            }
1567:                        }
1568:                        // Nobody uses it!
1569:                        found = true;
1570:                        it.remove();
1571:                        willDisable.add(m);
1572:                    }
1573:                }
1574:                return found;
1575:            }
1576:
1577:            // dummy object to be placed in the problem set while recursive checking is in progress
1578:            private static final Union2<Dependency, InvalidException> PROBING_IN_PROCESS = Union2
1579:                    .createSecond(new InvalidException("PROBING_IN_PROCESS"));
1580:
1581:            // Access from Module.getProblems, q.v.
1582:            // The probed module must not be currently enabled or fixed.
1583:            Set<Union2<Dependency, InvalidException>> missingDependencies(
1584:                    Module probed) {
1585:                return missingDependencies(probed, true);
1586:            }
1587:
1588:            private Set<Union2<Dependency, InvalidException>> missingDependencies(
1589:                    Module probed, boolean withNeeds) {
1590:                // We need to synchronize here because though this method may be called
1591:                // only within a read mutex, it can write to moduleProblems. Other places
1592:                // where moduleProblems are used are write-mutex only and so do not have
1593:                // to worry about contention.
1594:                synchronized (moduleProblemsWithNeeds) {
1595:                    Map<Module, Set<Union2<Dependency, InvalidException>>> mP = (withNeeds ? moduleProblemsWithNeeds
1596:                            : moduleProblemsWithoutNeeds);
1597:                    Set<Union2<Dependency, InvalidException>> probs = mP
1598:                            .get(probed);
1599:                    if (probs == null) {
1600:                        probs = new HashSet<Union2<Dependency, InvalidException>>(
1601:                                8);
1602:                        if (withNeeds) {
1603:                            probs.addAll(missingDependencies(probed, false));
1604:                        }
1605:                        probs.add(PROBING_IN_PROCESS);
1606:                        mP.put(probed, probs);
1607:                        for (Dependency dep : probed.getDependenciesArray()) {
1608:                            if (dep.getType() == Dependency.TYPE_PACKAGE) {
1609:                                // Can't check it in advance. Assume it is OK; if not
1610:                                // a problem will be indicated during an actual installation
1611:                                // attempt.
1612:                            } else if (dep.getType() == Dependency.TYPE_MODULE) {
1613:                                // Look for the corresponding module.
1614:                                Object[] depParse = Util.parseCodeName(dep
1615:                                        .getName());
1616:                                String codeNameBase = (String) depParse[0];
1617:                                int relVersionMin = (depParse[1] != null) ? ((Integer) depParse[1])
1618:                                        .intValue()
1619:                                        : -1;
1620:                                int relVersionMax = (depParse[2] != null) ? ((Integer) depParse[2])
1621:                                        .intValue()
1622:                                        : relVersionMin;
1623:                                Module other = get(codeNameBase);
1624:                                if (other == null) {
1625:                                    // No such module, bad.
1626:                                    probs
1627:                                            .add(Union2
1628:                                                    .<Dependency, InvalidException> createFirst(dep));
1629:                                    continue;
1630:                                }
1631:                                if (relVersionMin == relVersionMax) {
1632:                                    // Non-ranged dep.
1633:                                    if (relVersionMin != other
1634:                                            .getCodeNameRelease()) {
1635:                                        // Wrong major version, bad.
1636:                                        probs
1637:                                                .add(Union2
1638:                                                        .<Dependency, InvalidException> createFirst(dep));
1639:                                        continue;
1640:                                    }
1641:                                    if (dep.getComparison() == Dependency.COMPARE_IMPL
1642:                                            && !Utilities
1643:                                                    .compareObjects(
1644:                                                            dep.getVersion(),
1645:                                                            other
1646:                                                                    .getImplementationVersion())) { // NOI18N
1647:                                        // Wrong impl version, bad.
1648:                                        probs
1649:                                                .add(Union2
1650:                                                        .<Dependency, InvalidException> createFirst(dep));
1651:                                        continue;
1652:                                    }
1653:                                    if (dep.getComparison() == Dependency.COMPARE_SPEC
1654:                                            && new SpecificationVersion(dep
1655:                                                    .getVersion())
1656:                                                    .compareTo(other
1657:                                                            .getSpecificationVersion()) > 0) {
1658:                                        // Spec version not high enough, bad.
1659:                                        probs
1660:                                                .add(Union2
1661:                                                        .<Dependency, InvalidException> createFirst(dep));
1662:                                        continue;
1663:                                    }
1664:                                } else if (relVersionMin < relVersionMax) {
1665:                                    // Ranged dep.
1666:                                    int otherRel = other.getCodeNameRelease();
1667:                                    if (otherRel < relVersionMin
1668:                                            || otherRel > relVersionMax) {
1669:                                        // Major version outside of range, bad.
1670:                                        probs
1671:                                                .add(Union2
1672:                                                        .<Dependency, InvalidException> createFirst(dep));
1673:                                        continue;
1674:                                    }
1675:                                    if (dep.getComparison() == Dependency.COMPARE_IMPL) {
1676:                                        throw new IllegalStateException(
1677:                                                "No such thing as ranged impl dep"); // NOI18N
1678:                                    }
1679:                                    if (dep.getComparison() == Dependency.COMPARE_SPEC
1680:                                            &&
1681:                                            // Spec comparisons only apply to the earliest major rel.
1682:                                            otherRel == relVersionMin
1683:                                            && new SpecificationVersion(dep
1684:                                                    .getVersion())
1685:                                                    .compareTo(other
1686:                                                            .getSpecificationVersion()) > 0) {
1687:                                        // Spec version not high enough, bad.
1688:                                        probs
1689:                                                .add(Union2
1690:                                                        .<Dependency, InvalidException> createFirst(dep));
1691:                                        continue;
1692:                                    }
1693:                                } else {
1694:                                    throw new IllegalStateException(
1695:                                            "Upside-down rel vers range"); // NOI18N
1696:                                }
1697:                                if (!other.isEnabled()) {
1698:                                    // Need to make sure the other one is not missing anything either.
1699:                                    // Nor that it depends (directly on indirectly) on this one.
1700:                                    if ((!withNeeds && !missingDependencies(
1701:                                            other, false).isEmpty())
1702:                                            || (withNeeds && !isAlmostEmpty(missingDependencies(
1703:                                                    other, true)))) {
1704:                                        // This is a little subtle. Either the other module had real
1705:                                        // problems, in which case our dependency on it is not legit.
1706:                                        // Or, the other actually depends cyclically on this one. In
1707:                                        // that case, *it* would wind up calling missingDependencies
1708:                                        // on this module, but this module has already put a nonempty
1709:                                        // set in the mapping (containing at least the element
1710:                                        // PROBING_IN_PROCESS), causing the other module to fail and
1711:                                        // return a dependency on this module, causing this module to
1712:                                        // also fail with a dependency on that module. In the process,
1713:                                        // both modules get marked permanently bogus (unless you reload
1714:                                        // them both of course).
1715:                                        probs
1716:                                                .add(Union2
1717:                                                        .<Dependency, InvalidException> createFirst(dep));
1718:                                        continue;
1719:                                    }
1720:                                    // If the other module is thought to be OK, assume we can depend
1721:                                    // on it if we need it.
1722:                                }
1723:                                // Already-installed modules are of course fine.
1724:                            } else if (dep.getType() == Dependency.TYPE_REQUIRES
1725:                                    || (withNeeds && dep.getType() == Dependency.TYPE_NEEDS)) {
1726:                                // Works much like a regular module dependency. However it only
1727:                                // fails if there are no satisfying modules with no problems.
1728:                                String token = dep.getName();
1729:                                Set<Module> providers = providersOf.get(token);
1730:                                if (providers == null) {
1731:                                    // Nobody provides it. This dep failed.
1732:                                    probs
1733:                                            .add(Union2
1734:                                                    .<Dependency, InvalidException> createFirst(dep));
1735:                                } else {
1736:                                    // We have some possible providers. Check that at least one is good.
1737:                                    boolean foundOne = false;
1738:                                    for (Module other : providers) {
1739:                                        if (foundOne) {
1740:                                            break;
1741:                                        }
1742:                                        if (other.isEnabled()) {
1743:                                            foundOne = true;
1744:                                        } else {
1745:                                            if ((!withNeeds && missingDependencies(
1746:                                                    other, false).isEmpty())
1747:                                                    || (withNeeds && isAlmostEmpty(missingDependencies(
1748:                                                            other, true)))) {
1749:                                                // See comment above for regular module deps
1750:                                                // re. use of PROBING_IN_PROCESS.
1751:                                                foundOne = true;
1752:                                            }
1753:                                        }
1754:                                    }
1755:                                    if (!foundOne) {
1756:                                        // Nobody can provide it, fail.
1757:                                        probs
1758:                                                .add(Union2
1759:                                                        .<Dependency, InvalidException> createFirst(dep));
1760:                                    }
1761:                                }
1762:                            } else if (dep.getType() == Dependency.TYPE_JAVA) {
1763:                                // Java dependency. Fixed for whole VM session, safe to check once and keep.
1764:                                if (!Util.checkJavaDependency(dep)) {
1765:                                    // Bad.
1766:                                    probs
1767:                                            .add(Union2
1768:                                                    .<Dependency, InvalidException> createFirst(dep));
1769:                                }
1770:                            }
1771:                        }
1772:                        probs.remove(PROBING_IN_PROCESS);
1773:                    }
1774:                    return probs;
1775:                }
1776:            }
1777:
1778:            private static boolean isAlmostEmpty(
1779:                    Set<Union2<Dependency, InvalidException>> probs) {
1780:                return probs.isEmpty()
1781:                        || probs.equals(Collections
1782:                                .singleton(PROBING_IN_PROCESS));
1783:            }
1784:
1785:            /** Forget about any possible "soft" problems there might have been.
1786:             * Next time anyone asks, recompute them.
1787:             * Currently enabled modules are left alone (no problems).
1788:             * Otherwise, any problems which are "hard" (result from failed
1789:             * Java/IDE/package dependencies, runtime errors, etc.) are left alone;
1790:             * "soft" problems of inter-module dependencies are cleared
1791:             * so they will be recomputed next time, and corresponding
1792:             * changes are fired (since the next call to getProblem might
1793:             * return a different result).
1794:             */
1795:            private void clearProblemCache() {
1796:                clearProblemCache(moduleProblemsWithoutNeeds);
1797:                clearProblemCache(moduleProblemsWithNeeds);
1798:            }
1799:
1800:            private void clearProblemCache(
1801:                    Map<Module, Set<Union2<Dependency, InvalidException>>> mP) {
1802:                Iterator<Map.Entry<Module, Set<Union2<Dependency, InvalidException>>>> it = mP
1803:                        .entrySet().iterator();
1804:                while (it.hasNext()) {
1805:                    Map.Entry<Module, Set<Union2<Dependency, InvalidException>>> entry = it
1806:                            .next();
1807:                    Module m = entry.getKey();
1808:                    if (!m.isEnabled()) {
1809:                        Set<Union2<Dependency, InvalidException>> s = entry
1810:                                .getValue();
1811:                        if (s != null) {
1812:                            boolean clear = false;
1813:                            for (Union2<Dependency, InvalidException> problem : s) {
1814:                                if (problem.hasSecond()) {
1815:                                    // Hard problem, skip this one.
1816:                                    continue;
1817:                                }
1818:                                Dependency dep = problem.first();
1819:                                if (dep.getType() != Dependency.TYPE_MODULE
1820:                                        && dep.getType() != Dependency.TYPE_REQUIRES
1821:                                        && dep.getType() != Dependency.TYPE_NEEDS
1822:                                        && dep.getType() != Dependency.TYPE_RECOMMENDS) {
1823:                                    // Also a hard problem.
1824:                                    continue;
1825:                                }
1826:                                // Some soft problems found, i.e. module deps. Clear them all.
1827:                                // #76917: Even clear any hard problems.
1828:                                clear = true;
1829:                                break;
1830:                            }
1831:                            if (clear || s.isEmpty()) { // leave alone only if all hard problems
1832:                                it.remove();
1833:                                firer.change(new ChangeFirer.Change(m,
1834:                                        Module.PROP_PROBLEMS, null, null));
1835:                            }
1836:                        }
1837:                        // if we never computed anything, make no change now
1838:                    }
1839:                    // enabled modules are definitely OK, no change there
1840:                }
1841:            }
1842:
1843:            /** Try to shut down the system.
1844:             * First all modules are asked if they wish to close, in the proper order.
1845:             * Assuming they say yes, then they are informed of the close.
1846:             * Returns true if they all said yes.
1847:             */
1848:            public boolean shutDown() {
1849:                return shutDown(null);
1850:            }
1851:
1852:            /**
1853:             * Try to shut down the system.
1854:             * First all modules are asked if they wish to close, in the proper order.
1855:             * Assuming they say yes, a hook is run, then they are informed of the close.
1856:             * If they did not agree to close, the hook is not run.
1857:             * @param midHook a hook to run before closing modules if they agree to close
1858:             * @return true if they all said yes and the module system is now shut down
1859:             * @since org.netbeans.core/1 1.11
1860:             */
1861:            public boolean shutDown(Runnable midHook) {
1862:                assertWritable();
1863:                Set<Module> unorderedModules = getEnabledModules();
1864:                Map<Module, List<Module>> deps = Util.moduleDependencies(
1865:                        unorderedModules, modulesByName, providersOf);
1866:                List<Module> sortedModules;
1867:                try {
1868:                    sortedModules = Utilities.topologicalSort(unorderedModules,
1869:                            deps);
1870:                } catch (TopologicalSortException ex) {
1871:                    // Once again, weird situation.
1872:                    if (PRINT_TOPOLOGICAL_EXCEPTION_STACK_TRACES) {
1873:                        Util.err.log(Level.WARNING, null, ex);
1874:                    }
1875:                    Util.err
1876:                            .warning("Cyclic module dependencies, will not shut down cleanly: "
1877:                                    + deps); // NOI18N
1878:                    return true;
1879:                }
1880:                if (!installer.closing(sortedModules)) {
1881:                    return false;
1882:                }
1883:                if (midHook != null) {
1884:                    try {
1885:                        midHook.run();
1886:                    } catch (RuntimeException e) {
1887:                        Util.err.log(Level.WARNING, null, e);
1888:                    } catch (LinkageError e) {
1889:                        Util.err.log(Level.WARNING, null, e);
1890:                    }
1891:                }
1892:                installer.close(sortedModules);
1893:                return true;
1894:            }
1895:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.