#96711: permit modules to declare JRE packages they wish to override. Otherwise do not mask any JRE packages from modules by default. Also use the override capability in several modules which relied on the old list. diff --git a/core.startup/src/org/netbeans/core/startup/ConsistencyVerifier.java b/core.startup/src/org/netbeans/core/startup/ConsistencyVerifier.java --- a/core.startup/src/org/netbeans/core/startup/ConsistencyVerifier.java +++ b/core.startup/src/org/netbeans/core/startup/ConsistencyVerifier.java @@ -99,7 +99,9 @@ public class ConsistencyVerifier { mgr.mutexPrivileged().enterWriteAccess(); Manifest dummy = new Manifest(); dummy.getMainAttributes().putValue("OpenIDE-Module", "__dummy__"); // NOI18N - dummy.getMainAttributes().putValue("OpenIDE-Module-Provides", "org.openide.modules.ModuleFormat1, " + // NOI18N + dummy.getMainAttributes().putValue("OpenIDE-Module-Provides", + "org.openide.modules.ModuleFormat1, " + // NOI18N + "org.openide.modules.ModuleFormat2, " + // NOI18N "org.openide.modules.os.Unix, " + // NOI18N "org.openide.modules.os.PlainUnix, " + // NOI18N "org.openide.modules.os.Windows, " + // NOI18N diff --git a/core.startup/src/org/netbeans/core/startup/NbInstaller.java b/core.startup/src/org/netbeans/core/startup/NbInstaller.java --- a/core.startup/src/org/netbeans/core/startup/NbInstaller.java +++ b/core.startup/src/org/netbeans/core/startup/NbInstaller.java @@ -52,6 +52,7 @@ import java.util.Date; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -93,7 +94,9 @@ import org.xml.sax.SAXException; * @author Jesse Glick, Jan Pokorsky, Jaroslav Tulach, et al. */ final class NbInstaller extends ModuleInstaller { - + + private static final Logger LOG = Logger.getLogger(NbInstaller.class.getName()); + /** set of manifest sections for each module */ private final Map> sections = new HashMap>(100); /** ModuleInstall classes for each module that declares one */ @@ -110,8 +113,8 @@ final class NbInstaller extends ModuleIn private ModuleManager mgr; /** set of permitted core or package dependencies from a module */ private final Map> kosherPackages = new HashMap>(100); - /** Package prefixes passed as special system property. */ - private static String[] specialResourcePrefixes = null; + /** classpath ~ JRE packages to be hidden from a module */ + private final Map> hiddenClasspathPackages = new HashMap>(); /** Create an NbInstaller. * You should also call {@link #registerManager} and if applicable @@ -135,6 +138,7 @@ final class NbInstaller extends ModuleIn // @SuppressWarnings("unchecked") public void prepare(Module m) throws InvalidException { ev.log(Events.PREPARE, m); + checkForHiddenPackages(m); Set mysections = null; Class clazz = null; { @@ -224,6 +228,50 @@ final class NbInstaller extends ModuleIn layers.put(m, layerResource); } } + + private void checkForHiddenPackages(Module m) throws InvalidException { + List hiddenPackages = new ArrayList(); + List mWithDeps = new LinkedList(); + mWithDeps.add(m); + for (Dependency d : m.getDependencies()) { + if (d.getType() == Dependency.TYPE_MODULE) { + Module _m = mgr.get((String) Util.parseCodeName(d.getName())[0]); + assert _m != null : d; + mWithDeps.add(_m); + } + } + for (Module _m : mWithDeps) { + String hidden = (String) _m.getAttribute("OpenIDE-Module-Hide-Classpath-Packages"); // NOI18N + if (hidden != null) { + for (String piece : hidden.trim().split("[ ,]+")) { // NOI18N + try { + if (piece.endsWith(".*")) { // NOI18N + String pkg = piece.substring(0, piece.length() - 2); + Dependency.create(Dependency.TYPE_MODULE, pkg); + if (pkg.lastIndexOf('/') != -1) { + throw new IllegalArgumentException("Illegal OpenIDE-Module-Hide-Classpath-Packages: " + hidden); // NOI18N + } + hiddenPackages.add(new Module.PackageExport(pkg.replace('.', '/') + '/', false)); + } else if (piece.endsWith(".**")) { // NOI18N + String pkg = piece.substring(0, piece.length() - 3); + Dependency.create(Dependency.TYPE_MODULE, pkg); + if (pkg.lastIndexOf('/') != -1) { + throw new IllegalArgumentException("Illegal OpenIDE-Module-Hide-Classpath-Packages: " + hidden); // NOI18N + } + hiddenPackages.add(new Module.PackageExport(pkg.replace('.', '/') + '/', true)); + } else { + throw new IllegalArgumentException("Illegal OpenIDE-Module-Hide-Classpath-Packages: " + hidden); // NOI18N + } + } catch (IllegalArgumentException x) { + throw new InvalidException(_m, x.getMessage()); + } + } + } + } + if (!hiddenPackages.isEmpty()) { + hiddenClasspathPackages.put(m, hiddenPackages); + } + } public void dispose(Module m) { Util.err.fine("dispose: " + m); @@ -237,6 +285,7 @@ final class NbInstaller extends ModuleIn installs.remove(m); layers.remove(m); kosherPackages.remove(m); + hiddenClasspathPackages.remove(m); } public void load(List modules) { @@ -727,8 +776,9 @@ final class NbInstaller extends ModuleIn arr.add("org.openide.modules.os.Solaris"); // NOI18N } - // module format is now 1 - arr.add ("org.openide.modules.ModuleFormat1"); // NOI18N + // module format is now 2 + arr.add("org.openide.modules.ModuleFormat1"); // NOI18N + arr.add("org.openide.modules.ModuleFormat2"); // NOI18N return arr.toArray (new String[0]); } @@ -743,33 +793,34 @@ final class NbInstaller extends ModuleIn for (String cppkg : CLASSPATH_PACKAGES) { if (pkg.startsWith(cppkg) && !findKosher(m).contains(cppkg)) { // Undeclared use of a classpath package. Refuse it. - if (Util.err.isLoggable(Level.FINE)) { - Util.err.fine("Refusing to load classpath package " + pkg + " for " + m.getCodeNameBase() + " without a proper dependency"); // NOI18N + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Refusing to load classpath package " + pkg + " for " + m.getCodeNameBase() + " without a proper dependency"); // NOI18N } return false; } } + List hiddenPackages = hiddenClasspathPackages.get(m); + if (hiddenPackages != null) { + for (Module.PackageExport hidden : hiddenPackages) { + if (hidden.recursive ? pkg.startsWith(hidden.pkg) : pkg.equals(hidden.pkg)) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Refusing to load classpath package " + pkg + " for " + m.getCodeNameBase()); + } + return false; + } + } + } + } + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("Delegating resource " + pkg + " from " + parent + " for " + m.getCodeNameBase()); } return true; } - private static final String[] CLASSPATH_PACKAGES = new String[] { + private static final String[] CLASSPATH_PACKAGES = { // core.jar shall be inaccessible "org/netbeans/core/startup/", - // Java language infrastructure bundled with IDE; do not want clashes with JDK 6: - "com/sun/tools/javac/", - "com/sun/tools/javadoc/", - "com/sun/javadoc/", - "com/sun/source/", - "javax/annotation/", - "javax/lang/model/", - "javax/tools/", - // do not want JAX-WS 2.0 classes from JDK 6; - "javax/xml/bind/", // NOI18N - "javax/xml/ws/", // NOI18N - "javax/xml/stream/", // NOI18N - "javax/jws/", // NOI18N - "javax/xml/soap/" // NOI18N + // Do not add JRE packages here! See issue #96711 for the alternative. }; private Set findKosher(Module m) { diff --git a/core.startup/test/unit/src/org/netbeans/core/startup/ConsistencyVerifierTest.java b/core.startup/test/unit/src/org/netbeans/core/startup/ConsistencyVerifierTest.java --- a/core.startup/test/unit/src/org/netbeans/core/startup/ConsistencyVerifierTest.java +++ b/core.startup/test/unit/src/org/netbeans/core/startup/ConsistencyVerifierTest.java @@ -100,8 +100,10 @@ public class ConsistencyVerifierTest ext public void testStandardProvides() throws Exception { assertProblems("{}", "=foo; Requires=org.openide.modules.ModuleFormat1"); - assertProblems("{foo=[requires org.openide.modules.ModuleFormat2]}", + assertProblems("{}", "=foo; Requires=org.openide.modules.ModuleFormat2"); + assertProblems("{foo=[requires org.openide.modules.ModuleFormat99]}", + "=foo; Requires=org.openide.modules.ModuleFormat99"); assertProblems("{}", "=foo; Requires=org.openide.modules.os.Unix"); assertProblems("{}", diff --git a/core.startup/test/unit/src/org/netbeans/core/startup/ModuleFormatSatisfiedTest.java b/core.startup/test/unit/src/org/netbeans/core/startup/ModuleFormatSatisfiedTest.java --- a/core.startup/test/unit/src/org/netbeans/core/startup/ModuleFormatSatisfiedTest.java +++ b/core.startup/test/unit/src/org/netbeans/core/startup/ModuleFormatSatisfiedTest.java @@ -75,7 +75,7 @@ public class ModuleFormatSatisfiedTest e man.getMainAttributes ().putValue ("OpenIDE-Module", "org.test.FormatDependency/1"); - String req = "org.openide.modules.ModuleFormat1"; + String req = "org.openide.modules.ModuleFormat1, org.openide.modules.ModuleFormat2"; man.getMainAttributes ().putValue ("OpenIDE-Module-Requires", req); diff --git a/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerHideClasspathPackagesTest.java b/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerHideClasspathPackagesTest.java new file mode 100644 --- /dev/null +++ b/core.startup/test/unit/src/org/netbeans/core/startup/NbInstallerHideClasspathPackagesTest.java @@ -0,0 +1,119 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.core.startup; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.logging.Level; +import org.netbeans.Events; +import org.netbeans.Module; +import org.netbeans.ModuleManager; + +/** + * Checks that OpenIDE-Module-Hide-Classpath-Packages works. + */ +public class NbInstallerHideClasspathPackagesTest extends SetupHid { + + public NbInstallerHideClasspathPackagesTest(String n) { + super(n); + } + + public void testHideClasspathPackages() throws Exception { + File m1j = new File(getWorkDir(), "m1.jar"); + Map contents = new HashMap(); + contents.put("javax/net/SocketFactory.class", "ignored"); + contents.put("javax/swing/JPanel.class", "overrides"); + contents.put("javax/swing/text/Document.class", "overrides"); + contents.put("javax/naming/Context.class", "overrides"); + contents.put("javax/naming/spi/Resolver.class", "ignored"); + Map mani = new HashMap(); + mani.put("OpenIDE-Module", "m1"); + mani.put("OpenIDE-Module-Hide-Classpath-Packages", "javax.swing.**, javax.naming.*"); + createJar(m1j, contents, mani); + File m2j = new File(getWorkDir(), "m2.jar"); + mani = new HashMap(); + mani.put("OpenIDE-Module", "m2"); + mani.put("OpenIDE-Module-Module-Dependencies", "m1"); + // Just to check early attempts to load packages: + mani.put("OpenIDE-Module-Layer", "m2/layer.xml"); + mani.put("OpenIDE-Module-Package-Dependencies", "javax.management[Descriptor]"); + createJar(m2j, Collections.singletonMap("m2/layer.xml", ""), mani); + File m3j = new File(getWorkDir(), "m3.jar"); + createJar(m3j, Collections.emptyMap(), Collections.singletonMap("OpenIDE-Module", "m3")); + Events ev = new FakeEvents(); + NbInstaller inst = new NbInstaller(ev); + ModuleManager mgr = new ModuleManager(inst, ev); + inst.registerManager(mgr); + mgr.mutexPrivileged().enterWriteAccess(); + try { + Module m1 = mgr.create(m1j, null, false, false, false); + Module m2 = mgr.create(m2j, null, false, false, false); + Module m3 = mgr.create(m3j, null, false, false, false); + mgr.enable(new HashSet(Arrays.asList(m1, m2, m3))); + ModuleManagerTest.assertDoesNotOverride(m1, "javax.net.SocketFactory"); + ModuleManagerTest.assertOverrides(m1, "javax.swing.JPanel"); + ModuleManagerTest.assertOverrides(m1, "javax.swing.text.Document"); + ModuleManagerTest.assertOverrides(m1, "javax.naming.Context"); + ModuleManagerTest.assertDoesNotOverride(m1, "javax.naming.spi.Resolver"); + ModuleManagerTest.assertDoesNotOverride(m2, "javax.net.SocketFactory"); + ModuleManagerTest.assertOverrides(m2, "javax.swing.JPanel"); + ModuleManagerTest.assertOverrides(m2, "javax.swing.text.Document"); + ModuleManagerTest.assertOverrides(m2, "javax.naming.Context"); + ModuleManagerTest.assertDoesNotOverride(m2, "javax.naming.spi.Resolver"); + ModuleManagerTest.assertDoesNotOverride(m3, "javax.net.SocketFactory"); + ModuleManagerTest.assertDoesNotOverride(m3, "javax.swing.JPanel"); + ModuleManagerTest.assertDoesNotOverride(m3, "javax.swing.text.Document"); + ModuleManagerTest.assertDoesNotOverride(m3, "javax.naming.Context"); + ModuleManagerTest.assertDoesNotOverride(m3, "javax.naming.spi.Resolver"); + } finally { + mgr.mutexPrivileged().exitWriteAccess(); + } + } + + @Override + protected Level logLevel() { + return Level.FINER; + } + +} diff --git a/etl.editor/manifest.mf b/etl.editor/manifest.mf --- a/etl.editor/manifest.mf +++ b/etl.editor/manifest.mf @@ -2,7 +2,8 @@ OpenIDE-Module: org.netbeans.modules.etl OpenIDE-Module: org.netbeans.modules.etl.editor OpenIDE-Module-Layer: org/netbeans/modules/etl/layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/etl/Bundle.properties -OpenIDE-Module-Requires: org.openide.windows.IOProvider +OpenIDE-Module-Requires: org.openide.windows.IOProvider, org.openide.modules.ModuleFormat2 +OpenIDE-Module-Hide-Classpath-Packages: javax.xml.stream.** OpenIDE-Module-Specification-Version: 1.0 Name: org/netbeans/modules/etl/ui/ETLDataLoader.class diff --git a/libs.javacapi/manifest.mf b/libs.javacapi/manifest.mf --- a/libs.javacapi/manifest.mf +++ b/libs.javacapi/manifest.mf @@ -3,3 +3,5 @@ OpenIDE-Module-Implementation-Version: 1 OpenIDE-Module-Implementation-Version: 1 OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/javacapi/Bundle.properties OpenIDE-Module-Layer: org/netbeans/libs/javacapi/layer.xml +OpenIDE-Module-Requires: org.openide.modules.ModuleFormat2 +OpenIDE-Module-Hide-Classpath-Packages: com.sun.javadoc.**, com.sun.source.**, javax.annotation.**, javax.lang.model.**, javax.tools.** diff --git a/libs.javacimpl/manifest.mf b/libs.javacimpl/manifest.mf --- a/libs.javacimpl/manifest.mf +++ b/libs.javacimpl/manifest.mf @@ -2,4 +2,6 @@ OpenIDE-Module: org.netbeans.libs.javaci OpenIDE-Module: org.netbeans.libs.javacimpl/1 OpenIDE-Module-Implementation-Version: 5 OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/javacimpl/Bundle.properties +OpenIDE-Module-Requires: org.openide.modules.ModuleFormat2 +OpenIDE-Module-Hide-Classpath-Packages: com.sun.tools.javac.**, com.sun.tools.javadoc.** diff --git a/o.n.soa.libs.xmlbeans/manifest.mf b/o.n.soa.libs.xmlbeans/manifest.mf --- a/o.n.soa.libs.xmlbeans/manifest.mf +++ b/o.n.soa.libs.xmlbeans/manifest.mf @@ -3,3 +3,5 @@ OpenIDE-Module-Localizing-Bundle: org/ne OpenIDE-Module-Localizing-Bundle: org/netbeans/soa/libs/xmlbeans/Bundle.properties OpenIDE-Module-Specification-Version: 1.0 OpenIDE-Module-Implementation-Version: 2.1.0 +OpenIDE-Module-Requires: org.openide.modules.ModuleFormat2 +OpenIDE-Module-Hide-Classpath-Packages: javax.xml.stream.** diff --git a/openide.modules/apichanges.xml b/openide.modules/apichanges.xml --- a/openide.modules/apichanges.xml +++ b/openide.modules/apichanges.xml @@ -47,6 +47,57 @@ made subject to such option by the copyr Modules API + + + + + + + +

+ To guaranteed that the new tag will be honored you should also: +

+
OpenIDE-Module-Requires: org.openide.modules.ModuleFormat2
+

+ Several JRE packages used to be hidden automatically but are not any more; + while these were never documented, modules which relied on being able to override + these packages could be broken by having the JRE classes exposed instead. Specifically, + the following packages (or package prefixes) were in NetBeans 6.0 not loaded from the + classpath, but now will be unless otherwise requested: +

+
com.sun.javadoc
+com.sun.source
+com.sun.tools.javac
+com.sun.tools.javadoc
+javax.annotation
+javax.jws
+javax.lang.model
+javax.tools
+javax.xml.bind
+javax.xml.soap
+javax.xml.stream
+javax.xml.ws
+
+ +

+ Packages supplied in a module which overlap those in the JRE or its extensions will normally be ignored + (as usual, the JRE takes precedence). Modules which wish to specifically suppress loading of some packages + from the classpath can now request the class loader to do so by specifying: +

+
OpenIDE-Module-Hide-Classpath-Packages: javax.lang.model.*, com.sun.source.**
+

+ (The syntax is analogous to that of OpenIDE-Module-Public-Packages.) +

+

+ Such a declaration affects not just this module, but any other modules declaring a direct + dependency on it (OpenIDE-Module-Module-Dependencies). The module is now free to bundle + its own versions of these classes and be sure they will be used by it and its clients. + Be aware that as with all changes to the normal class loading scheme, + careless usage could result in LinkageErrors. +

+
+ +
No longer possible to obtain a module JAR entry as a FileObject diff --git a/openide.modules/manifest.mf b/openide.modules/manifest.mf --- a/openide.modules/manifest.mf +++ b/openide.modules/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 Manifest-Version: 1.0 OpenIDE-Module: org.openide.modules OpenIDE-Module-Localizing-Bundle: org/openide/modules/Bundle.properties -OpenIDE-Module-Specification-Version: 7.5 +OpenIDE-Module-Specification-Version: 7.6 diff --git a/websvc.jaxws21api/manifest.mf b/websvc.jaxws21api/manifest.mf --- a/websvc.jaxws21api/manifest.mf +++ b/websvc.jaxws21api/manifest.mf @@ -3,3 +3,5 @@ OpenIDE-Module-Localizing-Bundle: org/ne OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/websvc/jaxws21api/Bundle.properties OpenIDE-Module-Specification-Version: 1.2 AutoUpdate-Show-In-Client: false +OpenIDE-Module-Requires: org.openide.modules.ModuleFormat2 +OpenIDE-Module-Hide-Classpath-Packages: javax.jws.**, javax.xml.bind.**, javax.xml.stream.**, javax.xml.ws.**, javax.xml.soap.**, javax.annotation.**