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