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