diff -r 1d9013023a29 core.netigso/test/unit/src/org/netbeans/core/netigso/NetigsoOSGiCanDependTest.java --- a/core.netigso/test/unit/src/org/netbeans/core/netigso/NetigsoOSGiCanDependTest.java Mon Apr 16 07:57:16 2012 +0200 +++ b/core.netigso/test/unit/src/org/netbeans/core/netigso/NetigsoOSGiCanDependTest.java Mon Apr 16 18:20:27 2012 +0200 @@ -45,10 +45,12 @@ import java.io.File; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import org.netbeans.MockEvents; import org.netbeans.MockModuleInstaller; import org.netbeans.Module; import org.netbeans.ModuleManager; +import org.openide.modules.Dependency; /** * @@ -77,6 +79,7 @@ File j2 = changeManifest(new File(jars, "depends-on-simple-module.jar"), mfBar); Module m1 = mgr.create(j1, null, false, false, false); Module m2 = mgr.create(j2, null, false, false, false); + assertProvidesRequires(m2, "org.bar", "org.foo"); HashSet b = new HashSet(Arrays.asList(m1, m2)); mgr.enable(b); both = b; @@ -93,4 +96,18 @@ } } + private static void assertProvidesRequires(Module m, String provides, String requires) { + List p = Arrays.asList(m.getProvides()); + assertTrue("Bundles provide their packages: " + p, p.contains(provides)); + + for (Dependency d : m.getDependencies()) { + if (d.getType() == Dependency.TYPE_RECOMMENDS) { + if (requires.equals(d.getName())) { + return; + } + } + } + fail("Module " + m + " does not require " + requires); + } + } diff -r 1d9013023a29 core.netigso/test/unit/src/org/netbeans/core/netigso/NetigsoOSGiCanRequestTest.java --- a/core.netigso/test/unit/src/org/netbeans/core/netigso/NetigsoOSGiCanRequestTest.java Mon Apr 16 07:57:16 2012 +0200 +++ b/core.netigso/test/unit/src/org/netbeans/core/netigso/NetigsoOSGiCanRequestTest.java Mon Apr 16 18:20:27 2012 +0200 @@ -45,10 +45,12 @@ import java.io.File; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import org.netbeans.MockEvents; import org.netbeans.MockModuleInstaller; import org.netbeans.Module; import org.netbeans.ModuleManager; +import org.openide.modules.Dependency; /** * @@ -78,6 +80,9 @@ File j2 = changeManifest(new File(jars, "depends-on-simple-module.jar"), mfBar); Module m1 = mgr.create(j1, null, false, false, false); Module m2 = mgr.create(j2, null, false, false, false); + + assertProvidesRequires(m2, "org.bar", "org.foo"); + HashSet b = new HashSet(Arrays.asList(m1, m2)); mgr.enable(b); both = b; @@ -93,5 +98,21 @@ mgr.mutexPrivileged().exitWriteAccess(); } } + private static void assertProvidesRequires(Module m, String provides, String requires) { + List p = Arrays.asList(m.getProvides()); + assertTrue("Bundles provide their packages: " + p, p.contains(provides)); + + for (Dependency d : m.getDependencies()) { + if (d.getType() == Dependency.TYPE_RECOMMENDS) { + if (!d.getName().startsWith("cnb.")) { + continue; + } + if (requires.equals(d.getName().substring(4))) { + return; + } + } + } + fail("Module " + m + " does not require " + requires); + } } diff -r 1d9013023a29 o.n.bootstrap/nbproject/project.xml --- a/o.n.bootstrap/nbproject/project.xml Mon Apr 16 07:57:16 2012 +0200 +++ b/o.n.bootstrap/nbproject/project.xml Mon Apr 16 18:20:27 2012 +0200 @@ -54,7 +54,7 @@ - 7.25 + 7.30 diff -r 1d9013023a29 o.n.bootstrap/src/org/netbeans/ModuleData.java --- a/o.n.bootstrap/src/org/netbeans/ModuleData.java Mon Apr 16 07:57:16 2012 +0200 +++ b/o.n.bootstrap/src/org/netbeans/ModuleData.java Mon Apr 16 18:20:27 2012 +0200 @@ -51,6 +51,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; @@ -130,7 +131,7 @@ String bld = attr.getValue("OpenIDE-Module-Build-Version"); // NOI18N buildVersion = bld == null ? implVersion : bld; - this.provides = computeProvides(forModule, attr, verifyCNBs); + this.provides = computeProvides(forModule, attr, verifyCNBs, false); // Exports String exportsS = attr.getValue("OpenIDE-Module-Public-Packages"); // NOI18N @@ -237,8 +238,8 @@ this.buildVersion = bld == null ? implVersion : bld; this.friendNames = Collections.emptySet(); this.publicPackages = null; - this.provides = computeProvides(m, mf.getMainAttributes(), false); - this.dependencies = null; + this.provides = computeProvides(m, mf.getMainAttributes(), false, true); + this.dependencies = computeImported(mf.getMainAttributes()); this.coveredPackages = new HashSet(); } @@ -274,16 +275,81 @@ Module.PackageExport.write(dos, publicPackages); } - private String[] computeProvides(Module forModule, Attributes attr, boolean verifyCNBs) throws InvalidException, IllegalArgumentException { - String[] arr; + private Dependency[] computeImported(Attributes attr) { + String pkgs = attr.getValue("Import-Package"); // NOI18N + List arr = null; + if (pkgs != null) { + arr = new ArrayList(); + StringTokenizer tok = createTokenizer(pkgs); // NOI18N + while (tok.hasMoreElements()) { + String dep = beforeSemicolon(tok); + arr.addAll(Dependency.create(Dependency.TYPE_RECOMMENDS, dep)); + } + } + String recomm = attr.getValue("Require-Bundle"); // NOI18N + if (recomm != null) { + if (arr == null) { + arr = new ArrayList(); + } + StringTokenizer tok = createTokenizer(recomm); // NOI18N + while (tok.hasMoreElements()) { + String dep = beforeSemicolon(tok); + arr.addAll(Dependency.create(Dependency.TYPE_RECOMMENDS, "cnb." + dep)); // NOI18N + } + } + return arr == null ? null : arr.toArray(new Dependency[0]); + } + + private static StringTokenizer createTokenizer(String osgiDep) { + for (;;) { + int first = osgiDep.indexOf('"'); + if (first == -1) { + break; + } + int second = osgiDep.indexOf('"', first + 1); + if (second == -1) { + break; + } + osgiDep = osgiDep.substring(0, first - 1) + osgiDep.substring(second + 1); + } + + return new StringTokenizer(osgiDep, ","); + } + + private static String beforeSemicolon(StringTokenizer tok) { + String dep = tok.nextToken().trim(); + int semicolon = dep.indexOf(';'); + if (semicolon >= 0) { + dep = dep.substring(0, semicolon); + } + return dep; + } + + private String[] computeExported(boolean useOSGi, Collection arr, Attributes attr) { + if (!useOSGi) { + return arr.toArray(ZERO_STRING_ARRAY); + } + String pkgs = attr.getValue("Export-Package"); // NOI18N + if (pkgs == null) { + return arr.toArray(ZERO_STRING_ARRAY); + } + StringTokenizer tok = createTokenizer(pkgs); // NOI18N + while (tok.hasMoreElements()) { + arr.add(beforeSemicolon(tok)); + } + return arr.toArray(ZERO_STRING_ARRAY); + } + + private String[] computeProvides( + Module forModule, Attributes attr, boolean verifyCNBs, boolean useOSGi + ) throws InvalidException, IllegalArgumentException { + Set arr = new LinkedHashSet(); // Token provides String providesS = attr.getValue("OpenIDE-Module-Provides"); // NOI18N - if (providesS == null) { - arr = ZERO_STRING_ARRAY; - } else { + if (providesS != null) { StringTokenizer tok = new StringTokenizer(providesS, ", "); // NOI18N - arr = new String[tok.countTokens()]; - for (int i = 0; i < arr.length; i++) { + int expCount = tok.countTokens(); + while (tok.hasMoreTokens()) { String provide = tok.nextToken(); if (provide.indexOf(',') != -1) { throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); // NOI18N @@ -292,24 +358,18 @@ Dependency.create(Dependency.TYPE_MODULE, provide); } if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Provides: " + provide); // NOI18N - arr[i] = provide; + arr.add(provide); } - if (new HashSet(Arrays.asList(arr)).size() < arr.length) { + if (arr.size() != expCount) { throw new IllegalArgumentException("Duplicate entries in OpenIDE-Module-Provides: " + providesS); // NOI18N } } String[] additionalProvides = forModule.getManager().refineProvides (forModule); if (additionalProvides != null) { - if (arr == null) { - arr = additionalProvides; - } else { - ArrayList l = new ArrayList (); - l.addAll (Arrays.asList (arr)); - l.addAll (Arrays.asList (additionalProvides)); - arr = l.toArray (arr); - } + arr.addAll (Arrays.asList (additionalProvides)); } - return arr; + arr.add("cnb." + getCodeNameBase()); // NOI18N + return computeExported(useOSGi, arr, attr); } /** diff -r 1d9013023a29 o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java --- a/o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java Mon Apr 16 07:57:16 2012 +0200 +++ b/o.n.bootstrap/test/unit/src/org/netbeans/ModuleManagerTest.java Mon Apr 16 18:20:27 2012 +0200 @@ -134,6 +134,8 @@ Module m1 = mgr.create(new File(jars, "simple-module.jar"), null, false, false, false); assertEquals("org.foo", m1.getCodeNameBase()); assertEquals("org.bar", m2.getCodeNameBase()); + assertCnb(m1); + assertCnb(m2); assertEquals(Collections.EMPTY_SET, m1.getDependencies()); assertEquals(Dependency.create(Dependency.TYPE_MODULE, "org.foo/1"), m2.getDependencies()); Map modulesByName = new HashMap(); @@ -902,8 +904,8 @@ try { Module m1 = mgr.create(new File(jars, "prov-foo.jar"), null, false, false, false); Module m2 = mgr.create(new File(jars, "req-foo.jar"), null, false, false, false); - assertEquals(Collections.singletonList("foo"), Arrays.asList(m1.getProvides())); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(m2.getProvides())); + assertEquals(Collections.singletonList("foo"), assertCnb(m1)); + assertEquals(Collections.EMPTY_LIST, assertCnb(m2)); assertEquals(Collections.EMPTY_SET, m1.getDependencies()); assertEquals(Dependency.create(Dependency.TYPE_REQUIRES, "foo"), m2.getDependencies()); Map modulesByName = new HashMap(); @@ -1134,8 +1136,8 @@ } else { m2 = mgr.create(new File(jars, "needs-foo.jar"), null, false, false, false); } - assertEquals(Collections.singletonList("foo"), Arrays.asList(m1.getProvides())); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(m2.getProvides())); + assertEquals(Collections.singletonList("foo"), assertCnb(m1)); + assertEquals(Collections.EMPTY_LIST, assertCnb(m2)); assertEquals(1, m1.getDependencies().size()); int type = recommends ? Dependency.TYPE_RECOMMENDS : Dependency.TYPE_NEEDS; assertEquals(Dependency.create(type, "foo"), m2.getDependencies()); @@ -1321,8 +1323,8 @@ "OpenIDE-Module-Recommends: foo\n"; m3 = mgr.create(copyJar(m2.getJarFile(), manifest), null, false, false, false); } - assertEquals(Collections.singletonList("foo"), Arrays.asList(m1.getProvides())); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(m2.getProvides())); + assertEquals(Collections.singletonList("foo"), assertCnb(m1)); + assertEquals(Collections.EMPTY_LIST, assertCnb(m2)); assertEquals(1, m1.getDependencies().size()); int type = recommends ? Dependency.TYPE_RECOMMENDS : Dependency.TYPE_NEEDS; assertEquals(Dependency.create(type, "foo"), m2.getDependencies()); @@ -1401,7 +1403,7 @@ mgr.mutexPrivileged().enterWriteAccess(); try { Module m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(m2.getProvides())); + assertEquals(Collections.EMPTY_LIST, assertCnb(m2)); assertEquals(Dependency.create(Dependency.TYPE_RECOMMENDS, "foo"), m2.getDependencies()); Map modulesByName = new HashMap(); modulesByName.put(m2.getCodeNameBase(), m2); @@ -1457,7 +1459,7 @@ mgr.mutexPrivileged().enterWriteAccess(); try { Module m2 = mgr.create(new File(jars, "recommends-foo.jar"), null, false, false, false); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(m2.getProvides())); + assertEquals(Collections.EMPTY_LIST, assertCnb(m2)); Module m1; { @@ -2717,4 +2719,18 @@ return mgr.createFixed(new Manifest(new ByteArrayInputStream(manifest.getBytes())), null, ModuleManagerTest.class.getClassLoader()); } + private static Collection assertCnb(Module m) { + String token = "cnb." + m.getCodeNameBase(); + List arr = new ArrayList(); + boolean ok = false; + for (String t : m.getProvides()) { + if (token.equals(t)) { + ok = true; + } else { + arr.add(t); + } + } + assertTrue(token + " is not among the list of provides of module " + m + " which is " + arr, ok); + return arr; + } } diff -r 1d9013023a29 openide.modules/apichanges.xml --- a/openide.modules/apichanges.xml Mon Apr 16 07:57:16 2012 +0200 +++ b/openide.modules/apichanges.xml Mon Apr 16 18:20:27 2012 +0200 @@ -50,6 +50,30 @@ Modules API + + + By default each module provides its code name base as token + + + + +

+ Unless accidental class in the name of the token with + cnb. prefix, the change is compatible. +

+
+ +

+ Each module provides by default a token composed from its + code name base as + "cnb." + getCodeNameBase() + from its getProvides() + method. +

+
+ + +
OnStart and OnStop