changeset 14621:9fdbe1e7defa

Merge
author mchung
date Tue, 01 Dec 2015 09:12:06 -0800
parents a22701474f29 dbd2f64d6653
children 66677a0b82a9 a963f1042b33
files
diffstat 15 files changed, 495 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Tue Dec 01 09:09:26 2015 -0800
+++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Tue Dec 01 09:12:06 2015 -0800
@@ -1060,7 +1060,7 @@
             hc = hc * 43 + Objects.hashCode(mainClass);
             hc = hc * 43 + Objects.hashCode(conceals);
             hc = hc * 43 + Objects.hashCode(hashes);
-            hash = hc;
+            if (hc != 0) hash = hc;
         }
         return hc;
     }
--- a/src/java.base/share/classes/java/lang/module/ModuleReference.java	Tue Dec 01 09:09:26 2015 -0800
+++ b/src/java.base/share/classes/java/lang/module/ModuleReference.java	Tue Dec 01 09:12:06 2015 -0800
@@ -174,7 +174,7 @@
         int hc = hash;
         if (hc == 0) {
             hc = Objects.hash(descriptor, location, readerSupplier, hasher);
-            hash = hc;
+            if (hc != 0) hash = hc;
         }
         return hc;
     }
--- a/src/java.base/share/classes/java/lang/module/Resolver.java	Tue Dec 01 09:09:26 2015 -0800
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Tue Dec 01 09:12:06 2015 -0800
@@ -323,18 +323,18 @@
     /**
      * Poll the given {@code Deque} for modules to resolve. On completion the
      * {@code Deque} will be empty and any selected modules will be added to
-     * the given Resolution.
+     * the Selected.
      *
-     * @return The set of module selected by this invocation of resolve
+     * @return The set of module resolved by this invocation of resolve
      */
     private Set<ModuleDescriptor> resolve(Deque<ModuleDescriptor> q,
                                           Selected selected)
     {
-
-        Set<ModuleDescriptor> newlySelected = new HashSet<>();
+        Set<ModuleDescriptor> resolved = new HashSet<>();
 
         while (!q.isEmpty()) {
             ModuleDescriptor descriptor = q.poll();
+            assert selected.contains(descriptor.name());
 
             // process dependences
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
@@ -356,7 +356,7 @@
                 if (!selected.contains(dn)) {
                     selected.add(mref);
                     q.offer(mref.descriptor());
-                    newlySelected.add(mref.descriptor());
+                    resolved.add(mref.descriptor());
 
                     if (TRACE) {
                         trace("Module %s located, required by %s",
@@ -367,9 +367,11 @@
                 }
 
             }
+
+            resolved.add(descriptor);
         }
 
-        return newlySelected;
+        return resolved;
     }
 
 
--- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Tue Dec 01 09:09:26 2015 -0800
+++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Tue Dec 01 09:12:06 2015 -0800
@@ -187,7 +187,7 @@
 
             // early VM startup case, java.base not defined
             if (lookupModule == null) {
-                if (refModule != null) throw new InternalError();
+                assert refModule == null;
                 return true;
             }
 
@@ -195,7 +195,11 @@
                 return false;
 
             // check the package is exported unconditionally
-            if (refModule.isExported(getPackageName(refc)))
+            Class<?> c = refc;
+            while (c.isArray()) {
+                c = c.getComponentType();
+            }
+            if (c.isPrimitive() || refModule.isExported(c.getPackageName()))
                 return true;
 
             // not exported but allow access during VM initialization
@@ -288,14 +292,11 @@
     /** Return the package name for this class.
      */
     public static String getPackageName(Class<?> cls) {
-        if (cls.isArray()) {
-            return getPackageName(cls.getComponentType());
-        } else {
-            String name = cls.getName();
-            int dot = name.lastIndexOf('.');
-            if (dot < 0) return "";
-            return name.substring(0, dot);
-        }
+        assert (!cls.isArray());
+        String name = cls.getName();
+        int dot = name.lastIndexOf('.');
+        if (dot < 0) return "";
+        return name.substring(0, dot);
     }
 
     /**
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue Dec 01 09:09:26 2015 -0800
+++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue Dec 01 09:12:06 2015 -0800
@@ -58,7 +58,7 @@
 \    -limitmods <modulename>[,<modulename>...]\n\
 \                  limit the universe of observable modules\n\
 \    -listmods[:<modulename>[,<modulename>...]]\n\
-\                  list the observable modules\n\
+\                  list the observable modules and exit\n\
 \    -D<name>=<value>\n\
 \                  set a system property\n\
 \    -verbose:[class|gc|jni]\n\
--- a/src/java.base/share/classes/sun/reflect/Reflection.java	Tue Dec 01 09:09:26 2015 -0800
+++ b/src/java.base/share/classes/sun/reflect/Reflection.java	Tue Dec 01 09:12:06 2015 -0800
@@ -104,7 +104,12 @@
             if (m2.isNamed())
                 memberSuffix = " (in " + m2 + ")";
 
-            String memberPackageName = packageName(memberClass);
+            Class<?> c = memberClass;
+            while (c.isArray()) {
+                c = c.getComponentType();
+            }
+            String memberPackageName = c.getPackageName();
+
             boolean canRead = m1.canRead(m2);
 
             String msg = currentClass + currentSuffix + " cannot access ";
@@ -234,17 +239,16 @@
         if (!currentModule.canRead(memberModule))
             return false;
 
+        // memberClass may be primitive or array class
+        Class<?> c = memberClass;
+        while (c.isArray()) {
+            c = c.getComponentType();
+        }
+        if (c.isPrimitive())
+            return true;
+
         // check that memberModule exports the package to currentModule
-        return memberModule.isExported(packageName(memberClass), currentModule);
-    }
-
-    private static String packageName(Class<?> c) {
-        String pn = c.getPackageName();
-        if (pn != null) {
-            return pn;
-        } else {
-            throw new InternalError("Should not get here: " + c);
-        }
+        return memberModule.isExported(c.getPackageName(), currentModule);
     }
 
     private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/Main.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Layer;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Basic test of ClassLoader getResource and getResourceAsStream when
+ * invoked from code in named modules.
+ */
+
+public class Main {
+
+    static final String NAME = "myresource";
+
+    public static void main(String[] args) throws IOException {
+
+        // create m1/myresource containing "m1"
+        Path file = directoryFor("m1").resolve(NAME);
+        Files.write(file, "m1".getBytes("UTF-8"));
+
+        // create m2/myresource containing "m2"
+        file = directoryFor("m2").resolve(NAME);
+        Files.write(file, "m2".getBytes("UTF-8"));
+
+        // check that m3/myresource does not exist
+        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
+
+        // invoke ClassLoader getResource from the unnamed module
+        assertNull(Main.class.getClassLoader().getResource("/" + NAME));
+
+        // invoke ClassLoader getResource from modules m1-m3
+        // Resources in a named module are private to that module.
+        // ClassLoader.getResource should not find resource in named modules.
+        assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
+
+        // invoke ClassLoader getResourceAsStream from the unnamed module
+        assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
+
+        // invoke ClassLoader getResourceAsStream from modules m1-m3
+        // Resources in a named module are private to that module.
+        // ClassLoader.getResourceAsStream should not find resource in named modules.
+        assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
+
+        // SecurityManager case
+        System.setSecurityManager(new SecurityManager());
+
+        assertNull(Main.class.getClassLoader().getResource("/" + NAME));
+        assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
+
+        assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
+        assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
+
+        System.out.println("Success!");
+    }
+
+    /**
+     * Returns the directory for the given module (by name).
+     */
+    static Path directoryFor(String mn) {
+        Configuration cf = Layer.boot().configuration();
+        ModuleReference mref = cf.findModule(mn).orElse(null);
+        if (mref == null)
+            throw new RuntimeException("not found: " + mn);
+        Path dir = Paths.get(mref.location().get());
+        if (!Files.isDirectory(dir))
+            throw new RuntimeException("not a directory: " + dir);
+        return dir;
+    }
+
+    static void assertTrue(boolean condition) {
+        if (!condition) throw new RuntimeException();
+    }
+
+    static void assertNull(Object o) {
+        assertTrue(o == null);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static jdk.testlibrary.ProcessTools.executeTestJava;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8087335
+ * @library /jdk/jigsaw/lib /lib/testlibrary
+ * @modules jdk.compiler
+ * @build ResourcesTest CompilerUtils jdk.testlibrary.*
+ * @run testng ResourcesTest
+ * @summary Driver for basic test of ClassLoader getResource and getResourceAsStream
+ */
+
+@Test
+public class ResourcesTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    /**
+     * Compiles the modules used by the test and the test Main
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        boolean compiled;
+
+        // javac -modulesource mods -d mods src/**
+        compiled = CompilerUtils
+            .compile(SRC_DIR,
+                     MODS_DIR,
+                     "-modulesourcepath", SRC_DIR.toString());
+        assertTrue(compiled);
+
+        // javac -mp mods -d classes Main.java
+        compiled = CompilerUtils
+            .compile(Paths.get(TEST_SRC, "Main.java"),
+                     CLASSES_DIR,
+                     "-mp", MODS_DIR.toString());
+        assertTrue(compiled);
+    }
+
+    /**
+     * Run the test
+     */
+    public void runTest() throws Exception {
+        int exitValue
+            = executeTestJava("-mp", MODS_DIR.toString(),
+                              "-addmods", "m1,m2,m3",
+                               "-cp", CLASSES_DIR.toString(),
+                              "Main")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResourceInClassLoader(String name) {
+        return Main.class.getClassLoader().getResource(name);
+    }
+
+    public static InputStream getResourceAsStreamInClassLoader(String name) {
+        return Main.class.getClassLoader().getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports p2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResourceInClassLoader(String name) {
+        return Main.class.getClassLoader().getResource(name);
+    }
+
+    public static InputStream getResourceAsStreamInClassLoader(String name) {
+        return Main.class.getClassLoader().getResourceAsStream(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    exports p3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java	Tue Dec 01 09:12:06 2015 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class Main {
+    private Main() { }
+
+    public static URL getResourceInClassLoader(String name) {
+        return Main.class.getClassLoader().getResource(name);
+    }
+
+    public static InputStream getResourceAsStreamInClassLoader(String name) {
+        return Main.class.getClassLoader().getResourceAsStream(name);
+    }
+}
--- a/test/jdk/jigsaw/module/ConfigurationTest.java	Tue Dec 01 09:09:26 2015 -0800
+++ b/test/jdk/jigsaw/module/ConfigurationTest.java	Tue Dec 01 09:12:06 2015 -0800
@@ -433,6 +433,8 @@
 
     /**
      * Basic test of binding services
+     *     m1 uses p.Service
+     *     m2 provides p.Service
      */
     public void testServiceBinding1() {
 
@@ -473,24 +475,75 @@
         assertTrue(cf.findModule("m1").isPresent());
         assertTrue(cf.findModule("m2").isPresent());
 
-        assertEquals(cf.modules().stream()
-                        .map(ModuleReference::descriptor)
-                        .collect(Collectors.toSet()),
-                cf.descriptors());
-
         assertTrue(cf.provides("p.Service").size() == 1);
         assertTrue(cf.provides("p.Service").contains(descriptor2));
     }
 
 
     /**
+     * Basic test of binding services
+     *     m1 uses p.Service1
+     *     m2 provides p.Service1, m2 uses p.Service2
+     *     m3 provides p.Service2
+     */
+    public void testServiceBinding2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .uses("p.Service1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .uses("p.Service2")
+                .provides("p.Service1", "q.Service1Impl")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .provides("p.Service2", "q.Service2Impl")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf
+            = Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m1");
+
+        // only m1 in configuration
+        assertTrue(cf.descriptors().size() == 1);
+        assertTrue(cf.findModule("m1").isPresent());
+
+        assertTrue(cf.parent().get() == empty());
+
+        assertTrue(cf.provides("p.Service1").isEmpty());
+
+        // bind services, should augment graph with m2 and m3
+        cf = cf.bind();
+
+        assertTrue(cf.parent().get() == empty());
+
+        assertTrue(cf.descriptors().size() == 3);
+        assertTrue(cf.findModule("m1").isPresent());
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+
+        assertTrue(cf.provides("p.Service1").size() == 1);
+        assertTrue(cf.provides("p.Service1").contains(descriptor2));
+
+        assertTrue(cf.provides("p.Service2").size() == 1);
+        assertTrue(cf.provides("p.Service2").contains(descriptor3));
+    }
+
+
+    /**
      * Basic test of binding services with configurations.
      *
      * The test consists of two configurations:
      * - Configuration cf1: m1 uses p.Service
      * - Configuration cf2: m2 provides p.Service
      */
-    public void testServiceBinding2() {
+    public void testServiceBindingWithConfigurations1() {
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
@@ -537,7 +590,7 @@
      * - Configuration cf2: m3 provides p.Service
      *                      m4 provides p.Service
      */
-    public void testServiceBinding3() {
+    public void testServiceBindingWithConfigurations2() {
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
@@ -609,7 +662,7 @@
      * Test configuration cf2: m1 uses p.Service
      * Test configuration cf2: m1 uses p.Service, p@2.0 uses p.Service
      */
-    public void testServiceBinding4() {
+    public void testServiceBindingWithConfigurations3() {
 
         ModuleDescriptor provider_v1
             = new ModuleDescriptor.Builder("p")