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