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