Path: blob/master/test/jdk/javax/naming/spi/providers/InitialContextTest.java
41155 views
/*1* Copyright (c) 2014, 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*/2223import javax.naming.Context;24import java.io.*;25import java.nio.file.Files;26import java.nio.file.Path;27import java.nio.file.Paths;28import java.util.*;29import java.util.Collection;30import java.util.Collections;31import java.util.List;32import java.util.function.Function;33import java.util.stream.Collectors;34import java.util.stream.Stream;3536import static java.lang.String.format;37import static java.util.Arrays.asList;38import static java.util.Collections.singleton;39import static java.util.Collections.singletonMap;4041/*42* @test43* @bug 804462744* @summary Examines different ways JNDI providers can hook up themselves and45* become available. Each case mimics the most straightforward way of46* executing scenarios.47*/48public class InitialContextTest {4950public static void main(String[] args) throws Throwable {51unknownInitialContextFactory();52initialContextFactoryInAJar();53initialContextFactoryAsService();54}5556private static void unknownInitialContextFactory() throws Throwable {5758// This is a parameter of this test case, it should work for any value59// of it, provided a class with this FQN is not available in a runtime.60// So pick any name you like.61String factoryClassFqn =62"net.java.openjdk.test.UnknownInitialContextFactory";6364Path tmp = Files.createDirectory(Paths.get("InitialContextTest-1"));6566Path src = templatesHome().resolve("test.template");67Path dst = tmp.resolve("Test.java");68Files.copy(src, dst);6970Path build = Files.createDirectory(tmp.resolve("build"));7172javac(build, dst);7374Map<String, String> props75= singletonMap(Context.INITIAL_CONTEXT_FACTORY, factoryClassFqn);7677Result r = java(props, singleton(build), "Test");7879if (r.exitValue == 0 || !r.output.startsWith(80stackTraceStringForClassNotFound(factoryClassFqn))) {81throw new RuntimeException(82"Expected a different kind of failure: " + r.output);83}84}8586private static String stackTraceStringForClassNotFound(String fqn) {87return String.format(88"Exception in thread \"main\" javax.naming.NoInitialContextException: "89+ "Cannot instantiate class: %s "90+ "[Root exception is java.lang.ClassNotFoundException: %s]",91fqn, fqn);92}9394private static void initialContextFactoryInAJar() throws Throwable {9596String factoryClassFqn =97"net.java.openjdk.test.DummyInitialContextFactory";9899Path tmp = Files.createDirectory(Paths.get("InitialContextTest-2"));100101Path src = templatesHome().resolve("test.template");102Path dst = tmp.resolve("Test.java");103Files.copy(src, dst);104105Path dst1 = createFactoryFrom(templatesHome().resolve("factory.template"),106factoryClassFqn, tmp);107108Path build = Files.createDirectory(tmp.resolve("build"));109110javac(build, dst);111Path explodedJar = Files.createDirectory(tmp.resolve("exploded-jar"));112javac(explodedJar, dst1);113jar(tmp.resolve("test.jar"), explodedJar);114115Files.copy(tmp.resolve("test.jar"), build.resolve("test.jar"));116117Map<String, String> props118= singletonMap(Context.INITIAL_CONTEXT_FACTORY, factoryClassFqn);119120Result r = java(props, asList(build.resolve("test.jar"), build), "Test");121122if (r.exitValue != 0 || !r.output.isEmpty())123throw new RuntimeException(r.output);124}125126127private static Path createFactoryFrom(Path srcTemplate,128String factoryFqn,129Path dstFolder) throws IOException {130131String factorySimpleName, packageName;132int i = factoryFqn.lastIndexOf('.');133if (i < 0) {134packageName = "";135factorySimpleName = factoryFqn;136} else {137packageName = factoryFqn.substring(0, i);138factorySimpleName = factoryFqn.substring(i + 1);139}140141Path result = dstFolder.resolve(factorySimpleName + ".java");142File dst = result.toFile();143File src = srcTemplate.toFile();144try (BufferedReader r = new BufferedReader(new FileReader(src));145BufferedWriter w = new BufferedWriter(new FileWriter(dst))) {146147List<String> lines = processTemplate(packageName, factorySimpleName,148r.lines()).collect(Collectors.toList());149150Iterator<String> it = lines.iterator();151if (it.hasNext())152w.write(it.next());153while (it.hasNext()) {154w.newLine();155w.write(it.next());156}157}158return result;159}160161private static Stream<String> processTemplate(String packageName,162String factorySimpleName,163Stream<String> lines) {164Function<String, String> pckg;165166if (packageName.isEmpty()) {167pckg = s -> s.contains("$package") ? "" : s;168} else {169pckg = s -> s.replaceAll("\\$package", packageName);170}171172Function<String, String> factory173= s -> s.replaceAll("\\$factoryName", factorySimpleName);174175return lines.map(pckg).map(factory);176}177178private static void initialContextFactoryAsService() throws Throwable {179180String factoryClassFqn =181"net.java.openjdk.test.BrokenInitialContextFactory";182183Path tmp = Files.createDirectory(Paths.get("InitialContextTest-3"));184185Path src = templatesHome().resolve("test.template");186Path dst = tmp.resolve("Test.java");187Files.copy(src, dst);188189Path dst1 = createFactoryFrom(templatesHome().resolve("broken_factory.template"),190factoryClassFqn, tmp);191192Path build = Files.createDirectory(tmp.resolve("build"));193194javac(build, dst);195196Path explodedJar = Files.createDirectory(tmp.resolve("exploded-jar"));197Path services = Files.createDirectories(explodedJar.resolve("META-INF")198.resolve("services"));199200Path s = services.resolve("javax.naming.spi.InitialContextFactory");201FileWriter fw = new FileWriter(s.toFile());202try {203fw.write(factoryClassFqn);204} finally {205fw.close();206}207208javac(explodedJar, dst1);209jar(tmp.resolve("test.jar"), explodedJar);210211Files.copy(tmp.resolve("test.jar"), build.resolve("test.jar"));212213Map<String, String> props214= singletonMap(Context.INITIAL_CONTEXT_FACTORY, factoryClassFqn);215216Result r = java(props, asList(build.resolve("test.jar"), build), "Test");217218if (r.exitValue == 0 || !verifyOutput(r.output, factoryClassFqn))219throw new RuntimeException(r.output);220}221222// IMO, that's the easiest way that gives you a fair amount of confidence in223// that j.u.ServiceLoader is loading a factory rather than Class.forName224private static boolean verifyOutput(String output, String fqn) {225String s1 = String.format(226"Exception in thread \"main\" javax.naming.NoInitialContextException: "227+ "Cannot load initial context factory '%s' "228+ "[Root exception is java.util.ServiceConfigurationError: "229+ "javax.naming.spi.InitialContextFactory: "230+ "Provider %s could not be instantiated]", fqn, fqn);231232String s2 = String.format("Caused by: java.util.ServiceConfigurationError: "233+ "javax.naming.spi.InitialContextFactory: "234+ "Provider %s could not be instantiated", fqn);235236String s3 = "Caused by: java.lang.RuntimeException: "237+ "This is a broken factory. It is supposed to throw this exception.";238239return output.startsWith(s1) && output.contains(s2)240&& output.contains(s1);241}242243private static void jar(Path jarName, Path jarRoot) {244String jar = getJDKTool("jar");245ProcessBuilder p = new ProcessBuilder(jar, "cf", jarName.toString(),246"-C", jarRoot.toString(), ".");247quickFail(run(p));248}249250private static void javac(Path compilationOutput, Path... sourceFiles) {251String javac = getJDKTool("javac");252List<String> commands = new ArrayList<>();253commands.addAll(asList(javac, "-d", compilationOutput.toString()));254List<Path> paths = asList(sourceFiles);255commands.addAll(paths.stream()256.map(Path::toString)257.collect(Collectors.toList()));258quickFail(run(new ProcessBuilder(commands)));259}260261private static void quickFail(Result r) {262if (r.exitValue != 0)263throw new RuntimeException(r.output);264}265266private static Result java(Map<String, String> properties,267Collection<Path> classpath,268String classname) {269270String java = getJDKTool("java");271272List<String> commands = new ArrayList<>();273commands.add(java);274commands.addAll(properties.entrySet()275.stream()276.map(e -> "-D" + e.getKey() + "=" + e.getValue())277.collect(Collectors.toList()));278279String cp = classpath.stream()280.map(Path::toString)281.collect(Collectors.joining(File.pathSeparator));282commands.add("-cp");283commands.add(cp);284commands.add(classname);285286return run(new ProcessBuilder(commands));287}288289private static Result run(ProcessBuilder b) {290Process p = null;291try {292p = b.start();293} catch (IOException e) {294throw new RuntimeException(295format("Couldn't start process '%s'", b.command()), e);296}297298String output;299try {300output = toString(p.getInputStream(), p.getErrorStream());301} catch (IOException e) {302throw new RuntimeException(303format("Couldn't read process output '%s'", b.command()), e);304}305306try {307p.waitFor();308} catch (InterruptedException e) {309throw new RuntimeException(310format("Process hasn't finished '%s'", b.command()), e);311}312313return new Result(p.exitValue(), output);314}315316private static String getJDKTool(String name) {317String testJdk = System.getProperty("test.jdk");318if (testJdk == null)319throw new RuntimeException("Please provide test.jdk property at a startup");320return testJdk + File.separator + "bin" + File.separator + name;321}322323private static Path templatesHome() {324String testSrc = System.getProperty("test.src");325if (testSrc == null)326throw new RuntimeException("Please provide test.src property at a startup");327return Paths.get(testSrc);328}329330private static String toString(InputStream... src) throws IOException {331StringWriter dst = new StringWriter();332Reader concatenated =333new InputStreamReader(334new SequenceInputStream(335Collections.enumeration(asList(src))));336copy(concatenated, dst);337return dst.toString();338}339340private static void copy(Reader src, Writer dst) throws IOException {341int len;342char[] buf = new char[1024];343try {344while ((len = src.read(buf)) != -1)345dst.write(buf, 0, len);346} finally {347try {348src.close();349} catch (IOException ignored1) {350} finally {351try {352dst.close();353} catch (IOException ignored2) {354}355}356}357}358359private static class Result {360361final int exitValue;362final String output;363364private Result(int exitValue, String output) {365this.exitValue = exitValue;366this.output = output;367}368}369}370371372