? startup/test/unit/src/org/netbeans/core/startup/jars/cyclic-1/org/bar
Index: arch/arch-core-launcher.xml
===================================================================
RCS file: /cvs/core/arch/arch-core-launcher.xml,v
retrieving revision 1.31
diff -u -r1.31 arch-core-launcher.xml
--- arch/arch-core-launcher.xml 22 Aug 2005 14:17:08 -0000 1.31
+++ arch/arch-core-launcher.xml 22 Aug 2005 19:59:06 -0000
@@ -738,6 +738,15 @@
+
The communication between core.jar
and rest of the platform code
Index: bootstrap/src/org/netbeans/FixedModule.java
===================================================================
RCS file: bootstrap/src/org/netbeans/FixedModule.java
diff -N bootstrap/src/org/netbeans/FixedModule.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ bootstrap/src/org/netbeans/FixedModule.java 22 Aug 2005 19:59:07 -0000
@@ -0,0 +1,263 @@
+/*
+ * 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;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import org.openide.ErrorManager;
+import org.openide.util.NbBundle;
+
+
+/** Object representing one module, possibly installed.
+ * Responsible for opening of module JAR file; reading
+ * manifest; parsing basic information such as dependencies;
+ * and creating a classloader for use by the installer.
+ * Methods not defined in ModuleInfo must be called from within
+ * the module manager's read mutex as a rule.
+ * @author Jesse Glick
+ */
+public final class FixedModule extends Module {
+
+ /** localized properties, only non-null if requested from disabled module */
+ private Properties localizedProps;
+
+ /** Map from extension JARs to sets of JAR that load them via Class-Path.
+ * Used only for debugging purposes, so that a warning is printed if two
+ * different modules try to load the same extension (which would cause them
+ * to both load their own private copy, which may not be intended).
+ */
+ private static final Map extensionOwners = new HashMap(); // Map>
+ /** Simple registry of JAR files used as modules.
+ * Used only for debugging purposes, so that we can be sure
+ * that no one is using Class-Path to refer to other modules.
+ */
+ private static final Set moduleJARs = new HashSet(); // Set
+
+ /** Set of locale-variants JARs for this module (or null).
+ * Added explicitly to classloader, and can be used by execution engine.
+ */
+ private Set localeVariants = null; // Set
+ /** Set of extension JARs that this module loads via Class-Path (or null).
+ * Can be used e.g. by execution engine. (#9617)
+ */
+ private Set plainExtensions = null; // Set
+ /** Set of localized extension JARs derived from plainExtensions (or null).
+ * Used to add these to the classloader. (#9348)
+ * Can be used e.g. by execution engine.
+ */
+ private Set localeExtensions = null; // Set
+ /** Patches added at the front of the classloader (or null).
+ * Files are assumed to be JARs; directories are themselves.
+ */
+ private Set patches = null; // Set
+
+ /** Create a special-purpose "fixed" JAR. */
+ public FixedModule(ModuleManager mgr, Events ev, Manifest manifest, Object history, ClassLoader classloader) throws InvalidException {
+ super(mgr, ev, manifest, history, classloader);
+ loadLocalizedPropsClasspath();
+ parseManifest();
+ }
+
+ /** Get a localized attribute.
+ * First, if OpenIDE-Module-Localizing-Bundle was given, the specified
+ * bundle file (in all locale JARs as well as base JAR) is searched for
+ * a key of the specified name.
+ * Otherwise, the manifest's main attributes are searched for an attribute
+ * with the specified name, possibly with a locale suffix.
+ * If the attribute name contains a slash, and there is a manifest section
+ * named according to the part before the last slash, then this section's attributes
+ * are searched instead of the main attributes, and for the attribute listed
+ * after the slash. Currently this would only be useful for localized filesystem
+ * names. E.g. you may request the attribute org/foo/MyFileSystem.class/Display-Name.
+ * In the future certain attributes known to be dangerous could be
+ * explicitly suppressed from this list; should only be used for
+ * documented localizable attributes such as OpenIDE-Module-Name etc.
+ */
+ public Object getLocalizedAttribute(String attr) {
+ String locb = getManifest().getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
+ boolean usingLoader = false;
+ if (locb != null) {
+ if (classloader != null) {
+ if (locb.endsWith(".properties")) { // NOI18N
+ usingLoader = true;
+ String basename = locb.substring(0, locb.length() - 11).replace('/', '.');
+ try {
+ ResourceBundle bundle = NbBundle.getBundle(basename, Locale.getDefault(), classloader);
+ try {
+ return bundle.getString(attr);
+ } catch (MissingResourceException mre) {
+ // Fine, ignore.
+ }
+ } catch (MissingResourceException mre) {
+ Util.err.notify(mre);
+ }
+ } else {
+ Util.err.log(ErrorManager.WARNING, "WARNING - cannot efficiently load non-*.properties OpenIDE-Module-Localizing-Bundle: " + locb);
+ }
+ }
+ if (!usingLoader) {
+ if (localizedProps != null) {
+ String val = localizedProps.getProperty(attr);
+ if (val != null) {
+ return val;
+ }
+ }
+ }
+ }
+ // Try in the manifest now.
+ int idx = attr.lastIndexOf('/'); // NOI18N
+ if (idx == -1) {
+ // Simple main attribute.
+ return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name(attr));
+ } else {
+ // Attribute of a manifest section.
+ String section = attr.substring(0, idx);
+ String realAttr = attr.substring(idx + 1);
+ Attributes attrs = getManifest().getAttributes(section);
+ if (attrs != null) {
+ return NbBundle.getLocalizedValue(attrs, new Attributes.Name(realAttr));
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public boolean isFixed() {
+ return true;
+ }
+
+ /** Similar, but for fixed modules only.
+ * Should be very rarely used: only for classpath modules with a strangely
+ * named OpenIDE-Module-Localizing-Bundle (not *.properties).
+ */
+ private void loadLocalizedPropsClasspath() throws InvalidException {
+ Attributes attr = manifest.getMainAttributes();
+ String locbundle = attr.getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
+ if (locbundle != null) {
+ Util.err.log("Localized props in " + locbundle + " for " + attr.getValue("OpenIDE-Module"));
+ try {
+ int idx = locbundle.lastIndexOf('.'); // NOI18N
+ String name, ext;
+ if (idx == -1) {
+ name = locbundle;
+ ext = ""; // NOI18N
+ } else {
+ name = locbundle.substring(0, idx);
+ ext = locbundle.substring(idx);
+ }
+ List suffixes = new ArrayList(10);
+ Iterator it = NbBundle.getLocalizingSuffixes();
+ while (it.hasNext()) {
+ suffixes.add(it.next());
+ }
+ Collections.reverse(suffixes);
+ it = suffixes.iterator();
+ while (it.hasNext()) {
+ String suffix = (String)it.next();
+ String resource = name + suffix + ext;
+ InputStream is = classloader.getResourceAsStream(resource);
+ if (is != null) {
+ Util.err.log("Found " + resource);
+ if (localizedProps == null) {
+ localizedProps = new Properties();
+ }
+ localizedProps.load(is);
+ }
+ }
+ if (localizedProps == null) {
+ throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N
+ }
+ } catch (IOException ioe) {
+ InvalidException e = new InvalidException(ioe.toString());
+ Util.err.annotate(e, ioe);
+ throw e;
+ }
+ }
+ }
+
+ /** Get all JARs loaded by this module.
+ * Includes the module itself, any locale variants of the module,
+ * any extensions specified with Class-Path, any locale variants
+ * of those extensions.
+ * The list will be in classpath order (patches first).
+ * Currently the temp JAR is provided in the case of test modules, to prevent
+ * sporadic ZIP file exceptions when background threads (like Java parsing) tries
+ * to open libraries found in the library path.
+ * JARs already present in the classpath are not listed.
+ * @return a List<File>
of JARs
+ */
+ public List getAllJars() {
+ return Collections.EMPTY_LIST;
+ }
+
+ /** Set whether this module is supposed to be reloadable.
+ * Has no immediate effect, only impacts what happens the
+ * next time it is enabled (after having been disabled if
+ * necessary).
+ * Must be called from within a write mutex.
+ * @param r whether the module should be considered reloadable
+ */
+ public void setReloadable(boolean r) {
+ throw new IllegalStateException();
+ }
+
+ /** Reload this module. Access from ModuleManager.
+ * If an exception is thrown, the module is considered
+ * to be in an invalid state.
+ */
+ public void reload() throws IOException {
+ throw new IllegalStateException();
+ }
+
+ // Access from ModuleManager:
+ /** Turn on the classloader. Passed a list of parent modules to use.
+ * The parents should already have had their classloaders initialized.
+ */
+ public void classLoaderUp(Set parents) throws IOException {
+ return; // no need
+ }
+
+ /** Turn off the classloader and release all resources. */
+ public void classLoaderDown() {
+ return; // don't touch it
+ }
+ /** Should be called after turning off the classloader of one or more modules & GC'ing. */
+ public void cleanup() {
+ return; // don't touch it
+ }
+
+ /** Notify the module that it is being deleted. */
+ public void destroy() {
+ }
+
+ /** String representation for debugging. */
+ public String toString() {
+ String s = "FixedModule:" + getCodeNameBase(); // NOI18N
+ if (!isValid()) s += "[invalid]"; // NOI18N
+ return s;
+ }
+}
Index: bootstrap/src/org/netbeans/Module.java
===================================================================
RCS file: /cvs/core/bootstrap/src/org/netbeans/Module.java,v
retrieving revision 1.5
diff -u -r1.5 Module.java
--- bootstrap/src/org/netbeans/Module.java 11 Aug 2005 18:33:57 -0000 1.5
+++ bootstrap/src/org/netbeans/Module.java 22 Aug 2005 19:59:09 -0000
@@ -15,31 +15,19 @@
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.security.AllPermission;
-import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.MissingResourceException;
import java.util.Properties;
-import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
-import java.util.jar.JarFile;
import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import org.netbeans.JarClassLoader;
-import org.netbeans.ProxyClassLoader;
import org.openide.ErrorManager;
import org.openide.modules.Dependency;
import org.openide.modules.ModuleInfo;
@@ -55,7 +43,7 @@
* the module manager's read mutex as a rule.
* @author Jesse Glick
*/
-public final class Module extends ModuleInfo {
+public abstract class Module extends ModuleInfo {
public static final String PROP_RELOADABLE = "reloadable"; // NOI18N
public static final String PROP_CLASS_LOADER = "classLoader"; // NOI18N
@@ -63,28 +51,24 @@
public static final String PROP_VALID = "valid"; // NOI18N
public static final String PROP_PROBLEMS = "problems"; // NOI18N
+ /** module manifest */
+ protected Manifest manifest;
/** manager which owns this module */
- private final ModuleManager mgr;
+ protected final ModuleManager mgr;
/** event logging (should not be much here) */
- private final Events ev;
+ protected final Events events;
/** associated history object
* @see ModuleHistory
*/
private final Object history;
- /** JAR file holding the module */
- private final File jar;
- /** if reloadable, temporary JAR file actually loaded from */
- private File physicalJar = null;
/** true if currently enabled; manipulated by ModuleManager */
private boolean enabled;
- /** whether it is supposed to be easily reloadable */
- private boolean reloadable;
/** whether it is supposed to be automatically loaded when required */
private final boolean autoload;
+ /** */
+ protected boolean reloadable;
/** if true, this module is eagerly turned on whenever it can be */
private final boolean eager;
- /** module manifest */
- private Manifest manifest;
/** code name base (no slash) */
private String codeNameBase;
/** code name release, or -1 if undefined */
@@ -98,7 +82,7 @@
/** specification version parsed from manifest, or null */
private SpecificationVersion specVers;
/** currently active module classloader */
- private ClassLoader classloader = null;
+ protected ClassLoader classloader = null;
/** localized properties, only non-null if requested from disabled module */
private Properties localizedProps;
/** public packages, may be null */
@@ -106,73 +90,29 @@
/** Set of CNBs of friend modules or null */
private Set/**/ friendNames;
- /** Map from extension JARs to sets of JAR that load them via Class-Path.
- * Used only for debugging purposes, so that a warning is printed if two
- * different modules try to load the same extension (which would cause them
- * to both load their own private copy, which may not be intended).
- */
- private static final Map extensionOwners = new HashMap(); // Map>
- /** Simple registry of JAR files used as modules.
- * Used only for debugging purposes, so that we can be sure
- * that no one is using Class-Path to refer to other modules.
- */
- private static final Set moduleJARs = new HashSet(); // Set
-
- /** Set of locale-variants JARs for this module (or null).
- * Added explicitly to classloader, and can be used by execution engine.
- */
- private Set localeVariants = null; // Set
- /** Set of extension JARs that this module loads via Class-Path (or null).
- * Can be used e.g. by execution engine. (#9617)
- */
- private Set plainExtensions = null; // Set
- /** Set of localized extension JARs derived from plainExtensions (or null).
- * Used to add these to the classloader. (#9348)
- * Can be used e.g. by execution engine.
- */
- private Set localeExtensions = null; // Set
- /** Patches added at the front of the classloader (or null).
- * Files are assumed to be JARs; directories are themselves.
- */
- private Set patches = null; // Set
-
/** Use ModuleManager.create as a factory. */
- Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
+ public Module(ModuleManager mgr, Events ev, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
if (autoload && eager) throw new IllegalArgumentException("A module may not be both autoload and eager"); // NOI18N
this.mgr = mgr;
- this.ev = ev;
- this.jar = jar;
+ this.events = ev;
this.history = history;
this.reloadable = reloadable;
this.autoload = autoload;
this.eager = eager;
enabled = false;
- loadManifest();
- parseManifest();
- findExtensionsAndVariants(manifest);
- // Check if some other module already listed this one in Class-Path.
- // For the chronologically reverse case, see findExtensionsAndVariants().
- Set bogoOwners = (Set)extensionOwners.get(jar);
- if (bogoOwners != null) {
- Util.err.log(ErrorManager.WARNING, "WARNING - module " + jar + " was incorrectly placed in the Class-Path of other JARs " + bogoOwners + "; please use OpenIDE-Module-Module-Dependencies instead");
- }
- moduleJARs.add(jar);
}
/** Create a special-purpose "fixed" JAR. */
- Module(ModuleManager mgr, Events ev, Manifest manifest, Object history, ClassLoader classloader) throws InvalidException {
+ public Module(ModuleManager mgr, Events ev, Manifest manifest, Object history, ClassLoader classloader) throws InvalidException {
this.mgr = mgr;
- this.ev = ev;
+ this.events = ev;
this.manifest = manifest;
this.history = history;
this.classloader = classloader;
- jar = null;
reloadable = false;
autoload = false;
eager = false;
enabled = false;
- //loadLocalizedPropsClasspath();
- parseManifest();
}
/** Get the associated module manager. */
@@ -186,9 +126,8 @@
// Access from ModuleManager:
void setEnabled(boolean enabled) {
- /* #13647: actually can happen if loading of bootstrap modules is rolled back:
+ /* #13647: actually can happen if loading of bootstrap modules is rolled back: */
if (isFixed() && ! enabled) throw new IllegalStateException("Cannot disable a fixed module: " + this); // NOI18N
- */
this.enabled = enabled;
}
@@ -250,75 +189,7 @@
* explicitly suppressed from this list; should only be used for
* documented localizable attributes such as OpenIDE-Module-Name etc.
*/
- public Object getLocalizedAttribute(String attr) {
- String locb = manifest.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
- boolean usingLoader = false;
- if (locb != null) {
- if (classloader != null) {
- if (locb.endsWith(".properties")) { // NOI18N
- usingLoader = true;
- String basename = locb.substring(0, locb.length() - 11).replace('/', '.');
- try {
- ResourceBundle bundle = NbBundle.getBundle(basename, Locale.getDefault(), classloader);
- try {
- return bundle.getString(attr);
- } catch (MissingResourceException mre) {
- // Fine, ignore.
- }
- } catch (MissingResourceException mre) {
- Util.err.notify(mre);
- }
- } else {
- Util.err.log(ErrorManager.WARNING, "WARNING - cannot efficiently load non-*.properties OpenIDE-Module-Localizing-Bundle: " + locb);
- }
- }
- if (!usingLoader) {
- if (localizedProps == null) {
- Util.err.log("Trying to get localized attr " + attr + " from disabled module " + getCodeNameBase());
- try {
- if (jar != null) {
- JarFile jarFile = new JarFile(jar, false);
- try {
- loadLocalizedProps(jarFile, manifest);
- } finally {
- jarFile.close();
- }
- } else if (classloader != null) {
- loadLocalizedPropsClasspath();
- } else {
- throw new IllegalStateException();
- }
- } catch (IOException ioe) {
- Util.err.annotate(ioe, ErrorManager.INFORMATIONAL, jar.getAbsolutePath(), null, null, null);
- Util.err.notify(ErrorManager.INFORMATIONAL, ioe);
- if (localizedProps == null) {
- localizedProps = new Properties();
- }
- }
- }
- String val = localizedProps.getProperty(attr);
- if (val != null) {
- return val;
- }
- }
- }
- // Try in the manifest now.
- int idx = attr.lastIndexOf('/'); // NOI18N
- if (idx == -1) {
- // Simple main attribute.
- return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name(attr));
- } else {
- // Attribute of a manifest section.
- String section = attr.substring(0, idx);
- String realAttr = attr.substring(idx + 1);
- Attributes attrs = getManifest().getAttributes(section);
- if (attrs != null) {
- return NbBundle.getLocalizedValue(attrs, new Attributes.Name(realAttr));
- } else {
- return null;
- }
- }
- }
+ public abstract Object getLocalizedAttribute(String attr);
public String getCodeName() {
return codeName;
@@ -393,14 +264,14 @@
* If anything is in an invalid format, throws an exception with
* some kind of description of the problem.
*/
- private void parseManifest() throws InvalidException {
+ public void parseManifest() throws InvalidException {
Attributes attr = manifest.getMainAttributes();
// Code name
codeName = attr.getValue("OpenIDE-Module"); // NOI18N
if (codeName == null) {
- InvalidException e = new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */jar); // NOI18N
+ InvalidException e = new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */this); // NOI18N
// #29393: plausible user mistake, deal with it politely.
- Util.err.annotate(e, NbBundle.getMessage(Module.class, "EXC_not_a_module", jar.getAbsolutePath()));
+ Util.err.annotate(e, NbBundle.getMessage(Module.class, "EXC_not_a_module", this.toString()));
throw e;
}
try {
@@ -550,311 +421,6 @@
}
}
- /** Get the JAR this module is packaged in.
- * May be null for modules installed specially, e.g.
- * automatically from the classpath.
- * @see #isFixed
- */
- public File getJarFile() {
- return jar;
- }
-
- /** Check if this is a "fixed" module.
- * Fixed modules are installed automatically (e.g. based on classpath)
- * and cannot be uninstalled or manipulated in any way.
- */
- public boolean isFixed() {
- return jar == null;
- }
-
- /** Create a temporary test JAR if necessary.
- * This is primarily necessary to work around a Java bug,
- * #4405789, which might be fixed in 1.4--check up on this.
- */
- private void ensurePhysicalJar() throws IOException {
- if (reloadable && physicalJar == null) {
- physicalJar = Util.makeTempJar(jar);
- }
- }
- private void destroyPhysicalJar() {
- if (physicalJar != null) {
- if (physicalJar.isFile()) {
- if (! physicalJar.delete()) {
- Util.err.log(ErrorManager.WARNING, "Warning: temporary JAR " + physicalJar + " not currently deletable.");
- } else {
- Util.err.log("deleted: " + physicalJar);
- }
- }
- physicalJar = null;
- } else {
- Util.err.log("no physicalJar to delete for " + this);
- }
- }
-
- /** Open the JAR, load its manifest, and do related things. */
- private void loadManifest() throws IOException {
- Util.err.log("loading manifest of " + jar);
- File jarBeingOpened = null; // for annotation purposes
- try {
- if (reloadable) {
- // Never try to cache reloadable JARs.
- jarBeingOpened = physicalJar; // might be null
- ensurePhysicalJar();
- jarBeingOpened = physicalJar; // might have changed
- JarFile jarFile = new JarFile(physicalJar, false);
- try {
- Manifest m = jarFile.getManifest();
- if (m == null) throw new IOException("No manifest found in " + physicalJar); // NOI18N
- manifest = m;
- } finally {
- jarFile.close();
- }
- } else {
- jarBeingOpened = jar;
- manifest = mgr.loadManifest(jar);
- }
- } catch (IOException e) {
- if (jarBeingOpened != null) {
- Util.err.annotate(e, ErrorManager.UNKNOWN, "While loading manifest from: " + jarBeingOpened, null, null, null); // NOI18N
- }
- throw e;
- }
- }
-
- /** Find any extensions loaded by the module, as well as any localized
- * variants of the module or its extensions.
- */
- private void findExtensionsAndVariants(Manifest m) {
- assert jar != null : "Cannot load extensions from classpath module " + codeNameBase;
- localeVariants = null;
- List l = Util.findLocaleVariantsOf(jar, false);
- if (!l.isEmpty()) localeVariants = new HashSet(l);
- plainExtensions = null;
- localeExtensions = null;
- String classPath = m.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
- if (classPath != null) {
- StringTokenizer tok = new StringTokenizer(classPath);
- while (tok.hasMoreTokens()) {
- String ext = tok.nextToken();
- if (new File(ext).isAbsolute() || ext.indexOf("../") != -1) { // NOI18N
- if (ext.equals("../lib/updater.jar")) { // NOI18N
- // Special case, see #24703.
- // JAR is special to the launcher, so it makes sense in lib/ rather
- // than modules/ext/. However updater.jar is not in startup classpath,
- // so autoupdate module explicitly declares it this way.
- } else {
- Util.err.log(ErrorManager.WARNING, "WARNING: Class-Path value " + ext + " from " + jar + " is illegal according to the Java Extension Mechanism: must be relative and not move up directories");
- }
- }
- File extfile = new File(jar.getParentFile(), ext.replace('/', File.separatorChar));
- if (! extfile.exists()) {
- // Ignore unloadable extensions.
- Util.err.log(ErrorManager.WARNING, "Warning: Class-Path value " + ext + " from " + jar + " cannot be found at " + extfile);
- continue;
- }
- //No need to sync on extensionOwners - we are in write mutex
- Set owners = (Set)extensionOwners.get(extfile);
- if (owners == null) {
- owners = new HashSet(2);
- owners.add(jar);
- extensionOwners.put(extfile, owners);
- } else if (! owners.contains(jar)) {
- owners.add(jar);
- ev.log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners);
- } // else already know about it (OK or warned)
- // Also check to make sure it is not a module JAR! See constructor for the reverse case.
- if (moduleJARs.contains(extfile)) {
- Util.err.log(ErrorManager.WARNING, "WARNING: Class-Path value " + ext + " from " + jar + " illegally refers to another module; use OpenIDE-Module-Module-Dependencies instead");
- }
- if (plainExtensions == null) plainExtensions = new HashSet();
- plainExtensions.add(extfile);
- l = Util.findLocaleVariantsOf(extfile, false);
- if (!l.isEmpty()) {
- if (localeExtensions == null) localeExtensions = new HashSet();
- localeExtensions.addAll(l);
- }
- }
- }
- // #9273: load any modules/patches/this-code-name/*.jar files first:
- File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
- getCodeNameBase().replace('.', '-')); // NOI18N
- scanForPatches(patchdir);
- // Use of the following system property is not supported, but is used
- // by e.g. XTest to influence installed modules without changing the build.
- // Format is -Dnetbeans.patches.org.nb.mods.foo=/path/to.file.jar:/path/to/dir
- String patchesClassPath = System.getProperty("netbeans.patches." + getCodeNameBase()); // NOI18N
- if (patchesClassPath != null) {
- StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator);
- while (tokenizer.hasMoreElements()) {
- String element = (String) tokenizer.nextElement();
- File fileElement = new File(element);
- if (fileElement.exists()) {
- if (patches == null) {
- patches = new HashSet(15);
- }
- patches.add(fileElement);
- }
- }
- }
- Util.err.log("localeVariants of " + jar + ": " + localeVariants);
- Util.err.log("plainExtensions of " + jar + ": " + plainExtensions);
- Util.err.log("localeExtensions of " + jar + ": " + localeExtensions);
- Util.err.log("patches of " + jar + ": " + patches);
- if (patches != null) {
- Iterator it = patches.iterator();
- while (it.hasNext()) {
- ev.log(Events.PATCH, it.next());
- }
- }
- }
-
- /** Scans a directory for possible patch JARs. */
- private void scanForPatches(File patchdir) {
- if (!patchdir.isDirectory()) {
- return;
- }
- File[] jars = patchdir.listFiles(Util.jarFilter());
- if (jars != null) {
- for (int j = 0; j < jars.length; j++) {
- if (patches == null) {
- patches = new HashSet(5);
- }
- patches.add(jars[j]);
- }
- } else {
- Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
- }
- }
-
- /** Check if there is any need to load localized properties.
- * If so, try to load them. Throw an exception if they cannot
- * be loaded for some reason. Uses an open JAR file for the
- * base module at least, though may also open locale variants
- * as needed.
- * Note: due to #19698, this cache is not usually used; only if you
- * specifically go to look at the display properties of a disabled module.
- * @see #12549
- */
- private void loadLocalizedProps(JarFile jarFile, Manifest m) throws IOException {
- String locbundle = m.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
- if (locbundle != null) {
- // Something requested, read it in.
- // locbundle is a resource path.
- {
- ZipEntry bundleFile = jarFile.getEntry(locbundle);
- // May not be present in base JAR: might only be in e.g. default locale variant.
- if (bundleFile != null) {
- localizedProps = new Properties();
- InputStream is = jarFile.getInputStream(bundleFile);
- try {
- localizedProps.load(is);
- } finally {
- is.close();
- }
- }
- }
- {
- // Check also for localized variant JARs and load in anything from them as needed.
- // Note we need to go in the reverse of the usual search order, so as to
- // overwrite less specific bundles with more specific.
- int idx = locbundle.lastIndexOf('.'); // NOI18N
- String name, ext;
- if (idx == -1) {
- name = locbundle;
- ext = ""; // NOI18N
- } else {
- name = locbundle.substring(0, idx);
- ext = locbundle.substring(idx);
- }
- List pairs = Util.findLocaleVariantsOf(jar, true);
- Collections.reverse(pairs);
- Iterator it = pairs.iterator();
- while (it.hasNext()) {
- Object[] pair = (Object[])it.next();
- File localeJar = (File)pair[0];
- String suffix = (String)pair[1];
- String rsrc = name + suffix + ext;
- JarFile localeJarFile = new JarFile(localeJar, false);
- try {
- ZipEntry bundleFile = localeJarFile.getEntry(rsrc);
- // Need not exist in all locale variants.
- if (bundleFile != null) {
- if (localizedProps == null) {
- localizedProps = new Properties();
- } // else append and overwrite base-locale values
- InputStream is = localeJarFile.getInputStream(bundleFile);
- try {
- localizedProps.load(is);
- } finally {
- is.close();
- }
- }
- } finally {
- localeJarFile.close();
- }
- }
- }
- if (localizedProps == null) {
- // We should have loaded from at least some bundle in there...
- throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N
- }
- /* Don't log; too large and annoying:
- if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
- Util.err.log("localizedProps=" + localizedProps);
- }
- */
- }
- }
-
- /** Similar, but for fixed modules only.
- * Should be very rarely used: only for classpath modules with a strangely
- * named OpenIDE-Module-Localizing-Bundle (not *.properties).
- */
- private void loadLocalizedPropsClasspath() throws InvalidException {
- Attributes attr = manifest.getMainAttributes();
- String locbundle = attr.getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
- if (locbundle != null) {
- Util.err.log("Localized props in " + locbundle + " for " + attr.getValue("OpenIDE-Module"));
- try {
- int idx = locbundle.lastIndexOf('.'); // NOI18N
- String name, ext;
- if (idx == -1) {
- name = locbundle;
- ext = ""; // NOI18N
- } else {
- name = locbundle.substring(0, idx);
- ext = locbundle.substring(idx);
- }
- List suffixes = new ArrayList(10);
- Iterator it = NbBundle.getLocalizingSuffixes();
- while (it.hasNext()) {
- suffixes.add(it.next());
- }
- Collections.reverse(suffixes);
- it = suffixes.iterator();
- while (it.hasNext()) {
- String suffix = (String)it.next();
- String resource = name + suffix + ext;
- InputStream is = classloader.getResourceAsStream(resource);
- if (is != null) {
- Util.err.log("Found " + resource);
- if (localizedProps == null) {
- localizedProps = new Properties();
- }
- localizedProps.load(is);
- }
- }
- if (localizedProps == null) {
- throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N
- }
- } catch (IOException ioe) {
- InvalidException e = new InvalidException(ioe.toString());
- Util.err.annotate(e, ioe);
- throw e;
- }
- }
- }
-
/** Get all JARs loaded by this module.
* Includes the module itself, any locale variants of the module,
* any extensions specified with Class-Path, any locale variants
@@ -866,23 +432,7 @@
* JARs already present in the classpath are not listed.
* @return a List<File>
of JARs
*/
- public List getAllJars() {
- if (jar == null) {
- // Classpath module.
- return Collections.EMPTY_LIST;
- }
- List l = new ArrayList (); // List
- if (patches != null) l.addAll(patches);
- if (physicalJar != null) {
- l.add(physicalJar);
- } else if (jar != null) {
- l.add(jar);
- }
- if (plainExtensions != null) l.addAll (plainExtensions);
- if (localeVariants != null) l.addAll (localeVariants);
- if (localeExtensions != null) l.addAll (localeExtensions);
- return l;
- }
+ public abstract List getAllJars();
/** Is this module supposed to be easily reloadable?
* If so, it is suitable for testing inside the IDE.
@@ -901,14 +451,7 @@
* Must be called from within a write mutex.
* @param r whether the module should be considered reloadable
*/
- public void setReloadable(boolean r) {
- mgr.assertWritable();
- if (isFixed()) throw new IllegalStateException();
- if (reloadable != r) {
- reloadable = r;
- mgr.fireReloadable(this);
- }
- }
+ public abstract void setReloadable(boolean r);
/** Used as a flag to tell if this module was really successfully released.
* Currently does not work, so if it cannot be made to work, delete it.
@@ -923,20 +466,7 @@
* to be in an invalid state.
* @since JST-PENDING: needed from ModuleSystem
*/
- public final void reload() throws IOException {
- if (isFixed()) throw new IllegalStateException();
- // Probably unnecessary but just in case:
- destroyPhysicalJar();
- String codeNameBase1 = getCodeNameBase();
- localizedProps = null;
- loadManifest();
- parseManifest();
- findExtensionsAndVariants(manifest);
- String codeNameBase2 = getCodeNameBase();
- if (! codeNameBase1.equals(codeNameBase2)) {
- throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N
- }
- }
+ public abstract void reload() throws IOException;
// impl of ModuleInfo method
public ClassLoader getClassLoader() throws IllegalArgumentException {
@@ -951,124 +481,25 @@
/** Turn on the classloader. Passed a list of parent modules to use.
* The parents should already have had their classloaders initialized.
*/
- void classLoaderUp(Set parents) throws IOException {
- if (isFixed()) return; // no need
- Util.err.log("classLoaderUp on " + this + " with parents " + parents);
- // Find classloaders for dependent modules and parent to them.
- List loaders = new ArrayList(parents.size() + 1); // List
- // This should really be the base loader created by org.nb.Main for loading openide etc.:
- loaders.add(Module.class.getClassLoader());
- Iterator it = parents.iterator();
- while (it.hasNext()) {
- Module parent = (Module)it.next();
- PackageExport[] exports = parent.getPublicPackages();
- if (exports != null && exports.length == 0) {
- // Check if there is an impl dep here.
- Dependency[] deps = getDependenciesArray();
- boolean implDep = false;
- for (int i = 0; i < deps.length; i++) {
- if (deps[i].getType() == Dependency.TYPE_MODULE &&
- deps[i].getComparison() == Dependency.COMPARE_IMPL &&
- deps[i].getName().equals(parent.getCodeName())) {
- implDep = true;
- break;
- }
- }
- if (!implDep) {
- // Nothing exported from here at all, no sense even adding it.
- // Shortcut; would not harm anything to add it now, but we would
- // never use it anyway.
- // Cf. #27853.
- continue;
- }
- }
- ClassLoader l = parent.getClassLoader();
- if (parent.isFixed() && loaders.contains(l)) {
- Util.err.log("#24996: skipping duplicate classloader from " + parent);
- continue;
- }
- loaders.add(l);
- }
- List classp = new ArrayList(3); // List
- if (patches != null) {
- for (it = patches.iterator(); it.hasNext(); ) {
- File f = (File)it.next();
- if (f.isDirectory()) {
- classp.add(f);
- } else {
- classp.add(new JarFile(f, false));
- }
- }
- }
- if (reloadable) {
- ensurePhysicalJar();
- // Using OPEN_DELETE does not work well with test modules under 1.4.
- // Random code (URL handler?) still expects the JAR to be there and
- // it is not.
- classp.add(new JarFile(physicalJar, false));
- } else {
- classp.add(new JarFile(jar, false));
- }
- // URLClassLoader would not otherwise find these, so:
- if (localeVariants != null) {
- for (it = localeVariants.iterator(); it.hasNext(); ) {
- classp.add(new JarFile((File)it.next(), false));
- }
- }
- if (localeExtensions != null) {
- for (it = localeExtensions.iterator(); it.hasNext(); ) {
- File act = (File)it.next();
- classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
- }
- }
- if (plainExtensions != null) {
- for( it = plainExtensions.iterator(); it.hasNext(); ) {
- File act = (File)it.next();
- classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
- }
- }
-
- // #27853:
- mgr.refineClassLoader(this, loaders);
-
- try {
- classloader = new OneModuleClassLoader(classp, (ClassLoader[])loaders.toArray(new ClassLoader[loaders.size()]));
- } catch (IllegalArgumentException iae) {
- // Should not happen, but just in case.
- IOException ioe = new IOException(iae.toString());
- Util.err.annotate(ioe, iae);
- throw ioe;
- }
- }
-
+ public abstract void classLoaderUp(Set parents) throws IOException;
+
/** Turn off the classloader and release all resources. */
- void classLoaderDown() {
- if (isFixed()) return; // don't touch it
- if (classloader instanceof ProxyClassLoader) {
- ((ProxyClassLoader)classloader).destroy();
- }
- classloader = null;
- Util.err.log("classLoaderDown on " + this + ": releaseCount=" + releaseCount + " released=" + released);
- released = false;
- }
+ public abstract void classLoaderDown();
/** Should be called after turning off the classloader of one or more modules & GC'ing. */
- void cleanup() {
- if (isFixed()) return; // don't touch it
- if (isEnabled()) throw new IllegalStateException("cleanup on enabled module: " + this); // NOI18N
- if (classloader != null) throw new IllegalStateException("cleanup on module with classloader: " + this); // NOI18N
- if (! released) {
- Util.err.log("Warning: not all resources associated with module " + jar + " were successfully released.");
- released = true;
- } else {
- Util.err.log ("All resources associated with module " + jar + " were successfully released.");
- }
- // XXX should this rather be done when the classloader is collected?
- destroyPhysicalJar();
- }
+ public abstract void cleanup();
/** Notify the module that it is being deleted. */
- void destroy() {
- moduleJARs.remove(jar);
+ public abstract void destroy();
+
+ public abstract boolean isFixed();
+
+ /** Get the JAR this module is packaged in.
+ * May be null for modules installed specially, e.g.
+ * automatically from the classpath.
+ * @see #isFixed
+ */
+ public File getJarFile() {
+ return null;
}
/** Get the JAR manifest.
@@ -1144,82 +575,6 @@
return modulePermissions;
}
- /** Class loader to load a single module.
- * Auto-localizing, multi-parented, permission-granting, the works.
- */
- private class OneModuleClassLoader extends JarClassLoader implements Util.ModuleProvider, Util.PackageAccessibleClassLoader {
- private int rc;
- /** Create a new loader for a module.
- * @param classp the List of all module jars of code directories;
- * includes the module itself, its locale variants,
- * variants of extensions and Class-Path items from Manifest.
- * The items are JarFiles for jars and Files for directories
- * @param parents a set of parent classloaders (from other modules)
- */
- public OneModuleClassLoader(List classp, ClassLoader[] parents) throws IllegalArgumentException {
- super(classp, parents, false);
- rc = releaseCount++;
- }
-
- public Module getModule() {
- return Module.this;
- }
-
- /** Inherited.
- * @param cs is ignored
- * @return PermissionCollection with an AllPermission instance
- */
- protected PermissionCollection getPermissions(CodeSource cs) {
- return getAllPermission();
- }
-
- /** look for JNI libraries also in modules/bin/ */
- protected String findLibrary(String libname) {
- String mapped = System.mapLibraryName(libname);
- File lib = new File(new File(jar.getParentFile(), "lib"), mapped); // NOI18N
- if (lib.isFile()) {
- return lib.getAbsolutePath();
- } else {
- return null;
- }
- }
-
- protected boolean isSpecialResource(String pkg) {
- if (mgr.isSpecialResource(pkg)) {
- return true;
- }
- return super.isSpecialResource(pkg);
- }
-
- protected boolean shouldDelegateResource(String pkg, ClassLoader parent) {
- if (!super.shouldDelegateResource(pkg, parent)) {
- return false;
- }
- Module other;
- if (parent instanceof Util.ModuleProvider) {
- other = ((Util.ModuleProvider)parent).getModule();
- } else {
- other = null;
- }
- return mgr.shouldDelegateResource(Module.this, other, pkg);
- }
-
- public String toString() {
- return super.toString() + "[" + getCodeNameBase() + "]"; // NOI18N
- }
-
- protected void finalize() throws Throwable {
- super.finalize();
- Util.err.log("Finalize for " + this + ": rc=" + rc + " releaseCount=" + releaseCount + " released=" + released); // NOI18N
- if (rc == releaseCount) {
- // Hurrah! release() worked.
- released = true;
- } else {
- Util.err.log("Now resources for " + getCodeNameBase() + " have been released."); // NOI18N
- }
- }
- }
-
/** Struct representing a package exported from a module.
* @since org.netbeans.core/1 > 1.4
* @see Module#getPublicPackages
Index: bootstrap/src/org/netbeans/ModuleFactory.java
===================================================================
RCS file: bootstrap/src/org/netbeans/ModuleFactory.java
diff -N bootstrap/src/org/netbeans/ModuleFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ bootstrap/src/org/netbeans/ModuleFactory.java 22 Aug 2005 19:59:09 -0000
@@ -0,0 +1,65 @@
+/*
+ * 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 Nokia. Portions Copyright 2005 Nokia. All Rights Reserved.
+ */
+package org.netbeans;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.jar.Manifest;
+
+/**
+ * Allows creation of custom modules. The factories are searched in
+ * the default lookup (org.openide.util.Lookup.getDefault()). If there is one
+ * it is used - if there are more of them arbitrary one is used (so please make
+ * sure that there is only one present in the installation). If there is none
+ * in the default lookup the system will use an instance of this class.
+ *
+ * @author David Strupl
+ */
+public class ModuleFactory {
+
+ /**
+ * This method creates a "standard" module. Standard modules can be
+ * disabled, reloaded, autoloaded (loaded only when needed).
+ * @see StandardModule
+ */
+ public Module create(File jar, Object history, boolean reloadable,
+ boolean autoload, boolean eager, ModuleManager mgr, Events ev)
+ throws IOException, DuplicateException {
+ return new StandardModule(mgr, ev, jar, history, reloadable, autoload, eager);
+ }
+ /**
+ * This method creates a "fixed" module. Fixed modules cannot be
+ * realoaded, are always enabled and are typically present on the
+ * classpath.
+ * @see FixedModule
+ */
+ public Module createFixed(Manifest mani, Object history,
+ ClassLoader loader, ModuleManager mgr, Events ev)
+ throws InvalidException, DuplicateException {
+ return new FixedModule(mgr, ev, mani, history, loader);
+ }
+ /**
+ * Allows specifying different parent classloader of all modules classloaders.
+ */
+ public ClassLoader getClasspathDelegateClassLoader(ModuleManager mgr, ClassLoader del) {
+ return del;
+ }
+
+ /**
+ * If this method returns true the parent the original classpath
+ * classloader will be removed from the parent classloaders of a module classloader.
+ */
+ public boolean removeBaseClassLoader() {
+ return false;
+ }
+
+}
Index: bootstrap/src/org/netbeans/ModuleManager.java
===================================================================
RCS file: /cvs/core/bootstrap/src/org/netbeans/ModuleManager.java,v
retrieving revision 1.3
diff -u -r1.3 ModuleManager.java
--- bootstrap/src/org/netbeans/ModuleManager.java 11 Aug 2005 18:33:57 -0000 1.3
+++ bootstrap/src/org/netbeans/ModuleManager.java 22 Aug 2005 19:59:14 -0000
@@ -56,6 +56,7 @@
private final Map providersOf = new HashMap(25); // Map>
private final ModuleInstaller installer;
+ private ModuleFactory moduleFactory;
private SystemClassLoader classLoader;
private List classLoaderPatches; // List
@@ -96,6 +97,11 @@
}
classLoader = new SystemClassLoader(classLoaderPatches, new ClassLoader[] {installer.getClass ().getClassLoader()}, Collections.EMPTY_SET);
updateContextClassLoaders(classLoader, true);
+
+ moduleFactory = (ModuleFactory)Lookup.getDefault().lookup(ModuleFactory.class);
+ if (moduleFactory == null) {
+ moduleFactory = new ModuleFactory();
+ }
}
/** Access for ManifestSection.
@@ -307,6 +313,9 @@
parents.add(m.getClassLoader());
}
}
+ if (moduleFactory.removeBaseClassLoader()) {
+ parents.remove(base);
+ }
ClassLoader[] parentCLs = (ClassLoader[])parents.toArray(new ClassLoader[parents.size()]);
SystemClassLoader nue;
try {
@@ -416,6 +425,9 @@
}
public String toString() {
+ if (debugme == null) {
+ return "SystemClassLoader";
+ }
return debugme.toString();
}
@@ -458,7 +470,8 @@
public Module create(File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException, DuplicateException {
assertWritable();
ev.log(Events.START_CREATE_REGULAR_MODULE, jar);
- Module m = new Module(this, ev, jar.getAbsoluteFile(), history, reloadable, autoload, eager);
+ Module m = moduleFactory.create(jar.getAbsoluteFile(),
+ history, reloadable, autoload, eager, this, ev);
ev.log(Events.FINISH_CREATE_REGULAR_MODULE, jar);
subCreate(m);
if (m.isEager()) {
@@ -491,7 +504,7 @@
assertWritable();
if (mani == null || loader == null) throw new IllegalArgumentException("null manifest or loader"); // NOI18N
ev.log(Events.START_CREATE_BOOT_MODULE, history);
- Module m = new Module(this, ev, mani, history, loader);
+ Module m = moduleFactory.createFixed(mani, history, loader, this, ev);
ev.log(Events.FINISH_CREATE_BOOT_MODULE, history);
subCreate(m);
return m;
@@ -507,12 +520,12 @@
return installer.refineProvides (m);
}
/** Used by Module to communicate with the ModuleInstaller re. classloader. */
- void refineClassLoader(Module m, List parents) {
+ public void refineClassLoader(Module m, List parents) {
// #27853:
installer.refineClassLoader(m, parents);
}
/** Use by OneModuleClassLoader to communicate with the ModuleInstaller re. masking. */
- boolean shouldDelegateResource(Module m, Module parent, String pkg) {
+ public boolean shouldDelegateResource(Module m, Module parent, String pkg) {
// Cf. #19621:
Module.PackageExport[] exports = (parent == null) ? null : parent.getPublicPackages();
if (exports != null) {
@@ -566,7 +579,7 @@
// The installer can perform additional checks:
return installer.shouldDelegateResource(m, parent, pkg);
}
- boolean isSpecialResource(String pkg) {
+ public boolean isSpecialResource(String pkg) {
return installer.isSpecialResource(pkg);
}
// Again, access from Module to ModuleInstaller:
@@ -858,8 +871,19 @@
Util.err.log("enable: adding to system classloader");
List nueclassloaders = new ArrayList(toEnable.size());
Iterator teIt = toEnable.iterator();
- while (teIt.hasNext()) {
- nueclassloaders.add(((Module)teIt.next()).getClassLoader());
+ if (moduleFactory.removeBaseClassLoader()) {
+ ClassLoader base = ModuleManager.class.getClassLoader();
+ nueclassloaders.add(moduleFactory.getClasspathDelegateClassLoader(this, base));
+ while (teIt.hasNext()) {
+ ClassLoader c1 = ((Module)teIt.next()).getClassLoader();
+ if (c1 != base) {
+ nueclassloaders.add(c1);
+ }
+ }
+ } else {
+ while (teIt.hasNext()) {
+ nueclassloaders.add(((Module)teIt.next()).getClassLoader());
+ }
}
classLoader.append((ClassLoader[])(nueclassloaders.toArray(new ClassLoader[nueclassloaders.size()])), toEnable);
} else {
@@ -992,7 +1016,7 @@
if (m.isAutoload()) throw new IllegalArgumentException("Cannot simulate enabling an autoload: " + m); // NOI18N
if (m.isEager()) throw new IllegalArgumentException("Cannot simulate enabling an eager module: " + m); // NOI18N
if (m.isEnabled()) throw new IllegalArgumentException("Already enabled: " + m); // NOI18N
- if (!m.isValid()) throw new IllegalArgumentException("Not managed by me: " + m + " in " + m.getJarFile()); // NOI18N
+ if (!m.isValid()) throw new IllegalArgumentException("Not managed by me: " + m + " in " + m); // NOI18N
maybeAddToEnableList(willEnable, modules, m, true);
}
// XXX clumsy but should work:
@@ -1535,5 +1559,4 @@
installer.close(modules);
return true;
}
-
}
Index: bootstrap/src/org/netbeans/ProxyClassLoader.java
===================================================================
RCS file: /cvs/core/bootstrap/src/org/netbeans/ProxyClassLoader.java,v
retrieving revision 1.18
diff -u -r1.18 ProxyClassLoader.java
--- bootstrap/src/org/netbeans/ProxyClassLoader.java 11 Aug 2005 18:33:57 -0000 1.18
+++ bootstrap/src/org/netbeans/ProxyClassLoader.java 22 Aug 2005 19:59:16 -0000
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import org.openide.util.Lookup;
/**
* A class loader that has multiple parents and uses them for loading
@@ -95,11 +96,15 @@
for (int i = 0; i < nueparents.length; i++) {
if (nueparents[i] == null) throw new IllegalArgumentException("null parent"); // NOI18N
}
-
- parents = coalesceAppend(parents, nueparents);
+ ModuleFactory moduleFactory = (ModuleFactory)Lookup.getDefault().lookup(ModuleFactory.class);
+ if (moduleFactory != null && moduleFactory.removeBaseClassLoader()) {
+ // this hack is here to prevent having the application classloader
+ // as parent to all module classloaders.
+ parents = coalesceAppend(new ClassLoader[0], nueparents);
+ } else {
+ parents = coalesceAppend(parents, nueparents);
+ }
}
-
-
/** Try to destroy this classloader.
* Subsequent attempts to use it will log an error (at most one though).
@@ -536,7 +541,8 @@
for (int i = 0; i < parents.length; i++) {
ClassLoader par = parents[i];
if (!shouldDelegateResource(pkg, par)) continue;
- if (par instanceof ProxyClassLoader) {
+ if ((par instanceof ProxyClassLoader) &&
+ ((ProxyClassLoader)par).shouldBeCheckedAsParentProxyClassLoader()) {
ProxyClassLoader pcl = (ProxyClassLoader)par;
Class c = pcl.fullFindClass(name, fileName, pkg);
// pcl might have have c in its already-loaded classes even though
@@ -546,16 +552,18 @@
} else {
// The following is an optimization, it should not affect semantics:
boolean skip = false;
- if (name.startsWith("org.netbeans.") || // NOI18N
- name.startsWith("org.openide.") || // NOI18N
- name.endsWith(".Bundle") || // NOI18N
- name.endsWith("BeanInfo") || // NOI18N
- name.endsWith("Editor")) { // NOI18N
- if (par.getResource(fileName) == null) {
- // We would just throw CNFE anyway, don't bother!
- // Avg. (over ten runs after primer, w/ netbeans.close):
- // before: 13.87s after: 13.40s saved: 1.3%
- skip = true;
+ if (optimizeNBLoading()) {
+ if (name.startsWith("org.netbeans.") || // NOI18N
+ name.startsWith("org.openide.") || // NOI18N
+ name.endsWith(".Bundle") || // NOI18N
+ name.endsWith("BeanInfo") || // NOI18N
+ name.endsWith("Editor")) { // NOI18N
+ if (par.getResource(fileName) == null) {
+ // We would just throw CNFE anyway, don't bother!
+ // Avg. (over ten runs after primer, w/ netbeans.close):
+ // before: 13.87s after: 13.40s saved: 1.3%
+ skip = true;
+ }
}
}
if (!skip) {
@@ -584,6 +592,21 @@
for (int i = 0; i < pkgs.length; i++) {
all.put(pkgs[i].getName(), pkgs[i]);
}
+ }
+
+ /**
+ * See loadInOrder(...). Can be overriden by special classloaders
+ * (see project installer/jnlp/modules).
+ */
+ protected boolean shouldBeCheckedAsParentProxyClassLoader() {
+ return true;
+ }
+
+ /**
+ * Allows turning off the optimilazation in loadInOrder(...).
+ */
+ protected boolean optimizeNBLoading() {
+ return true;
}
/** Test whether a given resource name is something that any JAR might
Index: bootstrap/src/org/netbeans/StandardModule.java
===================================================================
RCS file: bootstrap/src/org/netbeans/StandardModule.java
diff -N bootstrap/src/org/netbeans/StandardModule.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ bootstrap/src/org/netbeans/StandardModule.java 22 Aug 2005 19:59:18 -0000
@@ -0,0 +1,743 @@
+/*
+ * 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;
+
+// THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES
+// OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM
+// INTERACTIONS SHOULD GO ELSEWHERE.
+// (NbBundle.getLocalizedValue is OK here.)
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import org.netbeans.JarClassLoader;
+import org.netbeans.ProxyClassLoader;
+import org.openide.ErrorManager;
+import org.openide.modules.Dependency;
+import org.openide.util.NbBundle;
+import org.openide.util.WeakSet;
+
+/** Object representing one module, possibly installed.
+ * Responsible for opening of module JAR file; reading
+ * manifest; parsing basic information such as dependencies;
+ * and creating a classloader for use by the installer.
+ * Methods not defined in ModuleInfo must be called from within
+ * the module manager's read mutex as a rule.
+ * @author Jesse Glick
+ */
+public final class StandardModule extends Module {
+
+ /** JAR file holding the module */
+ private final File jar;
+ /** if reloadable, temporary JAR file actually loaded from */
+ private File physicalJar = null;
+
+ /** Map from extension JARs to sets of JAR that load them via Class-Path.
+ * Used only for debugging purposes, so that a warning is printed if two
+ * different modules try to load the same extension (which would cause them
+ * to both load their own private copy, which may not be intended).
+ */
+ private static final Map extensionOwners = new HashMap(); // Map>
+ /** Simple registry of JAR files used as modules.
+ * Used only for debugging purposes, so that we can be sure
+ * that no one is using Class-Path to refer to other modules.
+ */
+ private static final Set moduleJARs = new HashSet(); // Set
+
+ /** Set of locale-variants JARs for this module (or null).
+ * Added explicitly to classloader, and can be used by execution engine.
+ */
+ private Set localeVariants = null; // Set
+ /** Set of extension JARs that this module loads via Class-Path (or null).
+ * Can be used e.g. by execution engine. (#9617)
+ */
+ private Set plainExtensions = null; // Set
+ /** Set of localized extension JARs derived from plainExtensions (or null).
+ * Used to add these to the classloader. (#9348)
+ * Can be used e.g. by execution engine.
+ */
+ private Set localeExtensions = null; // Set
+ /** Patches added at the front of the classloader (or null).
+ * Files are assumed to be JARs; directories are themselves.
+ */
+ private Set patches = null; // Set
+
+ /** localized properties, only non-null if requested from disabled module */
+ private Properties localizedProps;
+
+ /** Use ModuleManager.create as a factory. */
+ public StandardModule(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
+ super(mgr, ev, history, reloadable, autoload, eager);
+ this.jar = jar;
+ loadManifest();
+ parseManifest();
+ findExtensionsAndVariants(manifest);
+ // Check if some other module already listed this one in Class-Path.
+ // For the chronologically reverse case, see findExtensionsAndVariants().
+ Set bogoOwners = (Set)extensionOwners.get(jar);
+ if (bogoOwners != null) {
+ Util.err.log(ErrorManager.WARNING, "WARNING - module " + jar + " was incorrectly placed in the Class-Path of other JARs " + bogoOwners + "; please use OpenIDE-Module-Module-Dependencies instead");
+ }
+ moduleJARs.add(jar);
+ }
+
+ /** Get a localized attribute.
+ * First, if OpenIDE-Module-Localizing-Bundle was given, the specified
+ * bundle file (in all locale JARs as well as base JAR) is searched for
+ * a key of the specified name.
+ * Otherwise, the manifest's main attributes are searched for an attribute
+ * with the specified name, possibly with a locale suffix.
+ * If the attribute name contains a slash, and there is a manifest section
+ * named according to the part before the last slash, then this section's attributes
+ * are searched instead of the main attributes, and for the attribute listed
+ * after the slash. Currently this would only be useful for localized filesystem
+ * names. E.g. you may request the attribute org/foo/MyFileSystem.class/Display-Name.
+ * In the future certain attributes known to be dangerous could be
+ * explicitly suppressed from this list; should only be used for
+ * documented localizable attributes such as OpenIDE-Module-Name etc.
+ */
+ public Object getLocalizedAttribute(String attr) {
+ String locb = getManifest().getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
+ boolean usingLoader = false;
+ if (locb != null) {
+ if (classloader != null) {
+ if (locb.endsWith(".properties")) { // NOI18N
+ usingLoader = true;
+ String basename = locb.substring(0, locb.length() - 11).replace('/', '.');
+ try {
+ ResourceBundle bundle = NbBundle.getBundle(basename, Locale.getDefault(), classloader);
+ try {
+ return bundle.getString(attr);
+ } catch (MissingResourceException mre) {
+ // Fine, ignore.
+ }
+ } catch (MissingResourceException mre) {
+ Util.err.notify(mre);
+ }
+ } else {
+ Util.err.log(ErrorManager.WARNING, "WARNING - cannot efficiently load non-*.properties OpenIDE-Module-Localizing-Bundle: " + locb);
+ }
+ }
+ if (!usingLoader) {
+ if (localizedProps == null) {
+ Util.err.log("Trying to get localized attr " + attr + " from disabled module " + getCodeNameBase());
+ try {
+ if (jar != null) {
+ JarFile jarFile = new JarFile(jar, false);
+ try {
+ loadLocalizedProps(jarFile, manifest);
+ } finally {
+ jarFile.close();
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+ } catch (IOException ioe) {
+ Util.err.annotate(ioe, ErrorManager.INFORMATIONAL, jar.getAbsolutePath(), null, null, null);
+ Util.err.notify(ErrorManager.INFORMATIONAL, ioe);
+ if (localizedProps == null) {
+ localizedProps = new Properties();
+ }
+ }
+ }
+ String val = localizedProps.getProperty(attr);
+ if (val != null) {
+ return val;
+ }
+ }
+ }
+ // Try in the manifest now.
+ int idx = attr.lastIndexOf('/'); // NOI18N
+ if (idx == -1) {
+ // Simple main attribute.
+ return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name(attr));
+ } else {
+ // Attribute of a manifest section.
+ String section = attr.substring(0, idx);
+ String realAttr = attr.substring(idx + 1);
+ Attributes attrs = getManifest().getAttributes(section);
+ if (attrs != null) {
+ return NbBundle.getLocalizedValue(attrs, new Attributes.Name(realAttr));
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public boolean owns(Class clazz) {
+ ClassLoader cl = clazz.getClassLoader();
+ if (cl instanceof Util.ModuleProvider) {
+ return ((Util.ModuleProvider) cl).getModule() == this;
+ }
+ return false;
+
+ }
+
+ public boolean isFixed() {
+ return false;
+ }
+
+ /** Get the JAR this module is packaged in.
+ * May be null for modules installed specially, e.g.
+ * automatically from the classpath.
+ * @see #isFixed
+ */
+ public File getJarFile() {
+ return jar;
+ }
+
+ /** Create a temporary test JAR if necessary.
+ * This is primarily necessary to work around a Java bug,
+ * #4405789, which might be fixed in 1.4--check up on this.
+ */
+ private void ensurePhysicalJar() throws IOException {
+ if (reloadable && physicalJar == null) {
+ physicalJar = Util.makeTempJar(jar);
+ }
+ }
+ private void destroyPhysicalJar() {
+ if (physicalJar != null) {
+ if (physicalJar.isFile()) {
+ if (! physicalJar.delete()) {
+ Util.err.log(ErrorManager.WARNING, "Warning: temporary JAR " + physicalJar + " not currently deletable.");
+ } else {
+ Util.err.log("deleted: " + physicalJar);
+ }
+ }
+ physicalJar = null;
+ } else {
+ Util.err.log("no physicalJar to delete for " + this);
+ }
+ }
+
+ /** Open the JAR, load its manifest, and do related things. */
+ private void loadManifest() throws IOException {
+ Util.err.log("loading manifest of " + jar);
+ File jarBeingOpened = null; // for annotation purposes
+ try {
+ if (reloadable) {
+ // Never try to cache reloadable JARs.
+ jarBeingOpened = physicalJar; // might be null
+ ensurePhysicalJar();
+ jarBeingOpened = physicalJar; // might have changed
+ JarFile jarFile = new JarFile(physicalJar, false);
+ try {
+ Manifest m = jarFile.getManifest();
+ if (m == null) throw new IOException("No manifest found in " + physicalJar); // NOI18N
+ manifest = m;
+ } finally {
+ jarFile.close();
+ }
+ } else {
+ jarBeingOpened = jar;
+ manifest = getManager().loadManifest(jar);
+ }
+ } catch (IOException e) {
+ if (jarBeingOpened != null) {
+ Util.err.annotate(e, ErrorManager.UNKNOWN, "While loading manifest from: " + jarBeingOpened, null, null, null); // NOI18N
+ }
+ throw e;
+ }
+ }
+
+ /** Find any extensions loaded by the module, as well as any localized
+ * variants of the module or its extensions.
+ */
+ private void findExtensionsAndVariants(Manifest m) {
+ assert jar != null : "Cannot load extensions from classpath module " + getCodeNameBase();
+ localeVariants = null;
+ List l = Util.findLocaleVariantsOf(jar, false);
+ if (!l.isEmpty()) localeVariants = new HashSet(l);
+ plainExtensions = null;
+ localeExtensions = null;
+ String classPath = m.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
+ if (classPath != null) {
+ StringTokenizer tok = new StringTokenizer(classPath);
+ while (tok.hasMoreTokens()) {
+ String ext = tok.nextToken();
+ if (new File(ext).isAbsolute() || ext.indexOf("../") != -1) { // NOI18N
+ if (ext.equals("../lib/updater.jar")) { // NOI18N
+ // Special case, see #24703.
+ // JAR is special to the launcher, so it makes sense in lib/ rather
+ // than modules/ext/. However updater.jar is not in startup classpath,
+ // so autoupdate module explicitly declares it this way.
+ } else {
+ Util.err.log(ErrorManager.WARNING, "WARNING: Class-Path value " + ext + " from " + jar + " is illegal according to the Java Extension Mechanism: must be relative and not move up directories");
+ }
+ }
+ File extfile = new File(jar.getParentFile(), ext.replace('/', File.separatorChar));
+ if (! extfile.exists()) {
+ // Ignore unloadable extensions.
+ Util.err.log(ErrorManager.WARNING, "Warning: Class-Path value " + ext + " from " + jar + " cannot be found at " + extfile);
+ continue;
+ }
+ //No need to sync on extensionOwners - we are in write mutex
+ Set owners = (Set)extensionOwners.get(extfile);
+ if (owners == null) {
+ owners = new HashSet(2);
+ owners.add(jar);
+ extensionOwners.put(extfile, owners);
+ } else if (! owners.contains(jar)) {
+ owners.add(jar);
+ events.log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners);
+ } // else already know about it (OK or warned)
+ // Also check to make sure it is not a module JAR! See constructor for the reverse case.
+ if (moduleJARs.contains(extfile)) {
+ Util.err.log(ErrorManager.WARNING, "WARNING: Class-Path value " + ext + " from " + jar + " illegally refers to another module; use OpenIDE-Module-Module-Dependencies instead");
+ }
+ if (plainExtensions == null) plainExtensions = new HashSet();
+ plainExtensions.add(extfile);
+ l = Util.findLocaleVariantsOf(extfile, false);
+ if (!l.isEmpty()) {
+ if (localeExtensions == null) localeExtensions = new HashSet();
+ localeExtensions.addAll(l);
+ }
+ }
+ }
+ // #9273: load any modules/patches/this-code-name/*.jar files first:
+ File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
+ getCodeNameBase().replace('.', '-')); // NOI18N
+ scanForPatches(patchdir);
+ // Use of the following system property is not supported, but is used
+ // by e.g. XTest to influence installed modules without changing the build.
+ // Format is -Dnetbeans.patches.org.nb.mods.foo=/path/to.file.jar:/path/to/dir
+ String patchesClassPath = System.getProperty("netbeans.patches." + getCodeNameBase()); // NOI18N
+ if (patchesClassPath != null) {
+ StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator);
+ while (tokenizer.hasMoreElements()) {
+ String element = (String) tokenizer.nextElement();
+ File fileElement = new File(element);
+ if (fileElement.exists()) {
+ if (patches == null) {
+ patches = new HashSet(15);
+ }
+ patches.add(fileElement);
+ }
+ }
+ }
+ Util.err.log("localeVariants of " + jar + ": " + localeVariants);
+ Util.err.log("plainExtensions of " + jar + ": " + plainExtensions);
+ Util.err.log("localeExtensions of " + jar + ": " + localeExtensions);
+ Util.err.log("patches of " + jar + ": " + patches);
+ if (patches != null) {
+ Iterator it = patches.iterator();
+ while (it.hasNext()) {
+ events.log(Events.PATCH, it.next());
+ }
+ }
+ }
+
+ /** Scans a directory for possible patch JARs. */
+ private void scanForPatches(File patchdir) {
+ if (!patchdir.isDirectory()) {
+ return;
+ }
+ File[] jars = patchdir.listFiles(Util.jarFilter());
+ if (jars != null) {
+ for (int j = 0; j < jars.length; j++) {
+ if (patches == null) {
+ patches = new HashSet(5);
+ }
+ patches.add(jars[j]);
+ }
+ } else {
+ Util.err.log(ErrorManager.WARNING, "Could not search for patches in " + patchdir);
+ }
+ }
+
+ /** Check if there is any need to load localized properties.
+ * If so, try to load them. Throw an exception if they cannot
+ * be loaded for some reason. Uses an open JAR file for the
+ * base module at least, though may also open locale variants
+ * as needed.
+ * Note: due to #19698, this cache is not usually used; only if you
+ * specifically go to look at the display properties of a disabled module.
+ * @see #12549
+ */
+ private void loadLocalizedProps(JarFile jarFile, Manifest m) throws IOException {
+ String locbundle = m.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N
+ if (locbundle != null) {
+ // Something requested, read it in.
+ // locbundle is a resource path.
+ {
+ ZipEntry bundleFile = jarFile.getEntry(locbundle);
+ // May not be present in base JAR: might only be in e.g. default locale variant.
+ if (bundleFile != null) {
+ localizedProps = new Properties();
+ InputStream is = jarFile.getInputStream(bundleFile);
+ try {
+ localizedProps.load(is);
+ } finally {
+ is.close();
+ }
+ }
+ }
+ {
+ // Check also for localized variant JARs and load in anything from them as needed.
+ // Note we need to go in the reverse of the usual search order, so as to
+ // overwrite less specific bundles with more specific.
+ int idx = locbundle.lastIndexOf('.'); // NOI18N
+ String name, ext;
+ if (idx == -1) {
+ name = locbundle;
+ ext = ""; // NOI18N
+ } else {
+ name = locbundle.substring(0, idx);
+ ext = locbundle.substring(idx);
+ }
+ List pairs = Util.findLocaleVariantsOf(jar, true);
+ Collections.reverse(pairs);
+ Iterator it = pairs.iterator();
+ while (it.hasNext()) {
+ Object[] pair = (Object[])it.next();
+ File localeJar = (File)pair[0];
+ String suffix = (String)pair[1];
+ String rsrc = name + suffix + ext;
+ JarFile localeJarFile = new JarFile(localeJar, false);
+ try {
+ ZipEntry bundleFile = localeJarFile.getEntry(rsrc);
+ // Need not exist in all locale variants.
+ if (bundleFile != null) {
+ if (localizedProps == null) {
+ localizedProps = new Properties();
+ } // else append and overwrite base-locale values
+ InputStream is = localeJarFile.getInputStream(bundleFile);
+ try {
+ localizedProps.load(is);
+ } finally {
+ is.close();
+ }
+ }
+ } finally {
+ localeJarFile.close();
+ }
+ }
+ }
+ if (localizedProps == null) {
+ // We should have loaded from at least some bundle in there...
+ throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N
+ }
+ /* Don't log; too large and annoying:
+ if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) {
+ Util.err.log("localizedProps=" + localizedProps);
+ }
+ */
+ }
+ }
+
+ /** Get all JARs loaded by this module.
+ * Includes the module itself, any locale variants of the module,
+ * any extensions specified with Class-Path, any locale variants
+ * of those extensions.
+ * The list will be in classpath order (patches first).
+ * Currently the temp JAR is provided in the case of test modules, to prevent
+ * sporadic ZIP file exceptions when background threads (like Java parsing) tries
+ * to open libraries found in the library path.
+ * JARs already present in the classpath are not listed.
+ * @return a List<File>
of JARs
+ */
+ public List getAllJars() {
+ List l = new ArrayList (); // List
+ if (patches != null) l.addAll(patches);
+ if (physicalJar != null) {
+ l.add(physicalJar);
+ } else if (jar != null) {
+ l.add(jar);
+ }
+ if (plainExtensions != null) l.addAll (plainExtensions);
+ if (localeVariants != null) l.addAll (localeVariants);
+ if (localeExtensions != null) l.addAll (localeExtensions);
+ return l;
+ }
+
+ /** Set whether this module is supposed to be reloadable.
+ * Has no immediate effect, only impacts what happens the
+ * next time it is enabled (after having been disabled if
+ * necessary).
+ * Must be called from within a write mutex.
+ * @param r whether the module should be considered reloadable
+ */
+ public void setReloadable(boolean r) {
+ getManager().assertWritable();
+ if (reloadable != r) {
+ reloadable = r;
+ getManager().fireReloadable(this);
+ }
+ }
+
+ /** Used as a flag to tell if this module was really successfully released.
+ * Currently does not work, so if it cannot be made to work, delete it.
+ * (Someone seems to be holding a strong reference to the classloader--who?!)
+ */
+ private transient boolean released;
+ /** Count which release() call is really being checked. */
+ private transient int releaseCount = 0;
+
+ /** Reload this module. Access from ModuleManager.
+ * If an exception is thrown, the module is considered
+ * to be in an invalid state.
+ */
+ public void reload() throws IOException {
+ // Probably unnecessary but just in case:
+ destroyPhysicalJar();
+ String codeNameBase1 = getCodeNameBase();
+ localizedProps = null;
+ loadManifest();
+ parseManifest();
+ findExtensionsAndVariants(manifest);
+ String codeNameBase2 = getCodeNameBase();
+ if (! codeNameBase1.equals(codeNameBase2)) {
+ throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N
+ }
+ }
+
+ // Access from ModuleManager:
+ /** Turn on the classloader. Passed a list of parent modules to use.
+ * The parents should already have had their classloaders initialized.
+ */
+ public void classLoaderUp(Set parents) throws IOException {
+ Util.err.log("classLoaderUp on " + this + " with parents " + parents);
+ // Find classloaders for dependent modules and parent to them.
+ List loaders = new ArrayList(parents.size() + 1); // List
+ // This should really be the base loader created by org.nb.Main for loading openide etc.:
+ loaders.add(Module.class.getClassLoader());
+ Iterator it = parents.iterator();
+ while (it.hasNext()) {
+ Module parent = (Module)it.next();
+ PackageExport[] exports = parent.getPublicPackages();
+ if (exports != null && exports.length == 0) {
+ // Check if there is an impl dep here.
+ Dependency[] deps = getDependenciesArray();
+ boolean implDep = false;
+ for (int i = 0; i < deps.length; i++) {
+ if (deps[i].getType() == Dependency.TYPE_MODULE &&
+ deps[i].getComparison() == Dependency.COMPARE_IMPL &&
+ deps[i].getName().equals(parent.getCodeName())) {
+ implDep = true;
+ break;
+ }
+ }
+ if (!implDep) {
+ // Nothing exported from here at all, no sense even adding it.
+ // Shortcut; would not harm anything to add it now, but we would
+ // never use it anyway.
+ // Cf. #27853.
+ continue;
+ }
+ }
+ ClassLoader l = parent.getClassLoader();
+ if (parent.isFixed() && loaders.contains(l)) {
+ Util.err.log("#24996: skipping duplicate classloader from " + parent);
+ continue;
+ }
+ loaders.add(l);
+ }
+ List classp = new ArrayList(3); // List
+ if (patches != null) {
+ for (it = patches.iterator(); it.hasNext(); ) {
+ File f = (File)it.next();
+ if (f.isDirectory()) {
+ classp.add(f);
+ } else {
+ classp.add(new JarFile(f, false));
+ }
+ }
+ }
+ if (reloadable) {
+ ensurePhysicalJar();
+ // Using OPEN_DELETE does not work well with test modules under 1.4.
+ // Random code (URL handler?) still expects the JAR to be there and
+ // it is not.
+ classp.add(new JarFile(physicalJar, false));
+ } else {
+ classp.add(new JarFile(jar, false));
+ }
+ // URLClassLoader would not otherwise find these, so:
+ if (localeVariants != null) {
+ for (it = localeVariants.iterator(); it.hasNext(); ) {
+ classp.add(new JarFile((File)it.next(), false));
+ }
+ }
+ if (localeExtensions != null) {
+ for (it = localeExtensions.iterator(); it.hasNext(); ) {
+ File act = (File)it.next();
+ classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
+ }
+ }
+ if (plainExtensions != null) {
+ for( it = plainExtensions.iterator(); it.hasNext(); ) {
+ File act = (File)it.next();
+ classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
+ }
+ }
+
+ // #27853:
+ getManager().refineClassLoader(this, loaders);
+
+ try {
+ classloader = new OneModuleClassLoader(classp, (ClassLoader[])loaders.toArray(new ClassLoader[loaders.size()]));
+ } catch (IllegalArgumentException iae) {
+ // Should not happen, but just in case.
+ IOException ioe = new IOException(iae.toString());
+ Util.err.annotate(ioe, iae);
+ throw ioe;
+ }
+ }
+
+ /** Turn off the classloader and release all resources. */
+ public void classLoaderDown() {
+ if (classloader instanceof ProxyClassLoader) {
+ ((ProxyClassLoader)classloader).destroy();
+ }
+ classloader = null;
+ Util.err.log("classLoaderDown on " + this + ": releaseCount=" + releaseCount + " released=" + released);
+ released = false;
+ }
+ /** Should be called after turning off the classloader of one or more modules & GC'ing. */
+ public void cleanup() {
+ if (isEnabled()) throw new IllegalStateException("cleanup on enabled module: " + this); // NOI18N
+ if (classloader != null) throw new IllegalStateException("cleanup on module with classloader: " + this); // NOI18N
+ if (! released) {
+ Util.err.log("Warning: not all resources associated with module " + jar + " were successfully released.");
+ released = true;
+ } else {
+ Util.err.log ("All resources associated with module " + jar + " were successfully released.");
+ }
+ // XXX should this rather be done when the classloader is collected?
+ destroyPhysicalJar();
+ }
+
+ /** Notify the module that it is being deleted. */
+ public void destroy() {
+ moduleJARs.remove(jar);
+ }
+
+ /** String representation for debugging. */
+ public String toString() {
+ String s = "StandardModule:" + getCodeNameBase() + " jarFile: " + jar.getAbsolutePath(); // NOI18N
+ if (!isValid()) s += "[invalid]"; // NOI18N
+ return s;
+ }
+
+ /** PermissionCollection with an instance of AllPermission. */
+ private static PermissionCollection modulePermissions;
+ /** @return initialized @see #modulePermission */
+ private static synchronized PermissionCollection getAllPermission() {
+ if (modulePermissions == null) {
+ modulePermissions = new Permissions();
+ modulePermissions.add(new AllPermission());
+ modulePermissions.setReadOnly();
+ }
+ return modulePermissions;
+ }
+
+ /** Class loader to load a single module.
+ * Auto-localizing, multi-parented, permission-granting, the works.
+ */
+ private class OneModuleClassLoader extends JarClassLoader implements Util.ModuleProvider, Util.PackageAccessibleClassLoader {
+ private int rc;
+ /** Create a new loader for a module.
+ * @param classp the List of all module jars of code directories;
+ * includes the module itself, its locale variants,
+ * variants of extensions and Class-Path items from Manifest.
+ * The items are JarFiles for jars and Files for directories
+ * @param parents a set of parent classloaders (from other modules)
+ */
+ public OneModuleClassLoader(List classp, ClassLoader[] parents) throws IllegalArgumentException {
+ super(classp, parents, false);
+ rc = releaseCount++;
+ }
+
+ public Module getModule() {
+ return StandardModule.this;
+ }
+
+ /** Inherited.
+ * @param cs is ignored
+ * @return PermissionCollection with an AllPermission instance
+ */
+ protected PermissionCollection getPermissions(CodeSource cs) {
+ return getAllPermission();
+ }
+
+ /** look for JNI libraries also in modules/bin/ */
+ protected String findLibrary(String libname) {
+ String mapped = System.mapLibraryName(libname);
+ File lib = new File(new File(jar.getParentFile(), "lib"), mapped); // NOI18N
+ if (lib.isFile()) {
+ return lib.getAbsolutePath();
+ } else {
+ return null;
+ }
+ }
+
+ protected boolean isSpecialResource(String pkg) {
+ if (mgr.isSpecialResource(pkg)) {
+ return true;
+ }
+ return super.isSpecialResource(pkg);
+ }
+
+
+ protected boolean shouldDelegateResource(String pkg, ClassLoader parent) {
+ if (!super.shouldDelegateResource(pkg, parent)) {
+ return false;
+ }
+ Module other;
+ if (parent instanceof Util.ModuleProvider) {
+ other = ((Util.ModuleProvider)parent).getModule();
+ } else {
+ other = null;
+ }
+ return getManager().shouldDelegateResource(StandardModule.this, other, pkg);
+ }
+
+ public String toString() {
+ return super.toString() + "[" + getCodeNameBase() + "]"; // NOI18N
+ }
+
+ protected void finalize() throws Throwable {
+ super.finalize();
+ Util.err.log("Finalize for " + this + ": rc=" + rc + " releaseCount=" + releaseCount + " released=" + released); // NOI18N
+ if (rc == releaseCount) {
+ // Hurrah! release() worked.
+ released = true;
+ } else {
+ Util.err.log("Now resources for " + getCodeNameBase() + " have been released."); // NOI18N
+ }
+ }
+ }
+
+}
Index: bootstrap/src/org/netbeans/Util.java
===================================================================
RCS file: /cvs/core/bootstrap/src/org/netbeans/Util.java,v
retrieving revision 1.2
diff -u -r1.2 Util.java
--- bootstrap/src/org/netbeans/Util.java 14 Jun 2005 12:34:26 -0000 1.2
+++ bootstrap/src/org/netbeans/Util.java 22 Aug 2005 19:59:20 -0000
@@ -303,7 +303,7 @@
}
/** Interface to permit a couple of methods in ClassLoader to be made public. */
- interface PackageAccessibleClassLoader {
+ public interface PackageAccessibleClassLoader {
/** @see ClassLoader#getPackage */
Package getPackageAccessibly (String name);
/** @see ClassLoader#getPackages */
@@ -311,7 +311,7 @@
}
/** Interface for a classloader to declare that it comes from a module. */
- interface ModuleProvider {
+ public interface ModuleProvider {
Module getModule();
}
Index: src/org/netbeans/core/LookupCache.java
===================================================================
RCS file: /cvs/core/src/org/netbeans/core/LookupCache.java,v
retrieving revision 1.6
diff -u -r1.6 LookupCache.java
--- src/org/netbeans/core/LookupCache.java 4 Jun 2005 05:11:05 -0000 1.6
+++ src/org/netbeans/core/LookupCache.java 22 Aug 2005 19:59:25 -0000
@@ -37,6 +37,7 @@
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
+import org.netbeans.StandardModule;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.Repository;
@@ -171,7 +172,7 @@
*/
private static File cacheFile() {
String ud = System.getProperty("netbeans.user");
- if (ud != null) {
+ if ((ud != null) && (! ud.equals("memory"))) {
File cachedir = new File(new File (ud, "var"), "cache"); // NOI18N
cachedir.mkdirs();
return new File(cachedir, "folder-lookup.ser"); // NOI18N
@@ -186,7 +187,7 @@
*/
private static File stampFile() {
String ud = System.getProperty("netbeans.user");
- if (ud != null) {
+ if ((ud != null) && (! ud.equals("memory"))) {
File cachedir = new File(new File (ud, "var"), "cache"); // NOI18N
cachedir.mkdirs();
return new File(cachedir, "lookup-stamp.txt"); // NOI18N
@@ -217,7 +218,7 @@
Module m = (Module)it.next();
String layer = (String)m.getAttribute("OpenIDE-Module-Layer"); // NOI18N
if (layer != null) {
- if (!m.isFixed()) {
+ if (m.getJarFile() != null) {
files.add(m.getJarFile());
} else {
URL layerURL = m.getClassLoader().getResource(layer);
Index: startup/src/org/netbeans/core/startup/ModuleList.java
===================================================================
RCS file: /cvs/core/startup/src/org/netbeans/core/startup/ModuleList.java,v
retrieving revision 1.3
diff -u -r1.3 ModuleList.java
--- startup/src/org/netbeans/core/startup/ModuleList.java 3 Aug 2005 19:09:50 -0000 1.3
+++ startup/src/org/netbeans/core/startup/ModuleList.java 22 Aug 2005 19:59:32 -0000
@@ -300,7 +300,7 @@
// We are going to try to turn it on...
status.pendingInstall = false;
Module m = status.module;
- if (m.isEnabled() || m.isFixed() || m.isAutoload() || m.isEager()) throw new IllegalStateException();
+ if (m.isEnabled() || m.isAutoload() || m.isEager()) throw new IllegalStateException();
maybeEnable.add(m);
}
}
@@ -1103,7 +1103,7 @@
Iterator it = mgr.getModules().iterator();
while (it.hasNext()) {
Module m = (Module)it.next();
- if (m.isFixed()) {
+ if (m.isFixed() || m.getAllJars().isEmpty()) {
// No way, we don't manage these.
continue;
}
Index: startup/src/org/netbeans/core/startup/ModuleSystem.java
===================================================================
RCS file: /cvs/core/startup/src/org/netbeans/core/startup/ModuleSystem.java,v
retrieving revision 1.1
diff -u -r1.1 ModuleSystem.java
--- startup/src/org/netbeans/core/startup/ModuleSystem.java 4 Jun 2005 05:11:46 -0000 1.1
+++ startup/src/org/netbeans/core/startup/ModuleSystem.java 22 Aug 2005 19:59:33 -0000
@@ -26,6 +26,7 @@
import java.util.jar.Manifest;
import java.net.URL;
import java.net.MalformedURLException;
+import org.openide.util.Lookup;
/** Controller of the IDE's whole module system.
* Contains higher-level convenience methods to
@@ -284,15 +285,17 @@
Iterator it = mgr.getModules().iterator();
while (it.hasNext()) {
Module m = (Module)it.next();
- if (jar.equals(m.getJarFile())) {
- // Hah, found it.
- if (! m.isReloadable()) {
- m.setReloadable(true);
+ if (m.getJarFile() != null) {
+ if (jar.equals(m.getJarFile())) {
+ // Hah, found it.
+ if (! m.isReloadable()) {
+ m.setReloadable(true);
+ }
+ turnOffModule(m, toReenable);
+ mgr.reload(m);
+ tm = m;
+ break;
}
- turnOffModule(m, toReenable);
- mgr.reload(m);
- tm = m;
- break;
}
}
if (tm == null) {
@@ -303,7 +306,7 @@
tm = mgr.create(jar, new ModuleHistory(jar.getAbsolutePath()), true, false, false);
} catch (DuplicateException dupe) {
Module old = dupe.getOldModule();
- System.err.println("Replacing old module in " + old.getJarFile()); // NOI18N
+ System.err.println("Replacing old module in " + old); // NOI18N
turnOffModule(old, toReenable);
mgr.delete(old);
try {
@@ -317,9 +320,9 @@
}
}
// Try to turn on the test module. It might throw InvalidExc < IOExc.
- System.err.println("Enabling " + tm.getJarFile() + "..."); // NOI18N
+ System.err.println("Enabling " + tm + "..."); // NOI18N
if (!mgr.simulateEnable(Collections.singleton(tm)).contains(tm)) {
- throw new IOException("Cannot enable " + tm.getJarFile() + "; problems: " + tm.getProblems());
+ throw new IOException("Cannot enable " + tm + "; problems: " + tm.getProblems());
}
mgr.enable(tm);
// OK, so far so good; also try to turn on any other modules if
@@ -367,7 +370,7 @@
}
}
try {
- System.err.println("Disabling " + m.getJarFile() + "..."); // NOI18N
+ System.err.println("Disabling " + m + "..."); // NOI18N
// Don't mention the others, they will be mentioned later anyway.
mgr.disable(toReenable);
} finally {
@@ -401,5 +404,5 @@
QuietEvents() {}
protected void logged(String message, Object[] args) {}
}
-
+
}
Index: startup/src/org/netbeans/core/startup/NbInstaller.java
===================================================================
RCS file: /cvs/core/startup/src/org/netbeans/core/startup/NbInstaller.java,v
retrieving revision 1.13
diff -u -r1.13 NbInstaller.java
--- startup/src/org/netbeans/core/startup/NbInstaller.java 22 Aug 2005 18:40:30 -0000 1.13
+++ startup/src/org/netbeans/core/startup/NbInstaller.java 22 Aug 2005 19:59:37 -0000
@@ -912,7 +912,10 @@
if ("org/openide/util/".equals (pkg)) return true; // NOI18N
}
-
+ // IBM's stuff goes here for now:
+ if (pkg.startsWith("org/omg/CORBA/")) return true; // NOI18N
+ if (pkg.startsWith("com/ibm/ejs/util/")) return true; // NOI18N
+ if (pkg.startsWith("javax/rmi/CORBA/")) return true; // NOI18N
// Some classes like DOMError are only in xerces.jar, not in JDK:
if (pkg.equals("org/w3c/dom/")) return true; // NOI18N
@@ -1338,6 +1341,7 @@
while (it.hasNext()) {
Module m = (Module)it.next();
if (m.isFixed()) continue;
+ if (m.getJarFile() == null) continue;
File jar = m.getJarFile();
// Note: extension JARs not checked.
try {
Index: startup/src/org/netbeans/core/startup/TopLogging.java
===================================================================
RCS file: /cvs/core/startup/src/org/netbeans/core/startup/TopLogging.java,v
retrieving revision 1.1
diff -u -r1.1 TopLogging.java
--- startup/src/org/netbeans/core/startup/TopLogging.java 4 Jun 2005 05:11:50 -0000 1.1
+++ startup/src/org/netbeans/core/startup/TopLogging.java 22 Aug 2005 19:59:38 -0000
@@ -33,7 +33,7 @@
private static final boolean disabledConsole = ! Boolean.getBoolean("netbeans.logger.console"); // NOI18N
- private final PrintStream logPrintStream;
+ private PrintStream logPrintStream;
private static TopLogging topLogging;
@@ -51,6 +51,29 @@
*/
TopLogging (String logDir) throws IOException {
topLogging = this;
+
+ DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
+ java.util.Date date = new java.util.Date();
+ if (logDir == null) {
+ // no demultiplexing -- everything goes just to stderr.
+ logPrintStream = System.err;
+ logPrintStream.println("-------------------------------------------------------------------------------"); // NOI18N
+ logPrintStream.println(">Log Session: "+df.format (date)); // NOI18N
+ logPrintStream.println(">System Info: "); // NOI18N
+ try {
+ printSystemInfo(logPrintStream);
+ } catch (Throwable t) {
+ // Serious problems.
+ t.printStackTrace();
+ logPrintStream.flush();
+ }
+ logPrintStream.println("-------------------------------------------------------------------------------"); // NOI18N
+ logPrintStream = new PrintStream(new OutputStream() {
+ public void write(int b) { /* intentionally empty */ }
+ });
+ return;
+ }
+ OutputStream log = null;
File logFileDir = new File (logDir);
if (! logFileDir.exists () && ! logFileDir.mkdirs ()) {
@@ -61,9 +84,7 @@
throw new IOException ("Cannot write to file"); // NOI18N
}
- OutputStream log = new BufferedOutputStream(new FileOutputStream(logFile.getAbsolutePath(), true));
- DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.ENGLISH);
- java.util.Date date = new java.util.Date();
+ log = new BufferedOutputStream(new FileOutputStream(logFile.getAbsolutePath(), true));
final PrintStream stderr = System.err;
logPrintStream = new PrintStream(new StreamDemultiplexor(stderr, log), false, "UTF-8"); // NOI18N
@@ -214,7 +235,7 @@
private static final int FLUSH_DELAY = Integer.getInteger("netbeans.logger.flush.delay", 15000).intValue(); // NOI18N
private final OutputStream stderr;
- private final OutputStream log;
+ private OutputStream log;
StreamDemultiplexor(PrintStream stderr, OutputStream log) {
this.stderr = stderr;
Index: startup/test/unit/src/org/netbeans/core/startup/ModuleFactoryTest.java
===================================================================
RCS file: startup/test/unit/src/org/netbeans/core/startup/ModuleFactoryTest.java
diff -N startup/test/unit/src/org/netbeans/core/startup/ModuleFactoryTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ startup/test/unit/src/org/netbeans/core/startup/ModuleFactoryTest.java 22 Aug 2005 19:59:38 -0000
@@ -0,0 +1,113 @@
+/*
+ * ModuleFactoryTest.java
+ *
+ * Created on July 24, 2005, 5:36 PM
+ *
+ * To change this template, choose Tools | Options and locate the template under
+ * the Source Creation and Management node. Right-click the template and choose
+ * Open. You can then make changes to the template in the Source Editor.
+ */
+
+package org.netbeans.core.startup;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import org.netbeans.DuplicateException;
+import org.netbeans.Events;
+import org.netbeans.FixedModule;
+import org.netbeans.InvalidException;
+import org.netbeans.Module;
+import org.netbeans.ModuleFactory;
+import org.netbeans.ModuleManager;
+import org.netbeans.StandardModule;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+/**
+ * These tests verify that the module manager behaves basically the
+ * same way with ModuleFactory as without it.
+ * @author david
+ */
+public class ModuleFactoryTest extends ModuleManagerTest {
+
+ static {
+ System.setProperty("org.openide.util.Lookup", L.class.getName());
+ assertTrue(Lookup.getDefault() instanceof L);
+ }
+
+ /** Creates a new instance of ModuleFactoryTest */
+ public ModuleFactoryTest(String name) {
+ super(name);
+ }
+
+ public static int numberOfStandard = 0;
+ public static int numberOfFixed = 0;
+
+ public void testFactoryCreatesOurModules() throws Exception {
+ // clear the counters before the test!
+ numberOfStandard = 0;
+ numberOfFixed = 0;
+
+ FakeModuleInstaller installer = new FakeModuleInstaller();
+ FakeEvents ev = new FakeEvents();
+ ModuleManager mgr = new ModuleManager(installer, ev);
+ mgr.mutexPrivileged().enterWriteAccess();
+ try {
+ File j1 = new File(jars, "simple-module.jar");
+ File j2 = new File(jars, "depends-on-simple-module.jar");
+ File j3 = new File(jars, "dep-on-two-modules.jar");
+ URLClassLoader l = new URLClassLoader(new URL[] {j1.toURL(), j2.toURL()});
+ Manifest mani1, mani2;
+ JarFile j = new JarFile(j1);
+ try {
+ mani1 = j.getManifest();
+ } finally {
+ j.close();
+ }
+ j = new JarFile(j2);
+ try {
+ mani2 = j.getManifest();
+ } finally {
+ j.close();
+ }
+ Module m1 = mgr.createFixed(mani1, null, l);
+ Module m2 = mgr.createFixed(mani2, null, l);
+ Module m3 = mgr.create(j3, null, false, false, false);
+ mgr.enable(new HashSet(Arrays.asList(new Module[] {m1, m2, m3})));
+ } finally {
+ mgr.mutexPrivileged().exitWriteAccess();
+ }
+ assertEquals("Number of standard modules created by our factory ", 1, numberOfStandard);
+ assertEquals("Number of fixed modules created by our factory ", 2, numberOfFixed);
+ }
+
+
+ public static final class L extends ProxyLookup {
+ public L() {
+ super(new Lookup[] {
+ Lookups.fixed(new Object[] {
+ new MyModuleFactory()
+ }),
+ });
+ }
+ }
+
+ public static final class MyModuleFactory extends ModuleFactory {
+ public Module create(File jar, Object history, boolean reloadable, boolean autoload, boolean eager, ModuleManager mgr, Events ev) throws IOException, DuplicateException {
+ numberOfStandard++;
+ return new StandardModule(mgr, ev, jar, history, reloadable, autoload, eager);
+ }
+
+ public Module createFixed(Manifest mani, Object history, ClassLoader loader, ModuleManager mgr, Events ev) throws InvalidException, DuplicateException {
+ numberOfFixed++;
+ return new FixedModule(mgr, ev, mani, history, loader);
+ }
+ }
+}