Path: blob/master/test/jdk/java/util/ServiceLoader/ModulesTest.java
41149 views
/*1* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @modules java.scripting26* @library modules /test/lib27* @build bananascript/*28* @build jdk.test.lib.util.JarUtils29* @compile classpath/pearscript/org/pear/PearScriptEngineFactory.java30* classpath/pearscript/org/pear/PearScript.java31* @run testng/othervm ModulesTest32* @summary Basic test for ServiceLoader with a provider deployed as a module.33*/3435import java.io.File;36import java.lang.module.Configuration;37import java.lang.module.ModuleFinder;38import java.nio.file.Files;39import java.nio.file.Path;40import java.nio.file.Paths;41import java.nio.file.StandardCopyOption;42import java.util.ArrayList;43import java.util.Collections;44import java.util.HashSet;45import java.util.Iterator;46import java.util.List;47import java.util.Optional;48import java.util.ServiceLoader;49import java.util.ServiceLoader.Provider;50import java.util.Set;51import java.util.stream.Collectors;52import java.util.stream.Stream;53import javax.script.ScriptEngineFactory;5455import jdk.test.lib.util.JarUtils;5657import org.testng.annotations.Test;58import org.testng.annotations.BeforeTest;59import static org.testng.Assert.*;6061/**62* Basic test for ServiceLoader. The test make use of two service providers:63* 1. BananaScriptEngine - a ScriptEngineFactory deployed as a module on the64* module path. It implementations a singleton via the public static65* provider method.66* 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path67* with a service configuration file.68*/6970public class ModulesTest {7172// Copy the services configuration file for "pearscript" into place.73@BeforeTest74public void setup() throws Exception {75Path src = Paths.get(System.getProperty("test.src"));76Path classes = Paths.get(System.getProperty("test.classes"));77String st = ScriptEngineFactory.class.getName();78Path config = Paths.get("META-INF", "services", st);79Path source = src.resolve("classpath").resolve("pearscript").resolve(config);80Path target = classes.resolve(config);81Files.createDirectories(target.getParent());82Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);83}8485/**86* Basic test of iterator() to ensure that providers located as modules87* and on the class path are found.88*/89@Test90public void testIterator() {91ServiceLoader<ScriptEngineFactory> loader92= ServiceLoader.load(ScriptEngineFactory.class);93Set<String> names = collectAll(loader)94.stream()95.map(ScriptEngineFactory::getEngineName)96.collect(Collectors.toSet());97assertTrue(names.contains("BananaScriptEngine"));98assertTrue(names.contains("PearScriptEngine"));99}100101/**102* Basic test of iterator() to test iteration order. Providers deployed103* as named modules should be found before providers deployed on the class104* path.105*/106@Test107public void testIteratorOrder() {108ServiceLoader<ScriptEngineFactory> loader109= ServiceLoader.load(ScriptEngineFactory.class);110boolean foundUnnamed = false;111for (ScriptEngineFactory factory : collectAll(loader)) {112if (factory.getClass().getModule().isNamed()) {113if (foundUnnamed) {114assertTrue(false, "Named module element after unnamed");115}116} else {117foundUnnamed = true;118}119}120}121122/**123* Basic test of Provider::type124*/125@Test126public void testProviderType() {127Set<String> types = ServiceLoader.load(ScriptEngineFactory.class)128.stream()129.map(Provider::type)130.map(Class::getName)131.collect(Collectors.toSet());132assertTrue(types.contains("org.banana.BananaScriptEngineFactory"));133assertTrue(types.contains("org.pear.PearScriptEngineFactory"));134}135136/**137* Basic test of Provider::get138*/139@Test140public void testProviderGet() {141Set<String> names = ServiceLoader.load(ScriptEngineFactory.class)142.stream()143.map(Provider::get)144.map(ScriptEngineFactory::getEngineName)145.collect(Collectors.toSet());146assertTrue(names.contains("BananaScriptEngine"));147assertTrue(names.contains("PearScriptEngine"));148}149150/**151* Basic test of the public static provider method. BananaScriptEngine152* defines a provider method that returns the same instance.153*/154@Test155public void testSingleton() {156Optional<Provider<ScriptEngineFactory>> oprovider157= ServiceLoader.load(ScriptEngineFactory.class)158.stream()159.filter(p -> p.type().getName().equals("org.banana.BananaScriptEngineFactory"))160.findFirst();161assertTrue(oprovider.isPresent());162Provider<ScriptEngineFactory> provider = oprovider.get();163164// invoke Provider::get twice165ScriptEngineFactory factory1 = provider.get();166ScriptEngineFactory factory2 = provider.get();167assertTrue(factory1 == factory2);168}169170/**171* Basic test of stream() to ensure that elements for providers in named172* modules come before elements for providers in unnamed modules.173*/174@Test175public void testStreamOrder() {176List<Class<?>> types = ServiceLoader.load(ScriptEngineFactory.class)177.stream()178.map(Provider::type)179.collect(Collectors.toList());180181boolean foundUnnamed = false;182for (Class<?> factoryClass : types) {183if (factoryClass.getModule().isNamed()) {184if (foundUnnamed) {185assertTrue(false, "Named module element after unnamed");186}187} else {188foundUnnamed = true;189}190}191}192193/**194* Basic test of ServiceLoader.findFirst()195*/196@Test197public void testFindFirst() {198Optional<ScriptEngineFactory> ofactory199= ServiceLoader.load(ScriptEngineFactory.class).findFirst();200assertTrue(ofactory.isPresent());201ScriptEngineFactory factory = ofactory.get();202assertTrue(factory.getClass().getModule().isNamed());203204class S { }205assertFalse(ServiceLoader.load(S.class).findFirst().isPresent());206}207208/**209* Basic test ServiceLoader.load specifying the platform class loader.210* The providers on the module path and class path should not be located.211*/212@Test213public void testWithPlatformClassLoader() {214ClassLoader pcl = ClassLoader.getPlatformClassLoader();215216// iterator217ServiceLoader<ScriptEngineFactory> loader218= ServiceLoader.load(ScriptEngineFactory.class, pcl);219Set<String> names = collectAll(loader)220.stream()221.map(ScriptEngineFactory::getEngineName)222.collect(Collectors.toSet());223assertFalse(names.contains("BananaScriptEngine"));224assertFalse(names.contains("PearScriptEngine"));225226// stream227names = ServiceLoader.load(ScriptEngineFactory.class, pcl)228.stream()229.map(Provider::get)230.map(ScriptEngineFactory::getEngineName)231.collect(Collectors.toSet());232assertFalse(names.contains("BananaScriptEngine"));233assertFalse(names.contains("PearScriptEngine"));234}235236/**237* Basic test of ServiceLoader.load where the service provider module is an238* automatic module.239*/240@Test241public void testWithAutomaticModule() throws Exception {242Path here = Paths.get("");243Path jar = Files.createTempDirectory(here, "lib").resolve("pearscript.jar");244Path classes = Paths.get(System.getProperty("test.classes"));245246JarUtils.createJarFile(jar, classes, "META-INF", "org");247248ModuleFinder finder = ModuleFinder.of(jar);249ModuleLayer bootLayer = ModuleLayer.boot();250Configuration parent = bootLayer.configuration();251Configuration cf = parent.resolveAndBind(finder, ModuleFinder.of(), Set.of());252assertTrue(cf.modules().size() == 1);253254ClassLoader scl = ClassLoader.getSystemClassLoader();255ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);256assertTrue(layer.modules().size() == 1);257258ClassLoader loader = layer.findLoader("pearscript");259ScriptEngineFactory factory;260261// load using the class loader as context262factory = ServiceLoader.load(ScriptEngineFactory.class, loader)263.findFirst()264.orElse(null);265assertNotNull(factory);266assertTrue(factory.getClass().getClassLoader() == loader);267268// load using the layer as context269factory = ServiceLoader.load(layer, ScriptEngineFactory.class)270.findFirst()271.orElse(null);272assertNotNull(factory);273assertTrue(factory.getClass().getClassLoader() == loader);274}275276/**277* Basic test of ServiceLoader.load, using the class loader for278* a module in a custom layer as the context.279*/280@Test281public void testWithCustomLayer1() {282ModuleLayer layer = createCustomLayer("bananascript");283284ClassLoader loader = layer.findLoader("bananascript");285List<ScriptEngineFactory> providers286= collectAll(ServiceLoader.load(ScriptEngineFactory.class, loader));287288// should have at least 2 x bananascript + pearscript289assertTrue(providers.size() >= 3);290291// first element should be the provider in the custom layer292ScriptEngineFactory factory = providers.get(0);293assertTrue(factory.getClass().getClassLoader() == loader);294assertTrue(factory.getClass().getModule().getLayer() == layer);295assertTrue(factory.getEngineName().equals("BananaScriptEngine"));296297// remainder should be the boot layer298providers.remove(0);299Set<String> names = providers.stream()300.map(ScriptEngineFactory::getEngineName)301.collect(Collectors.toSet());302assertTrue(names.contains("BananaScriptEngine"));303assertTrue(names.contains("PearScriptEngine"));304}305306/**307* Basic test of ServiceLoader.load using a custom Layer as the context.308*/309@Test310public void testWithCustomLayer2() {311ModuleLayer layer = createCustomLayer("bananascript");312313List<ScriptEngineFactory> factories314= collectAll(ServiceLoader.load(layer, ScriptEngineFactory.class));315316// should have at least 2 x bananascript317assertTrue(factories.size() >= 2);318319// first element should be the provider in the custom layer320ScriptEngineFactory factory = factories.get(0);321assertTrue(factory.getClass().getModule().getLayer() == layer);322assertTrue(factory.getEngineName().equals("BananaScriptEngine"));323324// remainder should be the boot layer325factories.remove(0);326Set<String> names = factories.stream()327.map(ScriptEngineFactory::getEngineName)328.collect(Collectors.toSet());329assertTrue(names.contains("BananaScriptEngine"));330assertFalse(names.contains("PearScriptEngine"));331}332333/**334* Basic test of ServiceLoader.load with a tree of layers.335*336* Test scenario:337* - boot layer contains "bananascript", maybe other script engines338* - layer1, with boot layer as parent, contains "bananascript"339* - layer2, with boot layer as parent, contains "bananascript"340* - layer3, with layer1 ad layer as parents, contains "bananascript"341*342* ServiceLoader should locate all 4 script engine factories in DFS order.343*/344@Test345public void testWithCustomLayer3() {346ModuleLayer bootLayer = ModuleLayer.boot();347Configuration cf0 = bootLayer.configuration();348349// boot layer should contain "bananascript"350List<ScriptEngineFactory> factories351= collectAll(ServiceLoader.load(bootLayer, ScriptEngineFactory.class));352int countInBootLayer = factories.size();353assertTrue(countInBootLayer >= 1);354assertTrue(factories.stream()355.map(p -> p.getEngineName())356.filter("BananaScriptEngine"::equals)357.findAny()358.isPresent());359360ClassLoader scl = ClassLoader.getSystemClassLoader();361ModuleFinder finder = ModuleFinder.of(testModulePath());362363// layer1364Configuration cf1 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of());365ModuleLayer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl);366assertTrue(layer1.modules().size() == 1);367368// layer2369Configuration cf2 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of());370ModuleLayer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl);371assertTrue(layer2.modules().size() == 1);372373// layer3 with layer1 and layer2 as parents374Configuration cf3 = Configuration.resolveAndBind(finder,375List.of(cf1, cf2),376ModuleFinder.of(),377Set.of());378ModuleLayer layer3379= ModuleLayer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer();380assertTrue(layer3.modules().size() == 1);381382383// class loaders384ClassLoader loader1 = layer1.findLoader("bananascript");385ClassLoader loader2 = layer2.findLoader("bananascript");386ClassLoader loader3 = layer3.findLoader("bananascript");387assertTrue(loader1 != loader2);388assertTrue(loader1 != loader3);389assertTrue(loader2 != loader3);390391// load all factories with layer3 as the context392factories = collectAll(ServiceLoader.load(layer3, ScriptEngineFactory.class));393int count = factories.size();394assertTrue(count == countInBootLayer + 3);395396// the ordering should be layer3, layer1, boot layer, layer2397398ScriptEngineFactory factory = factories.get(0);399assertTrue(factory.getClass().getModule().getLayer() == layer3);400assertTrue(factory.getClass().getClassLoader() == loader3);401assertTrue(factory.getEngineName().equals("BananaScriptEngine"));402403factory = factories.get(1);404assertTrue(factory.getClass().getModule().getLayer() == layer1);405assertTrue(factory.getClass().getClassLoader() == loader1);406assertTrue(factory.getEngineName().equals("BananaScriptEngine"));407408// boot layer "bananascript" and maybe other factories409int last = count -1;410boolean found = false;411for (int i=2; i<last; i++) {412factory = factories.get(i);413assertTrue(factory.getClass().getModule().getLayer() == bootLayer);414if (factory.getEngineName().equals("BananaScriptEngine")) {415assertFalse(found);416found = true;417}418}419assertTrue(found);420421factory = factories.get(last);422assertTrue(factory.getClass().getModule().getLayer() == layer2);423assertTrue(factory.getClass().getClassLoader() == loader2);424assertTrue(factory.getEngineName().equals("BananaScriptEngine"));425}426427428// -- nulls --429430@Test(expectedExceptions = { NullPointerException.class })431public void testLoadNull1() {432ServiceLoader.load(null);433}434435@Test(expectedExceptions = { NullPointerException.class })436public void testLoadNull2() {437ServiceLoader.load((Class<?>) null, ClassLoader.getSystemClassLoader());438}439440@Test(expectedExceptions = { NullPointerException.class })441public void testLoadNull3() {442class S { }443ServiceLoader.load((ModuleLayer) null, S.class);444}445446@Test(expectedExceptions = { NullPointerException.class })447public void testLoadNull4() {448ServiceLoader.load(ModuleLayer.empty(), null);449}450451@Test(expectedExceptions = { NullPointerException.class })452public void testLoadNull5() {453ServiceLoader.loadInstalled(null);454}455456/**457* Create a custom layer by resolving the given module names. The modules458* are located on the test module path ({@code ${test.module.path}}).459*/460private ModuleLayer createCustomLayer(String... modules) {461ModuleFinder finder = ModuleFinder.of(testModulePath());462Set<String> roots = new HashSet<>();463Collections.addAll(roots, modules);464ModuleLayer bootLayer = ModuleLayer.boot();465Configuration parent = bootLayer.configuration();466Configuration cf = parent.resolve(finder, ModuleFinder.of(), roots);467ClassLoader scl = ClassLoader.getSystemClassLoader();468ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);469assertTrue(layer.modules().size() == 1);470return layer;471}472473private Path[] testModulePath() {474String mp = System.getProperty("test.module.path");475return Stream.of(mp.split(File.pathSeparator))476.map(Paths::get)477.toArray(Path[]::new);478}479480private <E> List<E> collectAll(ServiceLoader<E> loader) {481List<E> list = new ArrayList<>();482Iterator<E> iterator = loader.iterator();483while (iterator.hasNext()) {484list.add(iterator.next());485}486return list;487}488}489490491492