1 /* 2 * Copyright (c) 2015, 2017, 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.io.FileWriter; 26 import java.io.Reader; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.io.InputStreamReader; 30 import java.io.SequenceInputStream; 31 import java.io.StringWriter; 32 import java.io.Writer; 33 import java.nio.file.Files; 34 import java.nio.file.Path; 35 import java.nio.file.Paths; 36 import java.util.ArrayList; 37 import java.util.Collection; 38 import java.util.Collections; 39 import java.util.List; 40 import java.util.function.Consumer; 41 import java.util.stream.Collectors; 42 import java.util.stream.Stream; 43 import javax.tools.JavaCompiler; 44 import javax.tools.JavaFileObject; 45 import javax.tools.StandardJavaFileManager; 46 import javax.tools.StandardLocation; 47 import javax.tools.ToolProvider; 48 import jdk.test.lib.util.FileUtils; 49 import jdk.testlibrary.JDKToolFinder; 50 import static java.lang.String.format; 51 import static java.util.Arrays.asList; 52 53 /* 54 * @test 55 * @bug 8064924 56 * @modules jdk.compiler 57 * @summary Basic test for URLStreamHandlerProvider 58 * @library /lib/testlibrary /test/lib 59 * @build jdk.test.lib.Platform 60 * jdk.test.lib.util.FileUtils 61 * jdk.testlibrary.JDKToolFinder 62 * @compile Basic.java Child.java 63 * @run main Basic 64 */ 65 66 public class Basic { 67 68 static final Path TEST_SRC = Paths.get(System.getProperty("test.src", ".")); 69 static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", ".")); 70 71 public static void main(String[] args) throws Throwable { 72 unknownProtocol("foo", UNKNOWN); 73 unknownProtocol("bar", UNKNOWN); 74 viaProvider("baz", KNOWN); 75 viaProvider("bert", KNOWN); 76 viaProvider("ernie", UNKNOWN, "-Djava.security.manager"); 77 viaProvider("curly", UNKNOWN, "-Djava.security.manager"); 78 viaProvider("larry", KNOWN, "-Djava.security.manager", 79 "-Djava.security.policy=" + TEST_SRC + File.separator + "basic.policy"); 80 viaProvider("moe", KNOWN, "-Djava.security.manager", 81 "-Djava.security.policy=" + TEST_SRC + File.separator + "basic.policy"); 82 viaBadProvider("tom", SCE); 83 viaBadProvider("jerry", SCE); 84 } 85 86 static final Consumer<Result> KNOWN = r -> { 87 if (r.exitValue != 0 || !r.output.isEmpty()) 88 throw new RuntimeException(r.output); 89 }; 90 static final Consumer<Result> UNKNOWN = r -> { 91 if (r.exitValue == 0 || 92 !r.output.contains("java.net.MalformedURLException: unknown protocol")) { 93 throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]"); 94 } 95 }; 96 static final Consumer<Result> SCE = r -> { 97 if (r.exitValue == 0 || 98 !r.output.contains("java.util.ServiceConfigurationError")) { 99 throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]"); 100 } 101 }; 102 103 static void unknownProtocol(String protocol, Consumer<Result> resultChecker) { 104 System.out.println("\nTesting " + protocol); 105 Result r = java(Collections.emptyList(), asList(TEST_CLASSES), 106 "Child", protocol); 107 resultChecker.accept(r); 108 } 109 110 static void viaProvider(String protocol, Consumer<Result> resultChecker, 111 String... sysProps) 112 throws Exception 113 { 114 viaProviderWithTemplate(protocol, resultChecker, 115 TEST_SRC.resolve("provider.template"), 116 sysProps); 117 } 118 119 static void viaBadProvider(String protocol, Consumer<Result> resultChecker, 120 String... sysProps) 121 throws Exception 122 { 123 viaProviderWithTemplate(protocol, resultChecker, 124 TEST_SRC.resolve("bad.provider.template"), 125 sysProps); 126 } 127 128 static void viaProviderWithTemplate(String protocol, 129 Consumer<Result> resultChecker, 130 Path template, String... sysProps) 131 throws Exception 132 { 133 System.out.println("\nTesting " + protocol); 134 Path testRoot = Paths.get("URLStreamHandlerProvider-" + protocol); 135 if (Files.exists(testRoot)) 136 FileUtils.deleteFileTreeWithRetry(testRoot); 137 Files.createDirectory(testRoot); 138 139 Path srcPath = Files.createDirectory(testRoot.resolve("src")); 140 Path srcClass = createProvider(protocol, template, srcPath); 141 142 Path build = Files.createDirectory(testRoot.resolve("build")); 143 javac(build, srcClass); 144 createServices(build, protocol); 145 Path testJar = testRoot.resolve("test.jar"); 146 jar(testJar, build); 147 148 List<String> props = new ArrayList<>(); 149 for (String p : sysProps) 150 props.add(p); 151 152 Result r = java(props, asList(testJar, TEST_CLASSES), 153 "Child", protocol); 154 155 resultChecker.accept(r); 156 } 157 158 static String platformPath(String p) { return p.replace("/", File.separator); } 159 static String binaryName(String name) { return name.replace(".", "/"); } 160 161 static final String SERVICE_IMPL_PREFIX = "net.java.openjdk.test"; 162 163 static void createServices(Path dst, String protocol) throws IOException { 164 Path services = Files.createDirectories(dst.resolve("META-INF") 165 .resolve("services")); 166 167 final String implName = SERVICE_IMPL_PREFIX + "." + protocol + ".Provider"; 168 Path s = services.resolve("java.net.spi.URLStreamHandlerProvider"); 169 FileWriter fw = new FileWriter(s.toFile()); 170 try { 171 fw.write(implName); 172 } finally { 173 fw.close(); 174 } 175 } 176 177 static Path createProvider(String protocol, Path srcTemplate, Path dst) 178 throws IOException 179 { 180 String pkg = SERVICE_IMPL_PREFIX + "." + protocol; 181 Path classDst = dst.resolve(platformPath(binaryName(pkg))); 182 Files.createDirectories(classDst); 183 Path classPath = classDst.resolve("Provider.java"); 184 185 List<String> lines = Files.lines(srcTemplate) 186 .map(s -> s.replaceAll("\\$package", pkg)) 187 .map(s -> s.replaceAll("\\$protocol", protocol)) 188 .collect(Collectors.toList()); 189 Files.write(classPath, lines); 190 191 return classPath; 192 } 193 194 static void jar(Path jarName, Path jarRoot) { String jar = getJDKTool("jar"); 195 ProcessBuilder p = new ProcessBuilder(jar, "cf", jarName.toString(), 196 "-C", jarRoot.toString(), "."); 197 quickFail(run(p)); 198 } 199 200 static void javac(Path dest, Path... sourceFiles) throws IOException { 201 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 202 try (StandardJavaFileManager fileManager = 203 compiler.getStandardFileManager(null, null, null)) { 204 205 List<File> files = Stream.of(sourceFiles) 206 .map(p -> p.toFile()) 207 .collect(Collectors.toList()); 208 List<File> dests = Stream.of(dest) 209 .map(p -> p.toFile()) 210 .collect(Collectors.toList()); 211 Iterable<? extends JavaFileObject> compilationUnits = 212 fileManager.getJavaFileObjectsFromFiles(files); 213 fileManager.setLocation(StandardLocation.CLASS_OUTPUT, dests); 214 JavaCompiler.CompilationTask task = 215 compiler.getTask(null, fileManager, null, null, null, compilationUnits); 216 boolean passed = task.call(); 217 if (!passed) 218 throw new RuntimeException("Error compiling " + files); 219 } 220 } 221 222 static void quickFail(Result r) { 223 if (r.exitValue != 0) 224 throw new RuntimeException(r.output); 225 } 226 227 static Result java(List<String> sysProps, Collection<Path> classpath, 228 String classname, String arg) { 229 String java = getJDKTool("java"); 230 231 List<String> commands = new ArrayList<>(); 232 commands.add(java); 233 for (String prop : sysProps) 234 commands.add(prop); 235 236 String cp = classpath.stream() 237 .map(Path::toString) 238 .collect(Collectors.joining(File.pathSeparator)); 239 commands.add("-cp"); 240 commands.add(cp); 241 commands.add(classname); 242 commands.add(arg); 243 244 return run(new ProcessBuilder(commands)); 245 } 246 247 static Result run(ProcessBuilder pb) { 248 Process p = null; 249 System.out.println("running: " + pb.command()); 250 try { 251 p = pb.start(); 252 } catch (IOException e) { 253 throw new RuntimeException( 254 format("Couldn't start process '%s'", pb.command()), e); 255 } 256 257 String output; 258 try { 259 output = toString(p.getInputStream(), p.getErrorStream()); 260 } catch (IOException e) { 261 throw new RuntimeException( 262 format("Couldn't read process output '%s'", pb.command()), e); 263 } 264 265 try { 266 p.waitFor(); 267 } catch (InterruptedException e) { 268 throw new RuntimeException( 269 format("Process hasn't finished '%s'", pb.command()), e); 270 } 271 272 return new Result(p.exitValue(), output); 273 } 274 275 static final String DEFAULT_IMAGE_BIN = System.getProperty("java.home") 276 + File.separator + "bin" + File.separator; 277 278 static String getJDKTool(String name) { 279 try { 280 return JDKToolFinder.getJDKTool(name); 281 } catch (Exception x) { 282 return DEFAULT_IMAGE_BIN + name; 283 } 284 } 285 286 static String toString(InputStream... src) throws IOException { 287 StringWriter dst = new StringWriter(); 288 Reader concatenated = 289 new InputStreamReader( 290 new SequenceInputStream( 291 Collections.enumeration(asList(src)))); 292 copy(concatenated, dst); 293 return dst.toString(); 294 } 295 296 static void copy(Reader src, Writer dst) throws IOException { 297 int len; 298 char[] buf = new char[1024]; 299 try { 300 while ((len = src.read(buf)) != -1) 301 dst.write(buf, 0, len); 302 } finally { 303 try { 304 src.close(); 305 } catch (IOException ignored1) { 306 } finally { 307 try { 308 dst.close(); 309 } catch (IOException ignored2) { 310 } 311 } 312 } 313 } 314 315 static class Result { 316 final int exitValue; 317 final String output; 318 319 private Result(int exitValue, String output) { 320 this.exitValue = exitValue; 321 this.output = output; 322 } 323 } 324 }