# HG changeset patch # Parent f34acce4ef90a133d298fc0da5aef3f5b7348e4e Issue #157828: new client method ModuleInfo.forClass avoids linear search. diff --git a/core.osgi/src/org/netbeans/core/osgi/OSGiMainLookup.java b/core.osgi/src/org/netbeans/core/osgi/OSGiMainLookup.java --- a/core.osgi/src/org/netbeans/core/osgi/OSGiMainLookup.java +++ b/core.osgi/src/org/netbeans/core/osgi/OSGiMainLookup.java @@ -131,7 +131,7 @@ private void postInit() { nonClassLoaderDelegates.add(Lookups.fixed(OSGiRepository.DEFAULT, new OSGiLifecycleManager(context), new OSGiInstalledFileLocator(context))); nonClassLoaderDelegates.add(new AbstractLookup(moduleInfoContent)); - // XXX InstalledFileLocator impl for OSGI-INF/files/* + // XXX should add a org.openide.modules.Modules setClassLoader(); } diff --git a/core.startup/src/org/netbeans/core/startup/preferences/PreferencesProviderImpl.java b/core.startup/src/org/netbeans/core/startup/preferences/PreferencesProviderImpl.java --- a/core.startup/src/org/netbeans/core/startup/preferences/PreferencesProviderImpl.java +++ b/core.startup/src/org/netbeans/core/startup/preferences/PreferencesProviderImpl.java @@ -45,7 +45,8 @@ package org.netbeans.core.startup.preferences; import java.util.prefs.Preferences; -import org.netbeans.Util; +import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.util.lookup.ServiceProvider; /** @@ -53,15 +54,11 @@ */ @ServiceProvider(service=org.openide.util.NbPreferences.Provider.class) public class PreferencesProviderImpl implements org.openide.util.NbPreferences.Provider { - /** Creates a new instance of PreferencesProviderImpl */ - public PreferencesProviderImpl() { - } - public Preferences preferencesForModule(Class cls) { String absolutePath = null; - ClassLoader cl = cls.getClassLoader(); - if (cl instanceof Util.ModuleProvider) { - absolutePath = ((Util.ModuleProvider) cl).getModule().getCodeNameBase(); + ModuleInfo owner = Modules.getDefault().ownerOf(cls); + if (owner != null) { + absolutePath = owner.getCodeNameBase(); } else { absolutePath = cls.getName().replaceFirst("(^|\\.)[^.]+$", "");//NOI18N } diff --git a/o.n.bootstrap/src/org/netbeans/Module.java b/o.n.bootstrap/src/org/netbeans/Module.java --- a/o.n.bootstrap/src/org/netbeans/Module.java +++ b/o.n.bootstrap/src/org/netbeans/Module.java @@ -259,8 +259,7 @@ return specVers; } - @Override - public boolean owns(Class clazz) { + public @Override boolean owns(Class clazz) { ClassLoader cl = clazz.getClassLoader(); if (cl instanceof Util.ModuleProvider) { return ((Util.ModuleProvider) cl).getModule() == this; @@ -268,6 +267,14 @@ if (cl != classloader) { return false; } + String _codeName = findClasspathModuleCodeName(clazz); + if (_codeName != null) { + return _codeName.equals(codeName); + } + return true; // not sure... + } + + static String findClasspathModuleCodeName(Class clazz) { // #157798: in JNLP or otherwise classpath mode, all modules share a CL. CodeSource src = clazz.getProtectionDomain().getCodeSource(); if (src != null) { @@ -280,8 +287,7 @@ URL manifest = new URL(loc, "META-INF/MANIFEST.MF"); InputStream is = manifest.openStream(); try { - Manifest mf = new Manifest(is); - return codeName.equals(mf.getMainAttributes().getValue("OpenIDE-Module")); + return new Manifest(is).getMainAttributes().getValue("OpenIDE-Module"); } finally { is.close(); } @@ -289,7 +295,7 @@ Logger.getLogger(Module.class.getName()).log(Level.FINE, null, x); } } - return true; // not sure... + return null; } /** Get all packages exported by this module to other modules. diff --git a/o.n.bootstrap/src/org/netbeans/ModuleManager.java b/o.n.bootstrap/src/org/netbeans/ModuleManager.java --- a/o.n.bootstrap/src/org/netbeans/ModuleManager.java +++ b/o.n.bootstrap/src/org/netbeans/ModuleManager.java @@ -70,18 +70,21 @@ import org.openide.LifecycleManager; import org.openide.modules.Dependency; import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.modules.SpecificationVersion; import org.openide.util.Lookup; import org.openide.util.Mutex; import org.openide.util.TopologicalSortException; import org.openide.util.Union2; import org.openide.util.Utilities; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ProxyLookup; /** Manages a collection of modules. * Must use {@link #mutex} to access its important methods. * @author Jesse Glick */ -public final class ModuleManager { +public final class ModuleManager extends Modules { public static final String PROP_MODULES = "modules"; // NOI18N public static final String PROP_ENABLED_MODULES = "enabledModules"; // NOI18N @@ -272,6 +275,7 @@ } private final Util.ModuleLookup lookup = new Util.ModuleLookup(); + private final Lookup completeLookup = new ProxyLookup(Lookups.fixed(this), lookup); /** Retrieve set of modules in Lookup form. * The core top manager should install this into the set of * available lookups. Will fire lookup events when the @@ -281,7 +285,7 @@ * straight to this lookup when ModuleInfo/Module is requested. */ public Lookup getModuleLookup() { - return lookup; + return completeLookup; } // Access from ChangeFirer: final void fireModulesCreatedDeleted(Set created, Set deleted) { @@ -320,6 +324,18 @@ return modulesByName.get(codeNameBase); } + public @Override ModuleInfo ownerOf(Class clazz) { + ClassLoader cl = clazz.getClassLoader(); + if (cl instanceof Util.ModuleProvider) { + return ((Util.ModuleProvider) cl).getModule(); + } + String codename = Module.findClasspathModuleCodeName(clazz); + if (codename != null) { + return get(codename.replaceFirst("/\\d+$", "")); // NOI18N + } + return null; + } + /** * Get a set of modules depended upon or depending on this module. *

Note that provide-require/need dependencies are listed alongside direct diff --git a/o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java b/o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java --- a/o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java +++ b/o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java @@ -77,6 +77,7 @@ import org.netbeans.junit.RandomlyFails; import org.openide.modules.Dependency; import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.util.Lookup; import org.openide.util.LookupEvent; import org.openide.util.LookupListener; @@ -2532,6 +2533,8 @@ TestFileUtils.writeFile(new File(data, "mod2/pkg/C3.java"), "package pkg; class C3 {}"); File mod2JAR = createTestJAR(data, jars, "mod2", null); ModuleManager mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents()); + Modules modules = mgr.getModuleLookup().lookup(Modules.class); + assertNotNull(modules); mgr.mutexPrivileged().enterWriteAccess(); try { Module mod1 = mgr.create(mod1JAR, null, false, false, false); @@ -2547,10 +2550,16 @@ assertFalse(mod2.owns(c1)); assertFalse(mod2.owns(c2)); assertTrue(mod2.owns(c3)); + assertEquals(mod1, modules.ownerOf(c1)); + assertEquals(mod1, modules.ownerOf(c2)); + assertEquals(mod2, modules.ownerOf(c3)); + assertNull(modules.ownerOf(String.class)); } finally { mgr.mutexPrivileged().exitWriteAccess(); } mgr = new ModuleManager(new MockModuleInstaller(), new MockEvents()); + modules = mgr.getModuleLookup().lookup(Modules.class); + assertNotNull(modules); mgr.mutexPrivileged().enterWriteAccess(); try { ClassLoader l = new URLClassLoader(new URL[] {mod1JAR.toURI().toURL(), mod2JAR.toURI().toURL()}); @@ -2569,6 +2578,10 @@ assertFalse(mod2.owns(c1)); assertFalse(mod2.owns(c2)); assertTrue(mod2.owns(c3)); + assertEquals(mod1, modules.ownerOf(c1)); + assertEquals(mod1, modules.ownerOf(c2)); + assertEquals(mod2, modules.ownerOf(c3)); + assertNull(modules.ownerOf(String.class)); } finally { mgr.mutexPrivileged().exitWriteAccess(); } diff --git a/o.n.core/src/org/netbeans/core/NbLoaderPool.java b/o.n.core/src/org/netbeans/core/NbLoaderPool.java --- a/o.n.core/src/org/netbeans/core/NbLoaderPool.java +++ b/o.n.core/src/org/netbeans/core/NbLoaderPool.java @@ -52,7 +52,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -74,6 +73,7 @@ import org.openide.loaders.DataLoader; import org.openide.loaders.DataLoaderPool; import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.modules.SpecificationVersion; import org.openide.util.Lookup; import org.openide.util.LookupEvent; @@ -317,9 +317,6 @@ oos.writeObject (new HashMap()/*installBefores*/); oos.writeObject (new HashMap()/*installAfters*/); - // Note which module each loader came from. - Collection modules = Lookup.getDefault().lookupAll(ModuleInfo.class); // Collection - Iterator it = loaders.iterator (); while (it.hasNext ()) { @@ -345,12 +342,9 @@ if (obj != null) { if (err.isLoggable(Level.FINE)) err.fine("writing modified " + l.getClass().getName()); // Find its module, if any. - Class c = l.getClass(); - Iterator mit = modules.iterator(); boolean found = false; - while (mit.hasNext()) { - ModuleInfo m = (ModuleInfo)mit.next(); - if (m.isEnabled() && m.owns(c)) { + ModuleInfo m = Modules.getDefault().ownerOf(l.getClass()); + if (m != null && m.isEnabled()) { if (err.isLoggable(Level.FINE)) err.fine("belongs to module: " + m.getCodeNameBase()); oos.writeObject(m.getCodeNameBase()); int r = m.getCodeNameRelease(); @@ -362,8 +356,6 @@ oos.writeObject(null); } found = true; - break; - } } if (!found) { if (err.isLoggable(Level.FINE)) err.fine("does not belong to any module"); diff --git a/openide.loaders/src/org/openide/loaders/DataLoaderPool.java b/openide.loaders/src/org/openide/loaders/DataLoaderPool.java --- a/openide.loaders/src/org/openide/loaders/DataLoaderPool.java +++ b/openide.loaders/src/org/openide/loaders/DataLoaderPool.java @@ -52,6 +52,7 @@ import javax.swing.event.*; import org.openide.filesystems.*; import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.nodes.*; import org.openide.util.*; import org.openide.util.actions.SystemAction; @@ -568,18 +569,11 @@ fo.setAttribute(DataObject.EA_ASSIGNED_LOADER, null); } else { Class c = loader.getClass(); - // [PENDING] in the future a more efficient API may be introduced - Iterator modules = Lookup.getDefault().lookupAll(ModuleInfo.class).iterator(); - String modulename = null; - while (modules.hasNext()) { - ModuleInfo module = (ModuleInfo)modules.next(); - if (module.owns(c)) { - modulename = module.getCodeNameBase(); - break; - } + fo.setAttribute (DataObject.EA_ASSIGNED_LOADER, c.getName ()); + ModuleInfo module = Modules.getDefault().ownerOf(c); + if (module != null) { + fo.setAttribute(DataObject.EA_ASSIGNED_LOADER_MODULE, module.getCodeNameBase()); } - fo.setAttribute (DataObject.EA_ASSIGNED_LOADER, c.getName ()); - fo.setAttribute(DataObject.EA_ASSIGNED_LOADER_MODULE, modulename); } if (!DataObjectPool.getPOOL().revalidate(Collections.singleton(fo)).isEmpty()) { DataObject.LOG.fine("It was not possible to invalidate data object: " + fo); // NOI18N diff --git a/openide.modules/src/org/openide/modules/ModuleInfo.java b/openide.modules/src/org/openide/modules/ModuleInfo.java --- a/openide.modules/src/org/openide/modules/ModuleInfo.java +++ b/openide.modules/src/org/openide/modules/ModuleInfo.java @@ -43,13 +43,9 @@ */ package org.openide.modules; -import java.beans.*; - -// THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES -// OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM -// INTERACTIONS SHOULD GO ELSEWHERE. -import java.util.*; - +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.Set; /** General information about a module. * Immutable from an API perspective, serves as @@ -162,10 +158,11 @@ * was loaded as a part of this module, and thus will only be * loadable later if this module is enabled. * If in doubt, return false. + * @see Modules#ownerOf * @since 1.28 */ public abstract boolean owns(Class clazz); - + /** * Get a class loader associated with this module that can load * classes defined in the module. @@ -197,4 +194,5 @@ public String[] getProvides() { return new String[] { }; } + } diff --git a/openide.modules/src/org/openide/modules/Modules.java b/openide.modules/src/org/openide/modules/Modules.java new file mode 100644 --- /dev/null +++ b/openide.modules/src/org/openide/modules/Modules.java @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2010 Sun Microsystems, Inc. + */ + +package org.openide.modules; + +import org.openide.util.Lookup; + +/** + * Information about the set of available {@linkplain ModuleInfo modules}. + * An implementation of this service should be registered by the module system. + * @since XXX + */ +public abstract class Modules { + + public static Modules getDefault() { + Modules impl = Lookup.getDefault().lookup(Modules.class); + if (impl == null) { + impl = new Trivial(); + } + return impl; + } + + /** + * Restricted constructor for subclasses. + */ + protected Modules() { + if (!(this instanceof Trivial) && !getClass().getName().equals("org.netbeans.ModuleManager")) { + throw new IllegalAccessError(); + } + } + + /** + * Finds the module which loaded a class. + * @param clazz a class + * @return the owner of the class, or null if it is not owned by any module + * @see ModuleInfo#owns + */ + public abstract ModuleInfo ownerOf(Class clazz); + + private static class Trivial extends Modules { + + public @Override ModuleInfo ownerOf(Class clazz) { + for (ModuleInfo module : Lookup.getDefault().lookupAll(ModuleInfo.class)) { + if (module.owns(clazz)) { + return module; + } + } + return null; + } + + } + +} diff --git a/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java b/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java --- a/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java +++ b/refactoring.api/src/org/netbeans/modules/refactoring/api/AbstractRefactoring.java @@ -72,6 +72,7 @@ import org.openide.util.Lookup; import org.netbeans.modules.refactoring.spi.RefactoringElementsBag; import org.netbeans.modules.refactoring.spi.impl.RefactoringPanel; +import org.openide.modules.Modules; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Parameters; @@ -373,13 +374,9 @@ } } - private String getModuleName(Class c) { - for (ModuleInfo info:Lookup.getDefault().lookupAll(ModuleInfo.class)) { - if (info.owns(c)) { - return info.getDisplayName(); - } - } - return "Unknown";//NOI18N + private String getModuleName(Class c) { + ModuleInfo info = Modules.getDefault().ownerOf(c); + return info != null ? info.getDisplayName() : "Unknown"; //NOI18N } private String createMessage(Class c, Throwable t) { diff --git a/settings/src/org/netbeans/modules/settings/convertors/ModuleInfoManager.java b/settings/src/org/netbeans/modules/settings/convertors/ModuleInfoManager.java --- a/settings/src/org/netbeans/modules/settings/convertors/ModuleInfoManager.java +++ b/settings/src/org/netbeans/modules/settings/convertors/ModuleInfoManager.java @@ -164,19 +164,6 @@ return reloaded; } - - /** look up ModuleInfo according to clazz - * @param clazz class used in the look up query - * @return module info of the module which clazz was loaded from - */ - public ModuleInfo getModuleInfo(Class clazz) { - Iterator it = getModulesResult().allInstances().iterator(); - while (it.hasNext()) { - ModuleInfo mi = (ModuleInfo) it.next(); - if (mi.owns(clazz)) return mi; - } - return null; - } /** register listener to be notified about changes of mi * @param sdc convertor diff --git a/settings/src/org/netbeans/modules/settings/convertors/SerialDataConvertor.java b/settings/src/org/netbeans/modules/settings/convertors/SerialDataConvertor.java --- a/settings/src/org/netbeans/modules/settings/convertors/SerialDataConvertor.java +++ b/settings/src/org/netbeans/modules/settings/convertors/SerialDataConvertor.java @@ -77,6 +77,7 @@ import org.openide.loaders.Environment; import org.openide.loaders.InstanceDataObject; import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.SharedClassObject; @@ -135,7 +136,7 @@ * @exception IOException if the object cannot be written */ public void write(Writer w, Object inst) throws IOException { - XMLSettingsSupport.storeToXML10(inst, w, ModuleInfoManager.getDefault().getModuleInfo(inst.getClass())); + XMLSettingsSupport.storeToXML10(inst, w, Modules.getDefault().ownerOf(inst.getClass())); } /** delegate to SaveSupport to handle an unfired setting object change diff --git a/settings/src/org/netbeans/modules/settings/convertors/XMLSettingsSupport.java b/settings/src/org/netbeans/modules/settings/convertors/XMLSettingsSupport.java --- a/settings/src/org/netbeans/modules/settings/convertors/XMLSettingsSupport.java +++ b/settings/src/org/netbeans/modules/settings/convertors/XMLSettingsSupport.java @@ -52,6 +52,7 @@ import org.openide.filesystems.*; import org.openide.modules.ModuleInfo; +import org.openide.modules.Modules; import org.openide.modules.SpecificationVersion; import org.openide.util.Exceptions; import org.openide.util.Lookup; @@ -1167,7 +1168,7 @@ } public void write(java.io.Writer w, Object inst) throws java.io.IOException { - XMLSettingsSupport.storeToXML10(inst, w, ModuleInfoManager.getDefault().getModuleInfo(inst.getClass())); + XMLSettingsSupport.storeToXML10(inst, w, Modules.getDefault().ownerOf(inst.getClass())); } }