Index: apisupport/project/src/org/netbeans/modules/apisupport/project/ManifestManager.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/ManifestManager.java,v retrieving revision 1.24 diff -u -r1.24 ManifestManager.java --- apisupport/project/src/org/netbeans/modules/apisupport/project/ManifestManager.java 2 Sep 2005 12:24:35 -0000 1.24 +++ apisupport/project/src/org/netbeans/modules/apisupport/project/ManifestManager.java 12 Jan 2006 20:13:35 -0000 @@ -7,7 +7,7 @@ * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun * Microsystems, Inc. All Rights Reserved. */ @@ -18,7 +18,9 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.JarFile; @@ -45,6 +47,7 @@ private String layer; private String classPath; private PackageExport[] publicPackages; + private String moduleDependencies; private boolean deprecated; public static final String OPENIDE_MODULE = "OpenIDE-Module"; // NOI18N @@ -56,6 +59,7 @@ public static final String OPENIDE_MODULE_LOCALIZING_BUNDLE = "OpenIDE-Module-Localizing-Bundle"; // NOI18N public static final String OPENIDE_MODULE_PUBLIC_PACKAGES = "OpenIDE-Module-Public-Packages"; // NOI18N public static final String OPENIDE_MODULE_FRIENDS = "OpenIDE-Module-Friends"; // NOI18N + public static final String OPENIDE_MODULE_MODULE_DEPENDENCIES = "OpenIDE-Module-Module-Dependencies"; // NOI18N public static final String CLASS_PATH = "Class-Path"; // NOI18N static final PackageExport[] EMPTY_EXPORTED_PACKAGES = new PackageExport[0]; @@ -70,7 +74,7 @@ private ManifestManager(String cnb, String releaseVersion, String specVer, String implVer, String provTokensString, String requiredTokens, String locBundle, String layer, String classPath, - PackageExport[] publicPackages, boolean deprecated) { + PackageExport[] publicPackages, boolean deprecated, String moduleDependencies) { this.codeNameBase = cnb; this.releaseVersion = releaseVersion; this.specificationVersion = specVer; @@ -83,6 +87,7 @@ this.classPath = classPath; this.publicPackages = publicPackages; this.deprecated = deprecated; + this.moduleDependencies = moduleDependencies; } private String[] parseTokens(String tokens) { @@ -165,7 +170,8 @@ attr.getValue(OPENIDE_MODULE_LAYER), attr.getValue(CLASS_PATH), publicPackages, - deprecated); + deprecated, + attr.getValue(OPENIDE_MODULE_MODULE_DEPENDENCIES)); return mm; } @@ -270,6 +276,14 @@ public boolean isDeprecated() { return deprecated; + } + + public Set/**/ getModuleDependencies() { + if (moduleDependencies != null) { + return Dependency.create(Dependency.TYPE_MODULE, moduleDependencies); + } else { + return Collections.EMPTY_SET; + } } /** Index: apisupport/project/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibraries.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibraries.java,v retrieving revision 1.23 diff -u -r1.23 SuiteCustomizerLibraries.java --- apisupport/project/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibraries.java 26 Dec 2005 23:42:16 -0000 1.23 +++ apisupport/project/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibraries.java 12 Jan 2006 20:13:36 -0000 @@ -7,20 +7,24 @@ * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.apisupport.project.ui.customizer; +import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyEditor; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.Set; import java.util.TreeSet; import javax.swing.JButton; @@ -28,7 +32,11 @@ import javax.swing.event.ChangeListener; import org.netbeans.api.java.platform.JavaPlatform; import org.netbeans.api.java.platform.PlatformsCustomizer; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.modules.apisupport.project.ManifestManager; import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.modules.apisupport.project.NbModuleProjectType; +import org.netbeans.modules.apisupport.project.Util; import org.netbeans.modules.apisupport.project.suite.SuiteProject; import org.netbeans.modules.apisupport.project.ui.platform.PlatformComponentFactory; import org.netbeans.modules.apisupport.project.ui.platform.NbPlatformCustomizer; @@ -36,14 +44,19 @@ import org.netbeans.modules.apisupport.project.universe.NbPlatform; import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; +import org.openide.ErrorManager; import org.openide.NotifyDescriptor; import org.openide.explorer.ExplorerManager; +import org.openide.modules.Dependency; +import org.openide.modules.SpecificationVersion; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; +import org.w3c.dom.Element; /** * Represents Libraries panel in Suite customizer. @@ -53,6 +66,7 @@ final class SuiteCustomizerLibraries extends NbPropertyPanel.Suite implements Comparator, ExplorerManager.Provider, ChangeListener { private ExplorerManager manager; + private ModuleEntry[] platformModules; /** * Creates new form SuiteCustomizerLibraries @@ -88,9 +102,11 @@ } private void refreshModules() { - ModuleEntry[] entry = getProperties().getActivePlatform().getModules(); - Node root = createModuleNode(entry); + platformModules = getProperties().getActivePlatform().getModules(); + Node root = createPlatformModulesNode(); manager.setRootContext(root); + universe = null; + updateDependencyWarnings(); } private void refreshJavaPlatforms() { @@ -301,7 +317,7 @@ // End of variables declaration//GEN-END:variables - private Node createModuleNode(ModuleEntry[] entries) { + private Node createPlatformModulesNode() { HashSet disabledModuleCNB = new HashSet(Arrays.asList(getProperties().getDisabledModules())); HashSet disabledClusters = new HashSet(Arrays.asList(getProperties().getDisabledClusters())); @@ -313,26 +329,26 @@ n.setName(getMessage("LBL_ModuleListClusters")); n.setDisplayName(getMessage("LBL_ModuleListClustersModules")); - for (int i = 0; i < entries.length; i++) { - Children clusterChildren = (Children)clusterToChildren.get(entries[i].getClusterDirectory()); + for (int i = 0; i < platformModules.length; i++) { + Children clusterChildren = (Children)clusterToChildren.get(platformModules[i].getClusterDirectory()); if (clusterChildren == null) { Children.SortedArray modules = new Children.SortedArray(); modules.setComparator(this); clusterChildren = modules; - String clusterName = entries[i].getClusterDirectory().getName(); + String clusterName = platformModules[i].getClusterDirectory().getName(); Enabled cluster = new Enabled(modules, !disabledClusters.contains(clusterName)); cluster.setName(clusterName); cluster.setIconBaseWithExtension(SuiteProject.SUITE_ICON_PATH); - clusterToChildren.put(entries[i].getClusterDirectory(), modules); + clusterToChildren.put(platformModules[i].getClusterDirectory(), modules); n.getChildren().add(new Node[] { cluster }); } - String cnb = entries[i].getCodeNameBase(); + String cnb = platformModules[i].getCodeNameBase(); AbstractNode module = new Enabled(Children.LEAF, !disabledModuleCNB.contains(cnb)); module.setName(cnb); - module.setDisplayName(entries[i].getLocalizedName()); - String desc = entries[i].getShortDescription(); + module.setDisplayName(platformModules[i].getLocalizedName()); + String desc = platformModules[i].getShortDescription(); String tooltip; if (desc != null) { if (desc.startsWith("")) { // NOI18N @@ -447,7 +463,7 @@ } } - static final class Enabled extends AbstractNode { + final class Enabled extends AbstractNode { private boolean enabled; private Children standard; @@ -482,6 +498,7 @@ Enabled en = (Enabled)n; en.firePropertyChange(null, null, null); } + updateDependencyWarnings(); } public boolean isEnabled() { @@ -555,6 +572,198 @@ private void initAccessibility() { managePlafsButton.getAccessibleContext().setAccessibleDescription(getMessage("ACSD_ManagePlafsButton")); platformValue.getAccessibleContext().setAccessibleDescription(getMessage("ACSD_PlatformValue")); + } + + // #65924: show warnings if some dependencies cannot be satisfied + + interface UniverseModule { + String getCodeNameBase(); + int getReleaseVersion(); + SpecificationVersion getSpecificationVersion(); + String getImplementationVersion(); + Set/**/ getProvidedTokens(); + Set/**/ getRequiredTokens(); + Set/**/ getModuleDependencies(); + String getCluster(); + String getDisplayName(); + } + + private static abstract class AbstractUniverseModule implements UniverseModule { + protected final ManifestManager mm; + protected AbstractUniverseModule(ManifestManager mm) { + this.mm = mm; + } + public int getReleaseVersion() { + String s = mm.getReleaseVersion(); + return s != null ? Integer.parseInt(s) : -1; + } + public String getImplementationVersion() { + return mm.getImplementationVersion(); + } + public Set/**/ getProvidedTokens() { + return new HashSet(Arrays.asList(mm.getProvidedTokens())); + } + public Set/**/ getRequiredTokens() { + return new HashSet(Arrays.asList(mm.getRequiredTokens())); + } + } + + private static final class PlatformModule extends AbstractUniverseModule { + private final ModuleEntry entry; + public PlatformModule(ModuleEntry entry) throws IOException { + super(ManifestManager.getInstanceFromJAR(entry.getJarLocation())); + this.entry = entry; + } + public String getCodeNameBase() { + return entry.getCodeNameBase(); + } + public SpecificationVersion getSpecificationVersion() { + String s = entry.getSpecificationVersion(); + return s != null ? new SpecificationVersion(s) : null; + } + public Set/**/ getModuleDependencies() { + return mm.getModuleDependencies(); + } + public String getCluster() { + return entry.getClusterDirectory().getName(); + } + public String getDisplayName() { + return entry.getLocalizedName(); + } + } + + private static final class SuiteModule extends AbstractUniverseModule { + private final NbModuleProject project; + private final Set/**/ dependencies; + public SuiteModule(NbModuleProject project) { + super(ManifestManager.getInstance(project.getManifest(), false)); + this.project = project; + dependencies = new HashSet(); + // Cannot use ProjectXMLManager since we need to report also deps on nonexistent modules. + Element dataE = project.getHelper().getPrimaryConfigurationData(true); + Element depsE = Util.findElement(dataE, "module-dependencies", NbModuleProjectType.NAMESPACE_SHARED); // NOI18N + Iterator/**/ deps = Util.findSubElements(depsE).iterator(); + while (deps.hasNext()) { + Element dep = (Element) deps.next(); + Element run = Util.findElement(dep, "run-dependency", NbModuleProjectType.NAMESPACE_SHARED); // NOI18N + if (run == null) { + continue; + } + String text = Util.findText(Util.findElement(dep, "code-name-base", NbModuleProjectType.NAMESPACE_SHARED)); // NOI18N + Element relverE = Util.findElement(run, "release-version", NbModuleProjectType.NAMESPACE_SHARED); // NOI18N + if (relverE != null) { + text += '/' + Util.findText(relverE); + } + Element specverE = Util.findElement(run, "specification-version", NbModuleProjectType.NAMESPACE_SHARED); // NOI18N + if (specverE != null) { + text += '>' + Util.findText(specverE); + } else { + Element implver = Util.findElement(run, "implementation-version", NbModuleProjectType.NAMESPACE_SHARED); // NOI18N + if (implver != null) { + // Will special-case '*' as an impl version to mean "match anything". + text += "=*"; // NOI18N + } + } + dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, text)); + } + } + public String getCodeNameBase() { + return project.getCodeNameBase(); + } + public SpecificationVersion getSpecificationVersion() { + String s = project.getSpecVersion(); + return s != null ? new SpecificationVersion(s) : null; + } + public Set/**/ getModuleDependencies() { + return dependencies; + } + public String getCluster() { + return null; + } + public String getDisplayName() { + return ProjectUtils.getInformation(project).getDisplayName(); + } + } + + private RequestProcessor.Task updateDependencyWarningsTask; + private void updateDependencyWarnings() { + if (updateDependencyWarningsTask == null) { + updateDependencyWarningsTask = RequestProcessor.getDefault().create(new Runnable() { + public void run() { + doUpdateDependencyWarnings(); + } + }); + } + updateDependencyWarningsTask.schedule(0); + } + + static Set/**/ loadUniverseModules(ModuleEntry[] platformModules, Set/**/ suiteModules) throws IOException { + Set universe = new LinkedHashSet(); + Iterator/**/ it = suiteModules.iterator(); + while (it.hasNext()) { + universe.add(new SuiteModule((NbModuleProject) it.next())); + } + for (int i = 0; i < platformModules.length; i++) { + universe.add(new PlatformModule(platformModules[i])); + } + return universe; + } + + static String[] findWarning(Set/**/ universeModules, Set/**/ disabledClusters, Set/**/ disabledModules) { + // XXX + return null; + } + + private Set/**/ universe; + private void doUpdateDependencyWarnings() { + // XXX consider using a PorgressHandle + if (universe == null) { + try { + universe = loadUniverseModules(platformModules, getProperties().getSubModules()); + } catch (IOException e) { + Util.err.notify(ErrorManager.INFORMATIONAL, e); + return; // any warnings would probably be wrong anyway + } + } + + Set disabledClusters = new TreeSet(); + Set disabledModules = new TreeSet(); + + Node[] clusters = getExplorerManager().getRootContext().getChildren().getNodes(); + for (int i = 0; i < clusters.length; i++) { + if (clusters[i] instanceof Enabled) { + Enabled e = (Enabled) clusters[i]; + if (!e.isEnabled()) { + disabledClusters.add(e.getName()); + } else { + Node[] modules = e.getChildren().getNodes(); + for (int j = 0; j < modules.length; j++) { + if (modules[j] instanceof Enabled) { + Enabled m = (Enabled) modules[j]; + if (!m.isEnabled()) { + disabledModules.add(m.getName()); + } + } + } + } + } + } + + final String[] warning = findWarning(universe, disabledClusters, disabledModules); + + EventQueue.invokeLater(new Runnable() { + public void run() { + if (warning != null) { + String key = warning[0]; + String[] args = new String[warning.length - 1]; + System.arraycopy(warning, 1, args, 0, args.length); + setWarning(NbBundle.getMessage(SuiteCustomizerLibraries.class, key, args)); + } else { + setWarning(null); + } + } + }); + } } Index: apisupport/project/test/unit/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibrariesTest.java =================================================================== RCS file: apisupport/project/test/unit/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibrariesTest.java diff -N apisupport/project/test/unit/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibrariesTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ apisupport/project/test/unit/src/org/netbeans/modules/apisupport/project/ui/customizer/SuiteCustomizerLibrariesTest.java 12 Jan 2006 20:13:36 -0000 @@ -0,0 +1,164 @@ +/* + * 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-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.apisupport.project.ui.customizer; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.jar.Manifest; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.apisupport.project.EditableManifest; +import org.netbeans.modules.apisupport.project.ManifestManager; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.modules.apisupport.project.ProjectXMLManager; +import org.netbeans.modules.apisupport.project.TestBase; +import org.netbeans.modules.apisupport.project.Util; +import org.netbeans.modules.apisupport.project.suite.SuiteProject; +import org.netbeans.modules.apisupport.project.universe.LocalizedBundleInfo; +import org.netbeans.modules.apisupport.project.universe.NbPlatform; +import org.openide.modules.Dependency; +import org.openide.modules.SpecificationVersion; + +/** + * Tests module dependencies in a suite. + * @author Jesse Glick + */ +public class SuiteCustomizerLibrariesTest extends NbTestCase { + + public SuiteCustomizerLibrariesTest(String name) { + super(name); + } + + private NbPlatform platform; + private SuiteProject suite; + + protected void setUp() throws Exception { + super.setUp(); + clearWorkDir(); + // PLATFORM SETUP + TestBase.initializeBuildProperties(getWorkDir()); + File install = new File(getWorkDir(), "install"); + TestBase.makePlatform(install); + // MODULE foo + Manifest mani = new Manifest(); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE, "foo/1"); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE_SPECIFICATION_VERSION, "1.0"); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE_IMPLEMENTATION_VERSION, "foo-1"); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE_LOCALIZING_BUNDLE, "foo/Bundle.properties"); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE_PROVIDES, "tok1, tok1a"); + Map/**/ contents = new HashMap(); + contents.put("foo/Bundle.properties", "OpenIDE-Module-Name=Foo Module"); + TestBase.createJar(new File(new File(new File(install, "somecluster"), "modules"), "foo.jar"), contents, mani); + // MODULE bar + mani = new Manifest(); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE, "bar"); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE_REQUIRES, "tok1"); + TestBase.createJar(new File(new File(new File(install, "somecluster"), "modules"), "bar.jar"), Collections.EMPTY_MAP, mani); + // MODULE baz + mani = new Manifest(); + mani.getMainAttributes().putValue(ManifestManager.OPENIDE_MODULE, "baz"); + mani.getMainAttributes().putValue("OpenIDE-Module-Module-Dependencies", "foo/1 > 1.0"); + TestBase.createJar(new File(new File(new File(install, "anothercluster"), "modules"), "baz.jar"), Collections.EMPTY_MAP, mani); + platform = NbPlatform.addPlatform("custom", install, "custom"); + // SUITE setup + suite = TestBase.generateSuite(getWorkDir(), "suite", "custom"); + // MODULE org.example.module1 + NbModuleProject module = TestBase.generateSuiteComponent(suite, "module1"); + EditableManifest em = Util.loadManifest(module.getManifestFile()); + em.setAttribute(ManifestManager.OPENIDE_MODULE, "org.example.module1/2", null); + em.setAttribute(ManifestManager.OPENIDE_MODULE_SPECIFICATION_VERSION, "2.0", null); + em.setAttribute(ManifestManager.OPENIDE_MODULE_PROVIDES, "tok2", null); + Util.storeManifest(module.getManifestFile(), em); + LocalizedBundleInfo lbinfo = ((LocalizedBundleInfo.Provider) module.getLookup().lookup(LocalizedBundleInfo.Provider.class)).getLocalizedBundleInfo(); + lbinfo.setDisplayName("Module One"); + lbinfo.store(); + // MODULE org.example.module2 + module = TestBase.generateSuiteComponent(suite, "module2"); + em = Util.loadManifest(module.getManifestFile()); + em.removeAttribute(ManifestManager.OPENIDE_MODULE_SPECIFICATION_VERSION, null); + em.setAttribute(ManifestManager.OPENIDE_MODULE_REQUIRES, "tok2", null); + Util.storeManifest(module.getManifestFile(), em); + lbinfo = ((LocalizedBundleInfo.Provider) module.getLookup().lookup(LocalizedBundleInfo.Provider.class)).getLocalizedBundleInfo(); + lbinfo.setDisplayName("Module Two"); + lbinfo.store(); + // MODULE org.example.module3 + module = TestBase.generateSuiteComponent(suite, "module3"); + ProjectXMLManager xml = new ProjectXMLManager(module.getHelper()); + xml.addDependency(new ModuleDependency(module.getModuleList().getEntry("org.example.module2"))); + xml.addDependency(new ModuleDependency(module.getModuleList().getEntry("bar"))); + // XXX need richer deps + ProjectManager.getDefault().saveAllProjects(); + } + + public void testUniverseModules() throws Exception { // #65924 + Set/**/ modules = SuiteCustomizerLibraries.loadUniverseModules(platform.getModules(), SuiteUtils.getSubProjects(suite)); + Map/**/ modulesByName = new HashMap(); + for (Iterator it = modules.iterator(); it.hasNext(); ) { + SuiteCustomizerLibraries.UniverseModule m = (SuiteCustomizerLibraries.UniverseModule) it.next(); + modulesByName.put(m.getCodeNameBase(), m); + } + assertEquals(modules.size(), modulesByName.size()); + SuiteCustomizerLibraries.UniverseModule m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("core"); + assertNotNull(m); + // core.jar is just a dummy JAR, nothing interesting to test + m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("foo"); + assertNotNull(m); + assertEquals("somecluster", m.getCluster()); + assertEquals("Foo Module", m.getDisplayName()); + assertEquals(1, m.getReleaseVersion()); + assertEquals(new SpecificationVersion("1.0"), m.getSpecificationVersion()); + assertEquals("foo-1", m.getImplementationVersion()); + assertEquals(new HashSet(Arrays.asList(new String[] {"tok1", "tok1a"})), m.getProvidedTokens()); + assertEquals(Collections.EMPTY_SET, m.getRequiredTokens()); + assertEquals(Collections.EMPTY_SET, m.getModuleDependencies()); + m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("bar"); + assertNotNull(m); + assertEquals(Collections.EMPTY_SET, m.getProvidedTokens()); + assertEquals(Collections.singleton("tok1"), m.getRequiredTokens()); + m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("baz"); + assertNotNull(m); + assertEquals(Dependency.create(Dependency.TYPE_MODULE, "foo/1 > 1.0"), m.getModuleDependencies()); + m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("org.example.module1"); + assertNotNull(m); + assertNull(m.getCluster()); + assertEquals("Module One", m.getDisplayName()); + assertEquals(2, m.getReleaseVersion()); + assertEquals(new SpecificationVersion("2.0"), m.getSpecificationVersion()); + assertNull(m.getImplementationVersion()); + assertEquals(Collections.singleton("tok2"), m.getProvidedTokens()); + assertEquals(Collections.EMPTY_SET, m.getRequiredTokens()); + assertEquals(Collections.EMPTY_SET, m.getModuleDependencies()); + m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("org.example.module2"); + assertNotNull(m); + assertEquals(-1, m.getReleaseVersion()); + assertNull(m.getSpecificationVersion()); + assertNull(m.getImplementationVersion()); + assertEquals(Collections.EMPTY_SET, m.getProvidedTokens()); + assertEquals(Collections.singleton("tok2"), m.getRequiredTokens()); + m = (SuiteCustomizerLibraries.UniverseModule) modulesByName.get("org.example.module3"); + assertNotNull(m); + assertEquals(Dependency.create(Dependency.TYPE_MODULE, "org.example.module2, bar"), m.getModuleDependencies()); + } + + public void testDependencyWarnings() throws Exception { // #65924 + // XXX + } + +}