jdk/test/java/util/ServiceLoader/modules/Basic.java
changeset 42338 a60f280f803c
child 43712 5dfd0950317c
equal deleted inserted replaced
42148:7a4a59859ac0 42338:a60f280f803c
       
     1 /*
       
     2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 /**
       
    25  * @test
       
    26  * @library modules
       
    27  * @build bananascript/*
       
    28  * @compile src/pearscript/org/pear/PearScriptEngineFactory.java
       
    29  *          src/pearscript/org/pear/PearScript.java
       
    30  * @run testng/othervm Basic
       
    31  * @summary Basic test for ServiceLoader with a provider deployed as a module.
       
    32  */
       
    33 
       
    34 import java.lang.module.Configuration;
       
    35 import java.lang.module.ModuleFinder;
       
    36 import java.lang.reflect.Layer;
       
    37 import java.nio.file.Files;
       
    38 import java.nio.file.Path;
       
    39 import java.nio.file.Paths;
       
    40 import java.nio.file.StandardCopyOption;
       
    41 import java.util.*;
       
    42 import java.util.ServiceLoader.Provider;
       
    43 import java.util.stream.Collectors;
       
    44 import javax.script.ScriptEngineFactory;
       
    45 
       
    46 import org.testng.annotations.Test;
       
    47 import org.testng.annotations.BeforeTest;
       
    48 import static org.testng.Assert.*;
       
    49 
       
    50 /**
       
    51  * Basic test for ServiceLoader. The test make use of two service providers:
       
    52  * 1. BananaScriptEngine - a ScriptEngineFactory deployed as a module on the
       
    53  *    module path. It implementations a singleton via the public static
       
    54  *    provider method.
       
    55  * 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path
       
    56  *    with a service configuration file.
       
    57  */
       
    58 
       
    59 public class Basic {
       
    60 
       
    61     // Copy the services configuration file for "pearscript" into place.
       
    62     @BeforeTest
       
    63     public void setup() throws Exception {
       
    64         Path src = Paths.get(System.getProperty("test.src", ""));
       
    65         Path classes = Paths.get(System.getProperty("test.classes", ""));
       
    66         String st = ScriptEngineFactory.class.getName();
       
    67         Path config = Paths.get("META-INF", "services", st);
       
    68         Path source = src.resolve("src").resolve("pearscript").resolve(config);
       
    69         Path target = classes.resolve(config);
       
    70         Files.createDirectories(target.getParent());
       
    71         Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
       
    72     }
       
    73 
       
    74     /**
       
    75      * Basic test of iterator() to ensure that providers located as modules
       
    76      * and on the class path are found.
       
    77      */
       
    78     @Test
       
    79     public void testIterator() {
       
    80         ServiceLoader<ScriptEngineFactory> loader
       
    81             = ServiceLoader.load(ScriptEngineFactory.class);
       
    82         Set<String> names = collectAll(loader)
       
    83                 .stream()
       
    84                 .map(ScriptEngineFactory::getEngineName)
       
    85                 .collect(Collectors.toSet());
       
    86         assertTrue(names.contains("BananaScriptEngine"));
       
    87         assertTrue(names.contains("PearScriptEngine"));
       
    88     }
       
    89 
       
    90     /**
       
    91      * Basic test of iterator() to test iteration order. Providers deployed
       
    92      * as named modules should be found before providers deployed on the class
       
    93      * path.
       
    94      */
       
    95     @Test
       
    96     public void testIteratorOrder() {
       
    97         ServiceLoader<ScriptEngineFactory> loader
       
    98             = ServiceLoader.load(ScriptEngineFactory.class);
       
    99         boolean foundUnnamed = false;
       
   100         for (ScriptEngineFactory factory : collectAll(loader)) {
       
   101             if (factory.getClass().getModule().isNamed()) {
       
   102                 if (foundUnnamed) {
       
   103                     assertTrue(false, "Named module element after unnamed");
       
   104                 }
       
   105             } else {
       
   106                 foundUnnamed = true;
       
   107             }
       
   108         }
       
   109     }
       
   110 
       
   111     /**
       
   112      * Basic test of Provider::type
       
   113      */
       
   114     @Test
       
   115     public void testProviderType() {
       
   116         Set<String> types = ServiceLoader.load(ScriptEngineFactory.class)
       
   117                 .stream()
       
   118                 .map(Provider::type)
       
   119                 .map(Class::getName)
       
   120                 .collect(Collectors.toSet());
       
   121         assertTrue(types.contains("org.banana.BananaScriptEngineFactory"));
       
   122         assertTrue(types.contains("org.pear.PearScriptEngineFactory"));
       
   123     }
       
   124 
       
   125     /**
       
   126      * Basic test of Provider::get
       
   127      */
       
   128     @Test
       
   129     public void testProviderGet() {
       
   130         Set<String> names = ServiceLoader.load(ScriptEngineFactory.class)
       
   131                 .stream()
       
   132                 .map(Provider::get)
       
   133                 .map(ScriptEngineFactory::getEngineName)
       
   134                 .collect(Collectors.toSet());
       
   135         assertTrue(names.contains("BananaScriptEngine"));
       
   136         assertTrue(names.contains("PearScriptEngine"));
       
   137     }
       
   138 
       
   139     /**
       
   140      * Basic test of the public static provider method. BananaScriptEngine
       
   141      * defines a provider method that returns the same instance.
       
   142      */
       
   143     @Test
       
   144     public void testSingleton() {
       
   145         Optional<Provider<ScriptEngineFactory>> oprovider
       
   146             = ServiceLoader.load(ScriptEngineFactory.class)
       
   147                 .stream()
       
   148                 .filter(p -> p.type().getName().equals("org.banana.BananaScriptEngineFactory"))
       
   149                 .findFirst();
       
   150         assertTrue(oprovider.isPresent());
       
   151         Provider<ScriptEngineFactory> provider = oprovider.get();
       
   152 
       
   153         // invoke Provider::get twice
       
   154         ScriptEngineFactory factory1 = provider.get();
       
   155         ScriptEngineFactory factory2 = provider.get();
       
   156         assertTrue(factory1 == factory2);
       
   157     }
       
   158 
       
   159     /**
       
   160      * Basic test of stream() to ensure that elements for providers in named
       
   161      * modules come before elements for providers in unnamed modules.
       
   162      */
       
   163     @Test
       
   164     public void testStreamOrder() {
       
   165         List<Class<?>> types = ServiceLoader.load(ScriptEngineFactory.class)
       
   166                 .stream()
       
   167                 .map(Provider::type)
       
   168                 .collect(Collectors.toList());
       
   169 
       
   170         boolean foundUnnamed = false;
       
   171         for (Class<?> factoryClass : types) {
       
   172             if (factoryClass.getModule().isNamed()) {
       
   173                 if (foundUnnamed) {
       
   174                     assertTrue(false, "Named module element after unnamed");
       
   175                 }
       
   176             } else {
       
   177                 foundUnnamed = true;
       
   178             }
       
   179         }
       
   180     }
       
   181 
       
   182     /**
       
   183      * Basic test of ServiceLoader.findFirst()
       
   184      */
       
   185     @Test
       
   186     public void testFindFirst() {
       
   187         Optional<ScriptEngineFactory> ofactory
       
   188             = ServiceLoader.load(ScriptEngineFactory.class).findFirst();
       
   189         assertTrue(ofactory.isPresent());
       
   190         ScriptEngineFactory factory = ofactory.get();
       
   191         assertTrue(factory.getClass().getModule().isNamed());
       
   192 
       
   193         class S { }
       
   194         assertFalse(ServiceLoader.load(S.class).findFirst().isPresent());
       
   195     }
       
   196 
       
   197     /**
       
   198      * Basic test ServiceLoader.load specifying the platform class loader.
       
   199      * The providers on the module path and class path should not be located.
       
   200      */
       
   201     @Test
       
   202     public void testWithPlatformClassLoader() {
       
   203         ClassLoader pcl = ClassLoader.getPlatformClassLoader();
       
   204 
       
   205         // iterator
       
   206         ServiceLoader<ScriptEngineFactory> loader
       
   207                 = ServiceLoader.load(ScriptEngineFactory.class, pcl);
       
   208         Set<String> names = collectAll(loader)
       
   209                 .stream()
       
   210                 .map(ScriptEngineFactory::getEngineName)
       
   211                 .collect(Collectors.toSet());
       
   212         assertFalse(names.contains("BananaScriptEngine"));
       
   213         assertFalse(names.contains("PearScriptEngine"));
       
   214 
       
   215         // stream
       
   216         names = ServiceLoader.load(ScriptEngineFactory.class, pcl)
       
   217                 .stream()
       
   218                 .map(Provider::get)
       
   219                 .map(ScriptEngineFactory::getEngineName)
       
   220                 .collect(Collectors.toSet());
       
   221         assertFalse(names.contains("BananaScriptEngine"));
       
   222         assertFalse(names.contains("PearScriptEngine"));
       
   223     }
       
   224 
       
   225     /**
       
   226      * Basic test of ServiceLoader.load, using the class loader for
       
   227      * a module in a custom layer as the context.
       
   228      */
       
   229     @Test
       
   230     public void testWithCustomLayer1() {
       
   231         Layer layer = createCustomLayer("bananascript");
       
   232 
       
   233         ClassLoader loader = layer.findLoader("bananascript");
       
   234         List<ScriptEngineFactory> providers
       
   235             = collectAll(ServiceLoader.load(ScriptEngineFactory.class, loader));
       
   236 
       
   237         // should have at least 2 x bananascript + pearscript
       
   238         assertTrue(providers.size() >= 3);
       
   239 
       
   240         // first element should be the provider in the custom layer
       
   241         ScriptEngineFactory factory = providers.get(0);
       
   242         assertTrue(factory.getClass().getClassLoader() == loader);
       
   243         assertTrue(factory.getClass().getModule().getLayer() == layer);
       
   244         assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
       
   245 
       
   246         // remainder should be the boot layer
       
   247         providers.remove(0);
       
   248         Set<String> names = providers.stream()
       
   249                 .map(ScriptEngineFactory::getEngineName)
       
   250                 .collect(Collectors.toSet());
       
   251         assertTrue(names.contains("BananaScriptEngine"));
       
   252         assertTrue(names.contains("PearScriptEngine"));
       
   253     }
       
   254 
       
   255     /**
       
   256      * Basic test of ServiceLoader.load using a custom Layer as the context.
       
   257      */
       
   258     @Test
       
   259     public void testWithCustomLayer2() {
       
   260         Layer layer = createCustomLayer("bananascript");
       
   261 
       
   262         List<ScriptEngineFactory> factories
       
   263             = collectAll(ServiceLoader.load(layer, ScriptEngineFactory.class));
       
   264 
       
   265         // should have at least 2 x bananascript
       
   266         assertTrue(factories.size() >= 2);
       
   267 
       
   268         // first element should be the provider in the custom layer
       
   269         ScriptEngineFactory factory = factories.get(0);
       
   270         assertTrue(factory.getClass().getModule().getLayer() == layer);
       
   271         assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
       
   272 
       
   273         // remainder should be the boot layer
       
   274         factories.remove(0);
       
   275         Set<String> names = factories.stream()
       
   276                 .map(ScriptEngineFactory::getEngineName)
       
   277                 .collect(Collectors.toSet());
       
   278         assertTrue(names.contains("BananaScriptEngine"));
       
   279         assertFalse(names.contains("PearScriptEngine"));
       
   280     }
       
   281 
       
   282     /**
       
   283      * Basic test of ServiceLoader.load with a tree of layers.
       
   284      *
       
   285      * Test scenario:
       
   286      * - boot layer contains "bananascript", maybe other script engines
       
   287      * - layer1, with boot layer as parent, contains "bananascript"
       
   288      * - layer2, with boot layer as parent, contains "bananascript"
       
   289      * - layer3, with layer1 ad layer as parents, contains "bananascript"
       
   290      *
       
   291      * ServiceLoader should locate all 4 script engine factories in DFS order.
       
   292      */
       
   293     @Test
       
   294     public void testWithCustomLayer3() {
       
   295         Layer bootLayer = Layer.boot();
       
   296         Configuration cf0 = bootLayer.configuration();
       
   297 
       
   298         // boot layer should contain "bananascript"
       
   299         List<ScriptEngineFactory> factories
       
   300             = collectAll(ServiceLoader.load(bootLayer, ScriptEngineFactory.class));
       
   301         int countInBootLayer = factories.size();
       
   302         assertTrue(countInBootLayer >= 1);
       
   303         assertTrue(factories.stream()
       
   304                 .map(p -> p.getEngineName())
       
   305                 .filter("BananaScriptEngine"::equals)
       
   306                 .findAny()
       
   307                 .isPresent());
       
   308 
       
   309         ClassLoader scl = ClassLoader.getSystemClassLoader();
       
   310         Path dir = Paths.get(System.getProperty("test.classes", "."), "modules");
       
   311         ModuleFinder finder = ModuleFinder.of(dir);
       
   312 
       
   313         // layer1
       
   314         Configuration cf1 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
       
   315         Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl);
       
   316         assertTrue(layer1.modules().size() == 1);
       
   317 
       
   318         // layer2
       
   319         Configuration cf2 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
       
   320         Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl);
       
   321         assertTrue(layer2.modules().size() == 1);
       
   322 
       
   323         // layer3 with layer1 and layer2 as parents
       
   324         Configuration cf3 = Configuration.resolveRequiresAndUses(finder,
       
   325                 List.of(cf1, cf2),
       
   326                 ModuleFinder.of(),
       
   327                 Set.of());
       
   328         Layer layer3 = Layer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer();
       
   329         assertTrue(layer3.modules().size() == 1);
       
   330 
       
   331 
       
   332         // class loaders
       
   333         ClassLoader loader1 = layer1.findLoader("bananascript");
       
   334         ClassLoader loader2 = layer2.findLoader("bananascript");
       
   335         ClassLoader loader3 = layer3.findLoader("bananascript");
       
   336         assertTrue(loader1 != loader2);
       
   337         assertTrue(loader1 != loader3);
       
   338         assertTrue(loader2 != loader3);
       
   339 
       
   340         // load all factories with layer3 as the context
       
   341         factories = collectAll(ServiceLoader.load(layer3, ScriptEngineFactory.class));
       
   342         int count = factories.size();
       
   343         assertTrue(count == countInBootLayer + 3);
       
   344 
       
   345         // the ordering should be layer3, layer1, boot layer, layer2
       
   346 
       
   347         ScriptEngineFactory factory = factories.get(0);
       
   348         assertTrue(factory.getClass().getModule().getLayer() == layer3);
       
   349         assertTrue(factory.getClass().getClassLoader() == loader3);
       
   350         assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
       
   351 
       
   352         factory = factories.get(1);
       
   353         assertTrue(factory.getClass().getModule().getLayer() == layer1);
       
   354         assertTrue(factory.getClass().getClassLoader() == loader1);
       
   355         assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
       
   356 
       
   357         // boot layer "bananascript" and maybe other factories
       
   358         int last = count -1;
       
   359         boolean found = false;
       
   360         for (int i=2; i<last; i++) {
       
   361             factory = factories.get(i);
       
   362             assertTrue(factory.getClass().getModule().getLayer() == bootLayer);
       
   363             if (factory.getEngineName().equals("BananaScriptEngine")) {
       
   364                 assertFalse(found);
       
   365                 found = true;
       
   366             }
       
   367         }
       
   368         assertTrue(found);
       
   369 
       
   370         factory = factories.get(last);
       
   371         assertTrue(factory.getClass().getModule().getLayer() == layer2);
       
   372         assertTrue(factory.getClass().getClassLoader() == loader2);
       
   373         assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
       
   374     }
       
   375 
       
   376 
       
   377     // -- nulls --
       
   378 
       
   379     @Test(expectedExceptions = { NullPointerException.class })
       
   380     public void testLoadNull1() {
       
   381         ServiceLoader.load(null);
       
   382     }
       
   383 
       
   384     @Test(expectedExceptions = { NullPointerException.class })
       
   385     public void testLoadNull2() {
       
   386         ServiceLoader.load((Class<?>) null, ClassLoader.getSystemClassLoader());
       
   387     }
       
   388 
       
   389     @Test(expectedExceptions = { NullPointerException.class })
       
   390     public void testLoadNull3() {
       
   391         class S { }
       
   392         ServiceLoader.load((Layer) null, S.class);
       
   393     }
       
   394 
       
   395     @Test(expectedExceptions = { NullPointerException.class })
       
   396     public void testLoadNull4() {
       
   397         ServiceLoader.load(Layer.empty(), null);
       
   398     }
       
   399 
       
   400     @Test(expectedExceptions = { NullPointerException.class })
       
   401     public void testLoadNull5() {
       
   402         ServiceLoader.loadInstalled(null);
       
   403     }
       
   404 
       
   405     /**
       
   406      * Create a custom Layer by resolving the given module names. The modules
       
   407      * are located in the {@code ${test.classes}/modules} directory.
       
   408      */
       
   409     private Layer createCustomLayer(String... modules) {
       
   410         Path dir = Paths.get(System.getProperty("test.classes", "."), "modules");
       
   411         ModuleFinder finder = ModuleFinder.of(dir);
       
   412         Set<String> roots = new HashSet<>();
       
   413         Collections.addAll(roots, modules);
       
   414         Layer bootLayer = Layer.boot();
       
   415         Configuration parent = bootLayer.configuration();
       
   416         Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), roots);
       
   417         ClassLoader scl = ClassLoader.getSystemClassLoader();
       
   418         Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
       
   419         assertTrue(layer.modules().size() == 1);
       
   420         return layer;
       
   421     }
       
   422 
       
   423     private <E> List<E> collectAll(ServiceLoader<E> loader) {
       
   424         List<E> list = new ArrayList<>();
       
   425         Iterator<E> iterator = loader.iterator();
       
   426         while (iterator.hasNext()) {
       
   427             list.add(iterator.next());
       
   428         }
       
   429         return list;
       
   430     }
       
   431 }
       
   432