1 /*
   2  * Copyright (c) 2015, 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 import java.io.File;
  25 import java.lang.module.Configuration;
  26 import java.lang.module.ModuleFinder;
  27 import java.lang.reflect.Layer;
  28 import java.nio.file.Files;
  29 import java.nio.file.Path;
  30 import java.nio.file.Paths;
  31 import java.util.ServiceLoader;
  32 import javax.script.ScriptEngineFactory;
  33 
  34 import static jdk.testlibrary.ProcessTools.executeTestJava;
  35 
  36 import org.testng.annotations.BeforeTest;
  37 import org.testng.annotations.Test;
  38 import static org.testng.Assert.*;
  39 
  40 /**
  41  * @test
  42  * @library ../../lib /lib/testlibrary
  43  * @build ServicesTest CompilerUtils jdk.testlibrary.*
  44  * @run testng ServicesTest
  45  * @summary Tests ServiceLoader to locate service providers on the module path
  46  *          and class path. Also tests ServiceLoader with a custom Layer.
  47  */
  48 
  49 @Test
  50 public class ServicesTest {
  51 
  52     private static final String TEST_SRC = System.getProperty("test.src");
  53 
  54     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  55     private static final Path CLASSES_DIR = Paths.get("classes");
  56     private static final Path MODS_DIR = Paths.get("mods");
  57 
  58     // modules to compile to the module path
  59     private static final String MODULES[] = { "test", "bananascript" };
  60 
  61     // directories of classes to compile to the class path
  62     private static final String CLASSES[] = { "pearscript" };
  63 
  64     // resources to copy to the class path
  65     private static final String RESOURCES[] = {
  66         "pearscript/META-INF/services/javax.script.ScriptEngineFactory"
  67     };
  68 
  69 
  70     /**
  71      * Compiles all modules and classes used by the test
  72      */
  73     @BeforeTest
  74     public void setup() throws Exception {
  75 
  76         // modules
  77         for (String mn : MODULES ) {
  78             Path src = SRC_DIR.resolve(mn);
  79             Path mods = MODS_DIR.resolve(mn);
  80             assertTrue(CompilerUtils.compile(src, mods));
  81         }
  82 
  83         // classes
  84         for (String dir : CLASSES) {
  85             Path src = SRC_DIR.resolve(dir);
  86             assertTrue(CompilerUtils.compile(src, CLASSES_DIR));
  87         }
  88 
  89         // copy resources
  90         for (String rn : RESOURCES) {
  91             Path file = Paths.get(rn.replace('/', File.separatorChar));
  92             Path source = SRC_DIR.resolve(file);
  93 
  94             // drop directory to get a target of classes/META-INF/...
  95             Path target = CLASSES_DIR.resolve(file.subpath(1, file.getNameCount()));
  96 
  97             Files.createDirectories(target.getParent());
  98             Files.copy(source, target);
  99         }
 100 
 101     }
 102 
 103 
 104     /**
 105      * Run test with -modulepath.
 106      *
 107      * BananaScriptEngine should be found.
 108      */
 109     public void runWithModulePath() throws Exception {
 110         int exitValue
 111             = executeTestJava("-mp", MODS_DIR.toString(),
 112                               "-m", "test/test.Main",
 113                               "BananaScriptEngine")
 114                 .outputTo(System.out)
 115                 .errorTo(System.out)
 116                 .getExitValue();
 117 
 118         assertTrue(exitValue == 0);
 119     }
 120 
 121 
 122     /**
 123      * Run test with -modulepath and -classpath.
 124      *
 125      * Both BananaScriptEngine and PearScriptEngine should be found
 126      */
 127     public void runWithModulePathAndClassPath() throws Exception {
 128         int exitValue
 129             = executeTestJava("-mp", MODS_DIR.toString(),
 130                               "-cp", CLASSES_DIR.toString(),
 131                               "-m", "test/test.Main",
 132                               "BananaScriptEngine", "PearScriptEngine")
 133                 .outputTo(System.out)
 134                 .errorTo(System.out)
 135                 .getExitValue();
 136 
 137         assertTrue(exitValue == 0);
 138     }
 139 
 140 
 141     /**
 142      * Exercise ServiceLoader.load(Layer, Class).
 143      */
 144     public void testWithCustomLayer() throws Exception {
 145 
 146         ServiceLoader<ScriptEngineFactory> sl;
 147 
 148         // BananaScriptEngine should not be in the boot Layer
 149         sl = ServiceLoader.load(Layer.boot(), ScriptEngineFactory.class);
 150         assertTrue(find("BananaScriptEngine", sl) == null);
 151 
 152         // create a custom Layer
 153         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
 154         Configuration cf = Configuration
 155             .resolve(finder, Layer.boot(), ModuleFinder.empty()).bind();
 156         ClassLoader loader = new ModuleClassLoader(cf);
 157         Layer layer = Layer.create(cf, mn -> loader);
 158         assertTrue(layer.findModule("bananascript").isPresent());
 159 
 160         sl = ServiceLoader.load(layer, ScriptEngineFactory.class);
 161         ScriptEngineFactory factory = find("BananaScriptEngine", sl);
 162         assertTrue(factory != null);
 163         assertEquals(factory.getClass().getModule().getName(), "bananascript");
 164         assertTrue(factory.getClass().getClassLoader() == loader);
 165 
 166     }
 167 
 168     /**
 169      * Find the given scripting engine (by name) via the ScriptEngineFactory
 170      * that ServiceLoader has found.
 171      */
 172     static ScriptEngineFactory find(String name,
 173                                     ServiceLoader<ScriptEngineFactory> sl) {
 174         for (ScriptEngineFactory factory : sl) {
 175             if (factory.getEngineName().equals(name))
 176                 return factory;
 177         }
 178         return null;
 179     }
 180 
 181 
 182 }
 183