alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.core.ui;

import java.awt.Component;
import org.netbeans.core.NbTopManager;
import org.netbeans.core.modules.*;
import java.util.*;
import javax.swing.SwingUtilities;
import org.openide.modules.SpecificationVersion;
import java.io.File;
import java.beans.*;
import org.openide.*;
import java.io.IOException;
import org.openide.util.*;

/** Bean representing a module.
 * Mirrors its properties but provides safe access from the event thread.
 * Also permits delayed write access, again safe to initiate from the event thread.
 * These changes are batched and auto-validating.
 * @author Jesse Glick
 */
public final class ModuleBean implements Runnable, PropertyChangeListener {
    
    private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.core.ui.ModuleBean"); // NOI18N
    
    private final Module module;
    
    private String codeName;
    private String codeNameBase;
    private String specVers;
    private String implVers;
    private String buildVers;
    private String[] provides;
    private File jar;
    private boolean enabled;
    private boolean reloadable;
    private boolean autoload;
    private boolean eager;
    private boolean problematic;
    private String[] problemDescriptions;
    private String displayName;
    private String shortDescription;
    private String longDescription;
    private String category;
    private String classpath;
    
    /** Must be created within mutex. */
    private ModuleBean(Module m) {
        module = m;
        loadProps();
        module.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange (this, module));
    }
    
    /** If necessary, get the underlying module. */
    public Module getModule() {
        return module;
    }
    
    private void loadProps() {
        if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
        err.log("loadProps: module=" + module);
        if (! module.isValid()) {
            err.log("invalid, forget it...");
            return;
        }
        // Set fields. Called inside read mutex.
        codeName = module.getCodeName();
        codeNameBase = module.getCodeNameBase();
        SpecificationVersion sv = module.getSpecificationVersion();
        specVers = (sv == null ? null : sv.toString());
        implVers = module.getImplementationVersion ();
        buildVers = module.getBuildVersion ();
        provides = module.getProvides();
        jar = module.getJarFile();
        enabled = module.isEnabled();
        reloadable = module.isReloadable();
        autoload = module.isAutoload();
        eager = module.isEager();
        Set problems = module.getProblems();
        problematic = !problems.isEmpty();
        if (problematic) {
            problemDescriptions = new String[problems.size()];
            Iterator it = problems.iterator();
            int i = 0;
            while (it.hasNext()) {
                problemDescriptions[i++] = NbProblemDisplayer.messageForProblem(module, it.next());
            }
        } else {
            problemDescriptions = null;
        }
        displayName = module.getDisplayName();
        shortDescription = (String)module.getLocalizedAttribute("OpenIDE-Module-Short-Description"); // NOI18N
        longDescription = (String)module.getLocalizedAttribute("OpenIDE-Module-Long-Description"); // NOI18N
        category = (String)module.getLocalizedAttribute("OpenIDE-Module-Display-Category"); // NOI18N
        classpath = NbTopManager.getUninitialized().getModuleSystem().getEffectiveClasspath(module);
    }
    
    /** Get the code name. */
    public String getCodeName() {
        return codeName;
    }
    
    /** Get the code name base. */
    public String getCodeNameBase() {
        return codeNameBase;
    }
    
    /** Get the specification version, or null. */
    public String getSpecificationVersion() {
        return specVers;
    }
    
    /** Get the implementation version, or null. */
    public String getImplementationVersion() {
        return implVers;
    }
    
    /** Get the build version, or null. */
    public String getBuildVersion() {
        return buildVers;
    }
    
    /** Get a list of provided tokens (never null, maybe empty). */
    public String[] getProvides() {
        return provides;
    }
    
    /** Get the module JAR file, or null. */
    public File getJar() {
        return jar;
    }
    
    /** Test whether the module is enabled. */
    public boolean isEnabled() {
        return enabled;
    }
    
    /** Enable/disable the module. */
    public void setEnabled(boolean e) {
        if (enabled == e) return;
        if (jar == null || autoload || eager || problematic) throw new IllegalStateException();
        err.log("setEnabled: module=" + module + " enabled=" + e);
        enabled = e; // optimistic change
        supp.firePropertyChange("enabled", null, null); // NOI18N
        Update u = new Update(e ? "enable" : "disable", module); // NOI18N
        AllModulesBean.getDefault().update(u);
    }
    
    /** Test whether the module is a library module. */
    public boolean isAutoload() {
        return autoload;
    }
    
    /** Test whether the module is a bridge module. */
    public boolean isEager() {
        return eager;
    }
    
    /** Test whether the module is reloadable. */
    public boolean isReloadable() {
        return reloadable;
    }
    
    /** Set whether the module is reloadable. */
    public void setReloadable(boolean r) {
        // XXX sanity-check
        if (reloadable == r) return;
        err.log("setReloadable: module=" + module + " reloadable=" + r);
        reloadable = r; // optimistic change
        supp.firePropertyChange("reloadable", null, null); // NOI18N
        Update u = new Update(r ? "makeReloadable" : "makeUnreloadable", module); // NOI18N
        AllModulesBean.getDefault().update(u);
    }
    
    /** Delete the module. */
    public void delete() {
        if (jar == null) throw new IllegalStateException();
        err.log("delete: module=" + module);
        Update u = new Update("delete", module); // NOI18N
        AllModulesBean.getDefault().update(u);
    }
    
    /** Test whether the module has problems with installation. */
    public boolean isProblematic() {
        return problematic;
    }
    
    /**
     * Get a list of descriptions of each problem in the module (if it has any).
     * Each item will be a localized phrase.
     * @return a nonempty array of explanations if {@link #isProblematic}, null otherwise
     * @see NbProblemDisplayer#messageForProblem
     * @see "#16636"
     */
    public String[] getProblemDescriptions() {
        return problemDescriptions;
    }
    
    /** Get the display name. */
    public String getDisplayName() {
        return displayName;
    }
    
    /** Get the short description, or null. */
    public String getShortDescription() {
        return shortDescription;
    }
    
    /** Get the long description, or null. */
    public String getLongDescription() {
        return longDescription;
    }
    
    /** Get the display category, or null. */
    public String getCategory() {
        return category;
    }
    
    /** Get the effective classpath for this module.
     * May be the empty string for a disabled module.
     * @see ModuleSystem#getEffectiveClasspath
     * @see "#22466"
     */
    public String getEffectiveClasspath() {
        return classpath;
    }
    
    private final PropertyChangeSupport supp = new PropertyChangeSupport(this);
    
    /** Listen to changes in bean properties. */
    public void addPropertyChangeListener(PropertyChangeListener l) {
        supp.removePropertyChangeListener(l);
        supp.addPropertyChangeListener(l);
    }
    
    /** Stop listening to changes in bean properties. */
    public void removePropertyChangeListener(PropertyChangeListener l) {
        supp.removePropertyChangeListener(l);
    }
    
    public void propertyChange(PropertyChangeEvent evt) {
        if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
        // Something on the module changed. Inside read mutex.
        err.log("got changes: module=" + module + " evt=" + evt);
        if (/* #13834 */ evt != null && Module.PROP_CLASS_LOADER.equals(evt.getPropertyName())) {
            err.log("ignoring PROP_CLASS_LOADER");
            // Speed optimization.
            return;
        }
        loadProps();
        SwingUtilities.invokeLater(this);
    }
    
    public void run() {
        if (! SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
        // Inside event thread after a change.
        err.log("firing changes: module=" + module);
        supp.firePropertyChange(null, null, null);
    }
    
    // ModuleNode uses these as keys, so make sure even if recreated after change
    // in list of modules that the node selection is retained. Cf. #23757 however:
    
    public boolean equals(Object o) {
        return (o instanceof ModuleBean) &&
            codeNameBase.equals(((ModuleBean)o).codeNameBase);
    }
    
    public int hashCode() {
        return 35632846 ^ codeNameBase.hashCode();
    }
    
    public String toString() {
        return "ModuleBean[" + codeNameBase + "]"; // NOI8N
    }
    
    public static final class AllModulesBean implements Runnable, PropertyChangeListener, Comparator {
        
        private static AllModulesBean deflt = null;
        /** Get the bean representing all modules. */
        public static synchronized AllModulesBean getDefault() {
            if (deflt == null) deflt = new AllModulesBean();
            return deflt;
        }
        private AllModulesBean() {}
        
        private final ModuleManager mgr = NbTopManager.getUninitialized().getModuleSystem().getManager();
        private final Events ev = NbTopManager.getUninitialized().getModuleSystem().getEvents();
        
        private final PropertyChangeSupport supp = new PropertyChangeSupport(this);
        
        /** Listen to changes in the list of modules or whether there are pending updates. */
        public void addPropertyChangeListener(PropertyChangeListener l) {
            supp.removePropertyChangeListener(l);
            supp.addPropertyChangeListener(l);
        }
        
        /** Stop listening to changes in the list of modules and whether there are pending updates. */
        public void removePropertyChangeListener(PropertyChangeListener l) {
            supp.removePropertyChangeListener(l);
        }
        
        private ModuleBean[] modules = null;
        
        private Task recalcTask = null;
        
        /** Get the list of all modules. */
        public synchronized ModuleBean[] getModules() {
            err.log("getModules: modules count=" + (modules == null ? "null" : String.valueOf(modules.length)));
            if (modules == null) {
                recalcTask = RequestProcessor.getDefault().post(new Reader());
                modules = new ModuleBean[0];
                return modules;
            } else {
                return modules/*.clone()*/;
            }
        }
        
        /** Get a task representing the need to get all modules.
         * When it is finished (if it is not already), they will be ready.
         * It is not guaranteed that changes will have been fired to
         * listeners by the time this task finishes.
         */
        public synchronized Task waitForModules() {
            getModules();
            if (recalcTask != null) {
                return recalcTask;
            } else {
                return Task.EMPTY;
            }
        }
        
        /** Create a new module from JAR file, perhaps reloadable. */
        public void create(File jar, boolean reloadable) {
            err.log("create: jar=" + jar);
            Update u = new Update(reloadable ? "createReloadable" : "create", jar); // NOI18N
            update(u);
        }
        
        private class Reader implements Runnable {
            private boolean theother = false;
            Reader() {}
            /** Called first in request processor, then pushed to read mutex,
             * to read list of modules.
             */
            public void run() {
                if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
                if (! theother) {
                    err.log("will load modules in read mutex...");
                    Reader r = new Reader();
                    r.theother = true;
                    mgr.mutex().readAccess(r);
                    return;
                }
                err.log("first time, finding module list");
                // First time. We are in read mutex and need to find out what is here.
                Set modulesSet = mgr.getModules();
                ModuleBean[] _modules = new ModuleBean[modulesSet.size()];
                Iterator it = modulesSet.iterator();
                int i = 0;
                while (it.hasNext()) {
                    Module m = (Module)it.next();
                    _modules[i++] = new ModuleBean(m);
                }
                synchronized (AllModulesBean.this) {
                    modules = _modules;
                    recalcTask = null;
                }
                // Listen for further changes.
                mgr.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(AllModulesBean.this, mgr));
                // Relative to the initial list of zero modules, something 'has changed'.
                SwingUtilities.invokeLater(AllModulesBean.this);
            }
        }
        
        public void run() {
            if (! SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
            err.log("in event thread, will fire changes");
            // Something changed and now we are in the event thread.
            // (Either list of modules or pending changes or both.)
            supp.firePropertyChange(null, null, null);
        }
        
        public void propertyChange(PropertyChangeEvent evt) {
            if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
            err.log("got changes: evt=" + evt);
            if (ModuleManager.PROP_MODULES.equals(evt.getPropertyName())) {
                // Later on. Something changed. Again in read mutex.
                Map modules2Beans = new HashMap(modules.length * 4 / 3 + 1);
                for (int i = 0; i < modules.length; i++) {
                    modules2Beans.put(modules[i].getModule(), modules[i]);
                }
                Set modulesSet = mgr.getModules();
                ModuleBean[] themodules = new ModuleBean[modulesSet.size()];
                Iterator it = modulesSet.iterator();
                int i = 0;
                while (it.hasNext()) {
                    Module m = (Module)it.next();
                    ModuleBean existing = (ModuleBean)modules2Beans.get(m);
                    if (existing == null) existing = new ModuleBean(m);
                    themodules[i++] = existing;
                }
                synchronized (this) {
                    modules = themodules;
                }
                // Fire changes later.
                SwingUtilities.invokeLater(this);
            }
        }
        
        private final List updates = new LinkedList(); // List
        
        private boolean paused = false;
        
        private Runnable updater = new Updater();
        
        /** Pause any pending updates for later. */
        public void pause() {
            err.log("pause");
            paused = true;
        }
        
        /** Resume any previously paused updates. */
        public void resume() {
            err.log("resume");
            paused = false;
            RequestProcessor.getDefault().post(updater);
        }
        
        /** Cancel any previously posted updates (whether paused or not). */
        public void cancel() {
            err.log("cancel");
            synchronized (updates) {
                updates.clear();
            }
            paused = false;
            supp.firePropertyChange("pending", null, null); // NOI18N
        }
        
        /** Test whether there are any pending updates (whether paused or not). */
        public boolean isPending() {
            synchronized (updates) {
                return ! updates.isEmpty();
            }
        }
        
        /** Called from event thread.
         * Access only from within this class or from ModuleBean.
         */
        void update(Update u) {
            synchronized (updates) {
                // If nonempty, we are already waiting for it...
                boolean runme = updates.isEmpty();
                updates.add(u);
                err.log("pending updates: " + updates);
                if (runme) {
                    RequestProcessor.getDefault().post(updater);
                }
            }
            supp.firePropertyChange("pending", null, null); // NOI18N
        }
        
        private class Updater implements Runnable {
            private boolean theother = false;
            Updater() {}
            /** Called from request processor to actually perform updates.
             * Or from the write mutex if theother is set.
             */
            public void run() {
                if (SwingUtilities.isEventDispatchThread()) throw new IllegalStateException();
                if (! theother) {
                    err.log("saving all documents...");
                    org.openide.LifecycleManager.getDefault ().saveAll ();
                    err.log("will run updates in write mutex...");
                    Updater u = new Updater();
                    u.theother = true;
                    mgr.mutex().writeAccess(u);
                    return;
                }
                try {
                    if (paused) {
                        err.log("run updates, but paused");
                        return;
                    }
                    Set toEnable = new HashSet(); // Set
                    Set toDisable = new HashSet(); // Set
                    Set toMakeReloadable = new HashSet(); // Set
                    Set toMakeUnreloadable = new HashSet(); // Set
                    Set toDelete = new HashSet(); // Set
                    Set toCreate = new HashSet(); // Set
                    Set toCreateReloable = new HashSet(); // Set
                    Iterator it;
                    synchronized (updates) {
                        if (updates.isEmpty()) {
                            err.log("run updates, but empty");
                            return;
                        }
                        err.log("run updates: " + updates);
                        it = new LinkedList(updates).iterator();
                        updates.clear();
                    }
                    while (it.hasNext()) {
                        Update u = (Update)it.next();
                        if (u.command.equals("enable")) { // NOI18N
                            if (toDelete.contains(u.arg)) throw new IllegalStateException();
                            toDisable.remove(u.arg);
                            toEnable.add(u.arg);
                        } else if (u.command.equals("disable")) { // NOI18N
                            if (toDelete.contains(u.arg)) throw new IllegalStateException();
                            toEnable.remove(u.arg);
                            toDisable.add(u.arg);
                        } else if (u.command.equals("makeReloadable")) { // NOI18N
                            if (toDelete.contains(u.arg)) throw new IllegalStateException();
                            toMakeUnreloadable.remove(u.arg);
                            toMakeReloadable.add(u.arg);
                        } else if (u.command.equals("makeUnreloadable")) { // NOI18N
                            if (toDelete.contains(u.arg)) throw new IllegalStateException();
                            toMakeReloadable.remove(u.arg);
                            toMakeUnreloadable.add(u.arg);
                        } else if (u.command.equals("delete")) { // NOI18N
                            toEnable.remove(u.arg);
                            toDisable.remove(u.arg); // will always be disabled anyway
                            toMakeReloadable.remove(u.arg);
                            toMakeUnreloadable.remove(u.arg);
                            toDelete.add(u.arg);
                        } else if (u.command.equals("create")) { // NOI18N
                            toCreateReloable.remove(u.arg);
                            toCreate.add(u.arg);
                        } else if (u.command.equals("createReloadable")) { // NOI18N
                            toCreate.remove(u.arg);
                            toCreateReloable.add(u.arg);
                        } else {
                            throw new IllegalStateException();
                        }
                    }
                    doDelete(toDelete);
                    doDisable(toDisable);
                    it = toMakeReloadable.iterator();
                    while (it.hasNext()) {
                        Module m = (Module)it.next();
                        m.setReloadable(true);
                    }
                    it = toMakeUnreloadable.iterator();
                    while (it.hasNext()) {
                        Module m = (Module)it.next();
                        m.setReloadable(false);
                    }
                    doEnable(toEnable);
                    doCreate(toCreate, false);
                    doCreate(toCreateReloable, true);
                } catch (RuntimeException re) {
                    err.notify(re);
                    // Never know. Revert everything to real state just in case.
                    // #17873: if not inited, no need...
                    ModuleBean[] _modules = modules;
                    if (_modules != null) {
                        for (int i = 0; i < _modules.length; i++) {
                            _modules[i].propertyChange(null);
                        }
                    }
                }
                // Fire a change in pending property.
                SwingUtilities.invokeLater(AllModulesBean.this);
            }
            
        }
        
        // Actual command to do certain kinds of updates, called within
        // write mutex and should take care of their own UI. Note that it
        // is OK to block on the event thread here indirectly, by means of
        // calling TopManager.notify and waiting for the result.
        
        private void doDelete(Set modules) {
            if (modules.isEmpty()) return;
            err.log("doDelete: " + modules);
            // Have to be turned off first:
            doDisable(modules);
            Iterator it = modules.iterator();
            while (it.hasNext()) {
                Module m = (Module)it.next();
                if (m.isFixed()) {
                    // Hmm, ignore.
                    continue;
                }
                mgr.delete(m);
            }
        }
        
        public int compare(Object o1, Object o2) {
            Module m1 = (Module)o1;
            Module m2 = (Module)o2;
            int i = m1.getDisplayName().compareTo(m2.getDisplayName());
            if (i != 0) {
                return i;
            } else {
                return m1.getCodeNameBase().compareTo(m2.getCodeNameBase());
            }
        }

        private void doDisable(Set modules) {
            if (modules.isEmpty()) return;
            err.log("doDisable: " + modules);
            SortedSet realModules = new TreeSet(this); // SortedSet
            realModules.addAll(modules);
            Iterator it = realModules.iterator();
            while (it.hasNext()) {
                Module m = (Module)it.next();
                if (!m.isEnabled() || m.isAutoload() || m.isEager() || m.isFixed()) {
                    // In here by mistake, ignore.
                    it.remove();
                }
            }
            List toDisable = mgr.simulateDisable(realModules);
            // Check if there are any non-autoloads/eagers added.
            it = toDisable.iterator();
            SortedSet others = new TreeSet(this); // SortedSet
            while (it.hasNext()) {
                Module m = (Module)it.next();
                if (!m.isAutoload() && !m.isEager() && !realModules.contains(m)) {
                    others.add(m);
                }
            }
            if (! others.isEmpty()) {
                Component c = new ModuleEnableDisablePanel(false,
                    (Module[])realModules.toArray(new Module[realModules.size()]),
                    (Module[])others.toArray(new Module[others.size()]));
                NotifyDescriptor d = new NotifyDescriptor.Confirmation(c,
                    NbBundle.getMessage(ModuleBean.class, "MB_TITLE_disabling"),
                    NotifyDescriptor.OK_CANCEL_OPTION);
                if (org.openide.DialogDisplayer.getDefault().notify(d) != NotifyDescriptor.OK_OPTION) {
                    // User refused.
                    // Fire changes again since modules are now wrong & need recalc.
                    ModuleBean[] _modules = this.modules;
                    if (_modules != null) {
                        for (int i = 0; i < _modules.length; i++) {
                            if (realModules.contains(_modules[i].module)) {
                                _modules[i].propertyChange(null);
                            }
                        }
                    }
                    return;
                }
                realModules.addAll(others);
            }
            // Ready to go.
            mgr.disable(realModules);
        }
        
        private void doEnable(Set modules) {
            if (modules.isEmpty()) return;
            err.log("doEnable: " + modules);
            SortedSet realModules = new TreeSet(this); // SortedSet
            realModules.addAll(modules);
            Iterator it = realModules.iterator();
            while (it.hasNext()) {
                Module m = (Module)it.next();
                if (m.isEnabled() || m.isAutoload() || m.isEager() || m.isFixed() || ! m.getProblems().isEmpty()) {
                    // In here by mistake, ignore.
                    it.remove();
                }
            }
            List toEnable = mgr.simulateEnable(realModules);
            // Check if there are any non-autoloads/eagers added.
            it = toEnable.iterator();
            SortedSet others = new TreeSet(this); // SortedSet
            while (it.hasNext()) {
                Module m = (Module)it.next();
                if (!m.isAutoload() && !m.isEager() && !realModules.contains(m)) {
                    others.add(m);
                }
            }
            if (! others.isEmpty()) {
                Component c = new ModuleEnableDisablePanel(true,
                    (Module[])realModules.toArray(new Module[realModules.size()]),
                    (Module[])others.toArray(new Module[others.size()]));
                NotifyDescriptor d = new NotifyDescriptor.Confirmation(c,
                    NbBundle.getMessage(ModuleBean.class, "MB_TITLE_enabling"),
                    NotifyDescriptor.OK_CANCEL_OPTION);
                if (org.openide.DialogDisplayer.getDefault().notify(d) != NotifyDescriptor.OK_OPTION) {
                    // User refused.
                    // Fire changes again since modules are now wrong & need recalc.
                    ModuleBean[] _modules = this.modules;
                    if (_modules != null) {
                        for (int i = 0; i < _modules.length; i++) {
                            if (realModules.contains(_modules[i].module)) {
                                _modules[i].propertyChange(null);
                            }
                        }
                    }
                    return;
                }
                realModules.addAll(others);
            }
            // Ready to go. First reload any test modules.
            it = toEnable.iterator();
            while (it.hasNext()) {
                Module m = (Module)it.next();
                if (m.isReloadable()) {
                    try {
                        mgr.reload(m);
                    } catch (IOException ioe) {
                        ErrorManager.getDefault().notify(ioe);
                        // Refresh all.
                        ModuleBean[] _modules = this.modules;
                        if (_modules != null) {
                            for (int i = 0; i < _modules.length; i++) {
                                if (realModules.contains(_modules[i].module)) {
                                    _modules[i].propertyChange(null);
                                }
                            }
                        }
                        return;
                    }
                }
            }
            try {
                mgr.enable(realModules);
            } catch (InvalidException ie) {
                err.notify(ErrorManager.INFORMATIONAL, ie);
                Module bad = ie.getModule();
                if (bad == null) throw new IllegalStateException();
                ev.log(Events.FAILED_INSTALL_NEW_UNEXPECTED, bad, ie);
                // Refresh it.
                ModuleBean[] _modules = this.modules;
                if (_modules != null) {
                    for (int i = 0; i < _modules.length; i++) {
                        if (_modules[i].module == bad) {
                            _modules[i].propertyChange(null);
                        }
                    }
                }
                // Try to enable a subset this time.
                realModules.remove(ie.getModule());
                doEnable(realModules);
            }
        }
        
        private void doCreate(Set files, boolean reloadable) {
            if (files.isEmpty()) return;
            err.log("doCreate: " + files + " reloadable=" + reloadable);
            Iterator it = files.iterator();
            while (it.hasNext()) {
                File jar = (File)it.next();
                Module nue;
                try {
                    nue = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), reloadable, false, false);
                } catch (IOException ioe) {
                    ErrorManager.getDefault().notify(ErrorManager.USER, ioe);
                    continue;
                } catch (DuplicateException dupe) {
                    // Replace the old one.
                    Module old = dupe.getOldModule();
                    if (old.isFixed()) {
                        // Cannot replace it.
                        continue;
                    }
                    if (old.isEnabled()) {
                        // Need to turn it off first.
                        if (old.isAutoload() || old.isEager()) {
                            // Hmm, too complicated to deal with now. Skip it.
                            continue;
                        }
                        doDisable(Collections.singleton(old));
                        if (old.isEnabled()) {
                            // Did not work for some reason, skip it.
                            continue;
                        }
                    }
                    mgr.delete(old);
                    try {
                        nue = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), reloadable, false, false);
                    } catch (IOException ioe) {
                        ErrorManager.getDefault().notify(ErrorManager.USER, ioe);
                        continue;
                    } catch (DuplicateException dupe2) {
                        // Huh??
                        ErrorManager.getDefault().notify(dupe2);
                        continue;
                    }
                }
                // Now turn it on.
                if (nue.getProblems().isEmpty()) {
                    doEnable(Collections.singleton(nue));
                    // If it did not work, just leave it there disabled, user
                    // can delete if desired.
                } else {
                    // Cannot install, make sure user knows about it!
                    ev.log(Events.FAILED_INSTALL_NEW, Collections.singleton(nue));
                }
            }
        }
        
        // Inter-module dependencies; see #22504.
        // Cumbersome to do with the property + change model used for simple
        // properties of modules, because these properties may be expensive
        // to compute and might never be needed. It is also harder to know for
        // sure when they might have changed.

        /**
         * Modules directly needed by this module.
         */
        public static final int RELATION_DIRECTLY_NEEDS = 0;
        /**
         * All modules needed by this module.
         */
        public static final int RELATION_TRANSITIVELY_NEEDS = 1;
        /**
         * Modules which directly need this module.
         */
        public static final int RELATION_DIRECTLY_NEEDED_BY = 2;
        /**
         * All modules which need this module.
         */
        public static final int RELATION_TRANSITIVELY_NEEDED_BY = 3;
        
        /** A callback used to supply the result of a relationship computation
         * asynchronously.
         */
        public interface RelationCallback {
            /** Called when a computation is done.
             * @param modules a set of {@link ModuleBean} instances
             */
            void result(Set modules);
        }
        
        /**
         * Compute the relations of other modules to this one.
         * 

Provide-require dependencies are treated just like direct dependencies, * where there is in fact a provider for a requirement. Note that this could * lead to slightly misleading results in some cases: for example, consider * if A (enabled) requires X, and B (enabled) and C (enabled) both provide X. * A's reported dependency list will include both B and C, despite the fact * that it is possible to disable either one by itself without disabling A. *

This computation is done asynchronously. Call this method * from the event thread; the callback will be called later * from the event thread. * @param mb the module to start with * @param type one of the RELATION_* constants * @param callback will be called when the computation is done */ public void getRelations(ModuleBean mb, int type, RelationCallback callback) { if (type != RELATION_DIRECTLY_NEEDS && type != RELATION_TRANSITIVELY_NEEDS && type != RELATION_DIRECTLY_NEEDED_BY && type != RELATION_TRANSITIVELY_NEEDED_BY) { throw new IllegalArgumentException("bad type: " + type); // NOI18N } RequestProcessor.getDefault().post(new RelationComputer(mb.module, type, callback)); } private class RelationComputer implements Runnable { private int stage; private final Module m; private final int type; private final RelationCallback callback; private Set result; // Set public RelationComputer(Module m, int type, RelationCallback callback) { this.stage = 0; this.m = m; this.type = type; this.callback = callback; } public void run() { switch (stage) { case 0: stage = 1; mgr.mutex().readAccess(this); break; case 1: compute(); stage = 2; SwingUtilities.invokeLater(this); break; default: // Convert Module -> ModuleBean and return it. Set mbresult = new HashSet(result.size() * 2 + 1); // Set ModuleBean[] _modules = getModules(); for (int i = 0; i < _modules.length; i++) { if (result.contains(_modules[i].module)) { mbresult.add(_modules[i]); } } callback.result(mbresult); break; } } /** Called from within module system read mutex. * Should do the calculations and store them. */ private void compute() { switch (type) { case RELATION_DIRECTLY_NEEDS: result = mgr.getModuleInterdependencies(m, false, false); break; case RELATION_DIRECTLY_NEEDED_BY: result = mgr.getModuleInterdependencies(m, true, false); break; case RELATION_TRANSITIVELY_NEEDS: result = mgr.getModuleInterdependencies(m, false, true); break; case RELATION_TRANSITIVELY_NEEDED_BY: result = mgr.getModuleInterdependencies(m, true, true); break; default: assert false : type; } } } } /** One update to run. */ private static final class Update { public final String command; public final Object arg; public Update(String command, Object arg) { this.command = command; this.arg = arg; } public boolean equals(Object o) { if (! (o instanceof Update)) return false; Update u = (Update)o; return command.equals(u.command) && arg.equals(u.arg); } public int hashCode() { return command.hashCode() ^ arg.hashCode(); } public String toString() { return "Update[" + command + "," + arg + "]"; // NOI18N } } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.