OpenJDK / bsd-port / jdk9 / jdk
changeset 11480:a4e47f145dda
8064924: Update java.net.URL to work with modules
Reviewed-by: alanb, plevart, psandoz
line wrap: on
line diff
--- a/src/java.base/share/classes/java/net/URL.java Mon Feb 23 11:37:36 2015 +0100 +++ b/src/java.base/share/classes/java/net/URL.java Mon Feb 23 15:48:20 2015 +0000 @@ -27,8 +27,15 @@ import java.io.IOException; import java.io.InputStream; +import java.net.spi.URLStreamHandlerProvider; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Hashtable; -import java.util.StringTokenizer; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; + import sun.security.util.SecurityConstants; /** @@ -248,23 +255,19 @@ * stream protocol handler. * <li>If no {@code URLStreamHandlerFactory} has yet been set up, * or if the factory's {@code createURLStreamHandler} method - * returns {@code null}, then the constructor finds the - * value of the system property: - * <blockquote><pre> - * java.protocol.handler.pkgs - * </pre></blockquote> - * If the value of that system property is not {@code null}, - * it is interpreted as a list of packages separated by a vertical - * slash character '{@code |}'. The constructor tries to load - * the class named: - * <blockquote><pre> - * <<i>package</i>>.<<i>protocol</i>>.Handler - * </pre></blockquote> - * where <<i>package</i>> is replaced by the name of the package - * and <<i>protocol</i>> is replaced by the name of the protocol. - * If this class does not exist, or if the class exists but it is not - * a subclass of {@code URLStreamHandler}, then the next package - * in the list is tried. + * returns {@code null}, then the {@linkplain java.util.ServiceLoader + * ServiceLoader} mechanism is used to locate {@linkplain + * java.net.spi.URLStreamHandlerProvider URLStreamHandlerProvider} + * implementations using the system class + * loader. The order that providers are located is implementation + * specific, and an implementation is free to cache the located + * providers. A {@linkplain java.util.ServiceConfigurationError + * ServiceConfigurationError}, {@code Error} or {@code RuntimeException} + * thrown from the {@code createURLStreamHandler}, if encountered, will + * be propagated to the calling thread. The {@code + * createURLStreamHandler} method of each provider, if instantiated, is + * invoked, with the protocol string, until a provider returns non-null, + * or all providers have been exhausted. * <li>If the previous step fails to find a protocol handler, then the * constructor tries to load a built-in protocol handler. * If this class does not exist, or if the class exists but it is not a @@ -277,8 +280,12 @@ * <blockquote><pre> * http, https, file, and jar * </pre></blockquote> - * Protocol handlers for additional protocols may also be - * available. + * Protocol handlers for additional protocols may also be available. + * Some protocol handlers, for example those used for loading platform + * classes or classes on the class path, may not be overridden. The details + * of such restrictions, and when those restrictions apply (during + * initialization of the runtime for example), are implementation specific + * and therefore not specified * * <p>No validation of the inputs is performed by this constructor. * @@ -1107,20 +1114,115 @@ } handlers.clear(); - // ensure the core protocol handlers are loaded before setting - // a custom URLStreamHandlerFactory - ensureHandlersLoaded("jrt", "jar", "file"); - // safe publication of URLStreamHandlerFactory with volatile write factory = fac; } } + private static final URLStreamHandlerFactory defaultFactory = new DefaultFactory(); + + private static class DefaultFactory implements URLStreamHandlerFactory { + private static String PREFIX = "sun.net.www.protocol"; + + public URLStreamHandler createURLStreamHandler(String protocol) { + String name = PREFIX + "." + protocol + ".Handler"; + try { + Class<?> c = Class.forName(name); + return (URLStreamHandler)c.newInstance(); + } catch (ClassNotFoundException x) { + // ignore + } catch (Exception e) { + // For compatibility, all Exceptions are ignored. + // any number of exceptions can get thrown here + } + return null; + } + } + + private static Iterator<URLStreamHandlerProvider> providers() { + return new Iterator<URLStreamHandlerProvider>() { + + ClassLoader cl = ClassLoader.getSystemClassLoader(); + ServiceLoader<URLStreamHandlerProvider> sl = + ServiceLoader.load(URLStreamHandlerProvider.class, cl); + Iterator<URLStreamHandlerProvider> i = sl.iterator(); + + URLStreamHandlerProvider next = null; + + private boolean getNext() { + while (next == null) { + try { + if (!i.hasNext()) + return false; + next = i.next(); + } catch (ServiceConfigurationError sce) { + if (sce.getCause() instanceof SecurityException) { + // Ignore security exceptions + continue; + } + throw sce; + } + } + return true; + } + + public boolean hasNext() { + return getNext(); + } + + public URLStreamHandlerProvider next() { + if (!getNext()) + throw new NoSuchElementException(); + URLStreamHandlerProvider n = next; + next = null; + return n; + } + }; + } + + // Thread-local gate to prevent recursive provider lookups + private static ThreadLocal<Object> gate = new ThreadLocal<>(); + + private static URLStreamHandler lookupViaProviders(final String protocol) { + if (!sun.misc.VM.isBooted()) + return null; + + if (gate.get() != null) + throw new Error("Circular loading of URL stream handler providers detected"); + + gate.set(gate); + try { + return AccessController.doPrivileged( + new PrivilegedAction<URLStreamHandler>() { + public URLStreamHandler run() { + Iterator<URLStreamHandlerProvider> itr = providers(); + while (itr.hasNext()) { + URLStreamHandlerProvider f = itr.next(); + URLStreamHandler h = f.createURLStreamHandler(protocol); + if (h != null) + return h; + } + return null; + } + }); + } finally { + gate.set(null); + } + } + + private static final String[] NON_OVERRIDEABLE_PROTOCOLS = {"file", "jrt"}; + private static boolean isOverrideable(String protocol) { + for (String p : NON_OVERRIDEABLE_PROTOCOLS) + if (protocol.equalsIgnoreCase(p)) + return false; + return true; + } + /** * A table of protocol handlers. */ static Hashtable<String,URLStreamHandler> handlers = new Hashtable<>(); - private static Object streamHandlerLock = new Object(); + private static final Object streamHandlerLock = new Object(); /** * Returns the Stream Handler. @@ -1129,66 +1231,33 @@ static URLStreamHandler getURLStreamHandler(String protocol) { URLStreamHandler handler = handlers.get(protocol); - if (handler == null) { - boolean checkedWithFactory = false; + if (handler != null) { + return handler; + } + URLStreamHandlerFactory fac; + boolean checkedWithFactory = false; + + if (isOverrideable(protocol)) { // Use the factory (if any). Volatile read makes // URLStreamHandlerFactory appear fully initialized to current thread. - URLStreamHandlerFactory fac = factory; + fac = factory; if (fac != null) { handler = fac.createURLStreamHandler(protocol); checkedWithFactory = true; } - // Try java protocol handler if (handler == null) { - String packagePrefixList = null; + handler = lookupViaProviders(protocol); + } + } - packagePrefixList - = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction( - protocolPathProp,"")); - if (packagePrefixList != "") { - packagePrefixList += "|"; - } - - // REMIND: decide whether to allow the "null" class prefix - // or not. - packagePrefixList += "sun.net.www.protocol"; - - StringTokenizer packagePrefixIter = - new StringTokenizer(packagePrefixList, "|"); - - while (handler == null && - packagePrefixIter.hasMoreTokens()) { - - String packagePrefix = - packagePrefixIter.nextToken().trim(); - try { - String clsName = packagePrefix + "." + protocol + - ".Handler"; - Class<?> cls = null; - try { - cls = Class.forName(clsName); - } catch (ClassNotFoundException e) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - if (cl != null) { - cls = cl.loadClass(clsName); - } - } - if (cls != null) { - handler = - (URLStreamHandler)cls.newInstance(); - } - } catch (Exception e) { - // any number of exceptions can get thrown here - } - } - } - - synchronized (streamHandlerLock) { - + synchronized (streamHandlerLock) { + if (handler == null) { + // Try the built-in protocol handler + handler = defaultFactory.createURLStreamHandler(protocol); + } else { URLStreamHandler handler2 = null; // Check again with hashtable just in case another @@ -1202,7 +1271,7 @@ // Check with factory if another thread set a // factory since our last check if (!checkedWithFactory && (fac = factory) != null) { - handler2 = fac.createURLStreamHandler(protocol); + handler2 = fac.createURLStreamHandler(protocol); } if (handler2 != null) { @@ -1211,30 +1280,18 @@ // this thread created. handler = handler2; } + } - // Insert this handler into the hashtable - if (handler != null) { - handlers.put(protocol, handler); - } - + // Insert this handler into the hashtable + if (handler != null) { + handlers.put(protocol, handler); } } return handler; - } /** - * Ensures that the given protocol handlers are loaded - */ - private static void ensureHandlersLoaded(String... protocols) { - for (String protocol: protocols) { - getURLStreamHandler(protocol); - } - } - - - /** * WriteObject is called to save the state of the URL to an * ObjectOutputStream. The handler is not saved since it is * specific to this system.
--- a/src/java.base/share/classes/java/net/URLStreamHandlerFactory.java Mon Feb 23 11:37:36 2015 +0100 +++ b/src/java.base/share/classes/java/net/URLStreamHandlerFactory.java Mon Feb 23 15:48:20 2015 +0000 @@ -44,7 +44,9 @@ * * @param protocol the protocol ("{@code ftp}", * "{@code http}", "{@code nntp}", etc.). - * @return a {@code URLStreamHandler} for the specific protocol. + * @return a {@code URLStreamHandler} for the specific protocol, or {@code + * null} if this factory cannot create a handler for the specific + * protocol * @see java.net.URLStreamHandler */ URLStreamHandler createURLStreamHandler(String protocol);
--- a/src/java.base/share/classes/java/net/package-info.java Mon Feb 23 11:37:36 2015 +0100 +++ b/src/java.base/share/classes/java/net/package-info.java Mon Feb 23 15:48:20 2015 +0000 @@ -143,13 +143,11 @@ * a similar URL will try to instantiate the handler for the specified protocol; * if it doesn't exist an exception will be thrown. * <p>By default the protocol handlers are loaded dynamically from the default - * location. It is, however, possible to add to the search path by setting - * the {@code java.protocol.handler.pkgs} system property. For instance if - * it is set to {@code myapp.protocols}, then the URL code will try, in the - * case of http, first to load {@code myapp.protocols.http.Handler}, then, - * if this fails, {@code http.Handler} from the default location. - * <p>Note that the Handler class <b>has to</b> be a subclass of the abstract - * class {@link java.net.URLStreamHandler}.</p> + * location. It is, however, possible to deploy additional protocols handlers + * as {@link java.util.ServiceLoader services}. Service providers of type + * {@linkplain java.net.spi.URLStreamHandlerProvider} are located at + * runtime, as specified in the {@linkplain + * java.net.URL#URL(String,String,int,String) URL constructor}. * <h2>Additional Specification</h2> * <ul> * <li><a href="doc-files/net-properties.html">
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/net/spi/URLStreamHandlerProvider.java Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net.spi; + +import java.net.URLStreamHandlerFactory; + +/** + * URL stream handler service-provider class. + * + *<p> A URL stream handler provider is a concrete subclass of this class that + * has a zero-argument constructor. URL stream handler providers may be + * installed in an instance of the Java platform by adding them to the + * application class path. + * + * <p> A URL stream handler provider identifies itself with a + * provider-configuration file named java.net.spi.URLStreamHandlerProvider in + * the resource directory META-INF/services. The file should contain a list of + * fully-qualified concrete URL stream handler provider class names, one per + * line. + * + * @since 1.9 + */ +public abstract class URLStreamHandlerProvider + implements URLStreamHandlerFactory +{ + private static Void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("setFactory")); + return null; + } + private URLStreamHandlerProvider(Void ignore) { } + + /** + * Initializes a new URL stream handler provider. + * + * @throws SecurityException + * If a security manager has been installed and it denies + * {@link RuntimePermission}{@code ("setFactory")}. + */ + protected URLStreamHandlerProvider() { + this(checkPermission()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/net/spi/package-info.java Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Service-provider classes for the <tt>{@link java.net}</tt> package. + * + * <p> Only developers who are defining new URL stream handler providers + * should need to make direct use of this package. + * + * @since 1.9 + */ + +package java.net.spi;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/net/spi/URLStreamHandlerProvider/Basic.java Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import jdk.testlibrary.FileUtils; +import jdk.testlibrary.JDKToolFinder; +import static java.lang.String.format; +import static java.util.Arrays.asList; + +/* + * @test + * @bug 8064924 + * @summary Basic test for URLStreamHandlerProvider + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder + * @compile Basic.java Child.java + * @run main Basic + */ + +public class Basic { + + static final Path TEST_SRC = Paths.get(System.getProperty("test.src", ".")); + static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", ".")); + + public static void main(String[] args) throws Throwable { + unknownProtocol("foo", UNKNOWN); + unknownProtocol("bar", UNKNOWN); + viaProvider("baz", KNOWN); + viaProvider("bert", KNOWN); + viaProvider("ernie", UNKNOWN, "-Djava.security.manager"); + viaProvider("curly", UNKNOWN, "-Djava.security.manager"); + viaProvider("larry", KNOWN, "-Djava.security.manager", + "-Djava.security.policy=" + TEST_SRC + File.separator + "basic.policy"); + viaProvider("moe", KNOWN, "-Djava.security.manager", + "-Djava.security.policy=" + TEST_SRC + File.separator + "basic.policy"); + viaBadProvider("tom", SCE); + viaBadProvider("jerry", SCE); + } + + static final Consumer<Result> KNOWN = r -> { + if (r.exitValue != 0 || !r.output.isEmpty()) + throw new RuntimeException(r.output); + }; + static final Consumer<Result> UNKNOWN = r -> { + if (r.exitValue == 0 || + !r.output.contains("java.net.MalformedURLException: unknown protocol")) { + throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]"); + } + }; + static final Consumer<Result> SCE = r -> { + if (r.exitValue == 0 || + !r.output.contains("java.util.ServiceConfigurationError")) { + throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]"); + } + }; + + static void unknownProtocol(String protocol, Consumer<Result> resultChecker) { + System.out.println("\nTesting " + protocol); + Result r = java(Collections.emptyList(), asList(TEST_CLASSES), + "Child", protocol); + resultChecker.accept(r); + } + + static void viaProvider(String protocol, Consumer<Result> resultChecker, + String... sysProps) + throws Exception + { + viaProviderWithTemplate(protocol, resultChecker, + TEST_SRC.resolve("provider.template"), + sysProps); + } + + static void viaBadProvider(String protocol, Consumer<Result> resultChecker, + String... sysProps) + throws Exception + { + viaProviderWithTemplate(protocol, resultChecker, + TEST_SRC.resolve("bad.provider.template"), + sysProps); + } + + static void viaProviderWithTemplate(String protocol, + Consumer<Result> resultChecker, + Path template, String... sysProps) + throws Exception + { + System.out.println("\nTesting " + protocol); + Path testRoot = Paths.get("URLStreamHandlerProvider-" + protocol); + if (Files.exists(testRoot)) + FileUtils.deleteFileTreeWithRetry(testRoot); + Files.createDirectory(testRoot); + + Path srcPath = Files.createDirectory(testRoot.resolve("src")); + Path srcClass = createProvider(protocol, template, srcPath); + + Path build = Files.createDirectory(testRoot.resolve("build")); + javac(build, srcClass); + createServices(build, protocol); + Path testJar = testRoot.resolve("test.jar"); + jar(testJar, build); + + List<String> props = new ArrayList<>(); + for (String p : sysProps) + props.add(p); + + Result r = java(props, asList(testJar, TEST_CLASSES), + "Child", protocol); + + resultChecker.accept(r); + } + + static String platformPath(String p) { return p.replace("/", File.separator); } + static String binaryName(String name) { return name.replace(".", "/"); } + + static final String SERVICE_IMPL_PREFIX = "net.java.openjdk.test"; + + static void createServices(Path dst, String protocol) throws IOException { + Path services = Files.createDirectories(dst.resolve("META-INF") + .resolve("services")); + + final String implName = SERVICE_IMPL_PREFIX + "." + protocol + ".Provider"; + Path s = services.resolve("java.net.spi.URLStreamHandlerProvider"); + FileWriter fw = new FileWriter(s.toFile()); + try { + fw.write(implName); + } finally { + fw.close(); + } + } + + static Path createProvider(String protocol, Path srcTemplate, Path dst) + throws IOException + { + String pkg = SERVICE_IMPL_PREFIX + "." + protocol; + Path classDst = dst.resolve(platformPath(binaryName(pkg))); + Files.createDirectories(classDst); + Path classPath = classDst.resolve("Provider.java"); + + List<String> lines = Files.lines(srcTemplate) + .map(s -> s.replaceAll("\\$package", pkg)) + .map(s -> s.replaceAll("\\$protocol", protocol)) + .collect(Collectors.toList()); + Files.write(classPath, lines); + + return classPath; + } + + static void jar(Path jarName, Path jarRoot) { String jar = getJDKTool("jar"); + ProcessBuilder p = new ProcessBuilder(jar, "cf", jarName.toString(), + "-C", jarRoot.toString(), "."); + quickFail(run(p)); + } + + static void javac(Path dest, Path... sourceFiles) throws IOException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + try (StandardJavaFileManager fileManager = + compiler.getStandardFileManager(null, null, null)) { + + List<File> files = Stream.of(sourceFiles) + .map(p -> p.toFile()) + .collect(Collectors.toList()); + List<File> dests = Stream.of(dest) + .map(p -> p.toFile()) + .collect(Collectors.toList()); + Iterable<? extends JavaFileObject> compilationUnits = + fileManager.getJavaFileObjectsFromFiles(files); + fileManager.setLocation(StandardLocation.CLASS_OUTPUT, dests); + JavaCompiler.CompilationTask task = + compiler.getTask(null, fileManager, null, null, null, compilationUnits); + boolean passed = task.call(); + if (!passed) + throw new RuntimeException("Error compiling " + files); + } + } + + static void quickFail(Result r) { + if (r.exitValue != 0) + throw new RuntimeException(r.output); + } + + static Result java(List<String> sysProps, Collection<Path> classpath, + String classname, String arg) { + String java = getJDKTool("java"); + + List<String> commands = new ArrayList<>(); + commands.add(java); + for (String prop : sysProps) + commands.add(prop); + + String cp = classpath.stream() + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + commands.add("-cp"); + commands.add(cp); + commands.add(classname); + commands.add(arg); + + return run(new ProcessBuilder(commands)); + } + + static Result run(ProcessBuilder pb) { + Process p = null; + System.out.println("running: " + pb.command()); + try { + p = pb.start(); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't start process '%s'", pb.command()), e); + } + + String output; + try { + output = toString(p.getInputStream(), p.getErrorStream()); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't read process output '%s'", pb.command()), e); + } + + try { + p.waitFor(); + } catch (InterruptedException e) { + throw new RuntimeException( + format("Process hasn't finished '%s'", pb.command()), e); + } + + return new Result(p.exitValue(), output); + } + + static final String DEFAULT_IMAGE_BIN = System.getProperty("java.home") + + File.separator + "bin" + File.separator; + + static String getJDKTool(String name) { + try { + return JDKToolFinder.getJDKTool(name); + } catch (Exception x) { + return DEFAULT_IMAGE_BIN + name; + } + } + + static String toString(InputStream... src) throws IOException { + StringWriter dst = new StringWriter(); + Reader concatenated = + new InputStreamReader( + new SequenceInputStream( + Collections.enumeration(asList(src)))); + copy(concatenated, dst); + return dst.toString(); + } + + static void copy(Reader src, Writer dst) throws IOException { + int len; + char[] buf = new char[1024]; + try { + while ((len = src.read(buf)) != -1) + dst.write(buf, 0, len); + } finally { + try { + src.close(); + } catch (IOException ignored1) { + } finally { + try { + dst.close(); + } catch (IOException ignored2) { + } + } + } + } + + static class Result { + final int exitValue; + final String output; + + private Result(int exitValue, String output) { + this.exitValue = exitValue; + this.output = output; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/net/spi/URLStreamHandlerProvider/Child.java Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.net.MalformedURLException; +import java.net.URL; + +public class Child { + + public static void main(String[] args) throws MalformedURLException { + if (args.length != 1) { + System.err.println("Usage: java Child <protocol>"); + return; + } + String protocol = args[0]; + URL url = new URL(protocol + "://"); + + // toExternalForm should return the protocol string + String s = url.toExternalForm(); + if (!s.equals(protocol)) { + System.err.println("Expected url.toExternalForm to return " + + protocol + ", but got: " + s); + System.exit(1); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/net/spi/URLStreamHandlerProvider/bad.provider.template Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package $package; + +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.spi.URLStreamHandlerProvider; + +public class Provider extends URLStreamHandlerProvider { + + public Provider(String someRandomArg) { // No no-args constructor + super(); + } + + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + return null; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/net/spi/URLStreamHandlerProvider/basic.policy Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + grant { + permission java.lang.RuntimePermission "setFactory"; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/net/spi/URLStreamHandlerProvider/provider.template Mon Feb 23 15:48:20 2015 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package $package; + +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.spi.URLStreamHandlerProvider; + +public class Provider extends URLStreamHandlerProvider { + + private static final String PROTOCOL = "$protocol"; + + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + if (!PROTOCOL.equals(protocol)) + return null; + + return new Handler(); + } + + static class Handler extends URLStreamHandler { + public URLConnection openConnection(URL u) throws java.io.IOException { + return null; + } + + public String toExternalForm(URL u) { return PROTOCOL; } + } +}
--- a/test/javax/net/ssl/FixingJavadocs/ComURLNulls.java Mon Feb 23 11:37:36 2015 +0100 +++ b/test/javax/net/ssl/FixingJavadocs/ComURLNulls.java Mon Feb 23 15:48:20 2015 +0000 @@ -46,12 +46,23 @@ public class ComURLNulls { + private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory { + private static String SUPPORTED_PROTOCOL = "https"; + + public URLStreamHandler createURLStreamHandler(String protocol) { + if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL)) + return null; + + return new com.sun.net.ssl.internal.www.protocol.https.Handler(); + } + } + public static void main(String[] args) throws Exception { HostnameVerifier reservedHV = HttpsURLConnection.getDefaultHostnameVerifier(); try { - System.setProperty("java.protocol.handler.pkgs", - "com.sun.net.ssl.internal.www.protocol"); + URL.setURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory()); + /** * This test does not establish any connection to the specified * URL, hence a dummy URL is used.
--- a/test/sun/net/www/protocol/https/NewImpl/ComHTTPSConnection.java Mon Feb 23 11:37:36 2015 +0100 +++ b/test/sun/net/www/protocol/https/NewImpl/ComHTTPSConnection.java Mon Feb 23 15:48:20 2015 +0000 @@ -188,6 +188,17 @@ } } + private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory { + private static String SUPPORTED_PROTOCOL = "https"; + + public URLStreamHandler createURLStreamHandler(String protocol) { + if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL)) + return null; + + return new com.sun.net.ssl.internal.www.protocol.https.Handler(); + } + } + /* * Define the client side of the test. * @@ -205,8 +216,7 @@ HostnameVerifier reservedHV = HttpsURLConnection.getDefaultHostnameVerifier(); try { - System.setProperty("java.protocol.handler.pkgs", - "com.sun.net.ssl.internal.www.protocol"); + URL.setURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier()); URL url = new URL("https://" + "localhost:" + serverPort +
--- a/test/sun/net/www/protocol/https/NewImpl/ComHostnameVerifier.java Mon Feb 23 11:37:36 2015 +0100 +++ b/test/sun/net/www/protocol/https/NewImpl/ComHostnameVerifier.java Mon Feb 23 15:48:20 2015 +0000 @@ -186,6 +186,17 @@ } } + private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory { + private static String SUPPORTED_PROTOCOL = "https"; + + public URLStreamHandler createURLStreamHandler(String protocol) { + if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL)) + return null; + + return new com.sun.net.ssl.internal.www.protocol.https.Handler(); + } + } + /* * Define the client side of the test. * @@ -200,8 +211,7 @@ Thread.sleep(50); } - System.setProperty("java.protocol.handler.pkgs", - "com.sun.net.ssl.internal.www.protocol"); + URL.setURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory()); System.setProperty("https.cipherSuites", "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");