# HG changeset patch # User psandoz # Date 1433830202 -3600 # Node ID 92cc72d2a11a338dd79738503eaad2290677bad0 # Parent 6cd3ae8de51c1195d2373a9ce9be3d96e0683f88 8081678: Add Stream returning methods to classes where there currently exist only Enumeration returning methods Reviewed-by: lancea, alanb, chegar, dfuchs, mullan, smarks diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/src/java.base/share/classes/java/net/NetworkInterface.java --- a/jdk/src/java.base/share/classes/java/net/NetworkInterface.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/net/NetworkInterface.java Tue Jun 09 07:10:02 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -25,10 +25,14 @@ package java.net; +import java.util.Arrays; import java.util.Enumeration; import java.util.NoSuchElementException; -import sun.security.action.*; import java.security.AccessController; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * This class represents a Network Interface made up of a name, @@ -95,8 +99,8 @@ } /** - * Convenience method to return an Enumeration with all or a - * subset of the InetAddresses bound to this network interface. + * Get an Enumeration with all or a subset of the InetAddresses bound to + * this network interface. *

* If there is a security manager, its {@code checkConnect} * method is called for each InetAddress. Only InetAddresses where @@ -104,53 +108,56 @@ * will be returned in the Enumeration. However, if the caller has the * {@link NetPermission}("getNetworkInformation") permission, then all * InetAddresses are returned. + * * @return an Enumeration object with all or a subset of the InetAddresses * bound to this network interface + * @see #inetAddresses() */ public Enumeration getInetAddresses() { - - class checkedAddresses implements Enumeration { - - private int i=0, count=0; - private InetAddress local_addrs[]; - - checkedAddresses() { - local_addrs = new InetAddress[addrs.length]; - boolean trusted = true; + return enumerationFromArray(getCheckedInetAddresses()); + } - SecurityManager sec = System.getSecurityManager(); - if (sec != null) { - try { - sec.checkPermission(new NetPermission("getNetworkInformation")); - } catch (SecurityException e) { - trusted = false; - } - } - for (int j=0; j + * If there is a security manager, its {@code checkConnect} + * method is called for each InetAddress. Only InetAddresses where + * the {@code checkConnect} doesn't throw a SecurityException will be + * returned in the Stream. However, if the caller has the + * {@link NetPermission}("getNetworkInformation") permission, then all + * InetAddresses are returned. + * + * @return a Stream object with all or a subset of the InetAddresses + * bound to this network interface + * @since 1.9 + */ + public Stream inetAddresses() { + return streamFromArray(getCheckedInetAddresses()); + } - } + private InetAddress[] getCheckedInetAddresses() { + InetAddress[] local_addrs = new InetAddress[addrs.length]; + boolean trusted = true; - public InetAddress nextElement() { - if (i < count) { - return local_addrs[i++]; - } else { - throw new NoSuchElementException(); - } - } - - public boolean hasMoreElements() { - return (i < count); + SecurityManager sec = System.getSecurityManager(); + if (sec != null) { + try { + sec.checkPermission(new NetPermission("getNetworkInformation")); + } catch (SecurityException e) { + trusted = false; } } - return new checkedAddresses(); - + int i = 0; + for (int j = 0; j < addrs.length; j++) { + try { + if (!trusted) { + sec.checkConnect(addrs[j].getHostAddress(), -1); + } + local_addrs[i++] = addrs[j]; + } catch (SecurityException e) { } + } + return Arrays.copyOf(local_addrs, i); } /** @@ -188,30 +195,23 @@ * * @return an Enumeration object with all of the subinterfaces * of this network interface + * @see #subInterfaces() * @since 1.6 */ public Enumeration getSubInterfaces() { - class subIFs implements Enumeration { - - private int i=0; - - subIFs() { - } + return enumerationFromArray(childs); + } - public NetworkInterface nextElement() { - if (i < childs.length) { - return childs[i++]; - } else { - throw new NoSuchElementException(); - } - } - - public boolean hasMoreElements() { - return (i < childs.length); - } - } - return new subIFs(); - + /** + * Get a Stream of all subinterfaces (also known as virtual + * interfaces) attached to this network interface. + * + * @return a Stream object with all of the subinterfaces + * of this network interface + * @since 1.9 + */ + public Stream subInterfaces() { + return streamFromArray(childs); } /** @@ -326,43 +326,80 @@ } /** - * Returns all the interfaces on this machine. The {@code Enumeration} - * contains at least one element, possibly representing a loopback - * interface that only supports communication between entities on + * Returns an {@code Enumeration} of all the interfaces on this machine. The + * {@code Enumeration} contains at least one element, possibly representing + * a loopback interface that only supports communication between entities on * this machine. * - * NOTE: can use getNetworkInterfaces()+getInetAddresses() - * to obtain all IP addresses for this node + * @apiNote this method can be used in combination with + * {@link #getInetAddresses()} to obtain all IP addresses for this node * * @return an Enumeration of NetworkInterfaces found on this machine * @exception SocketException if an I/O error occurs. + * @see #networkInterfaces() */ - public static Enumeration getNetworkInterfaces() throws SocketException { - final NetworkInterface[] netifs = getAll(); + NetworkInterface[] netifs = getAll(); + assert netifs != null && netifs.length > 0; - // specified to return null if no network interfaces - if (netifs == null) - return null; + return enumerationFromArray(netifs); + } + /** + * Returns a {@code Stream} of all the interfaces on this machine. The + * {@code Stream} contains at least one interface, possibly representing a + * loopback interface that only supports communication between entities on + * this machine. + * + * @apiNote this method can be used in combination with + * {@link #inetAddresses()}} to obtain a stream of all IP addresses for + * this node, for example: + *

 {@code
+     * Stream addrs = NetworkInterface.networkInterfaces()
+     *     .flatMap(NetworkInterface::inetAddresses);
+     * }
+ * + * @return a Stream of NetworkInterfaces found on this machine + * @exception SocketException if an I/O error occurs. + * @since 1.9 + */ + public static Stream networkInterfaces() + throws SocketException { + NetworkInterface[] netifs = getAll(); + assert netifs != null && netifs.length > 0; + + return streamFromArray(netifs); + } + + private static Enumeration enumerationFromArray(T[] a) { return new Enumeration<>() { - private int i = 0; - public NetworkInterface nextElement() { - if (netifs != null && i < netifs.length) { - NetworkInterface netif = netifs[i++]; - return netif; + int i = 0; + + @Override + public T nextElement() { + if (i < a.length) { + return a[i++]; } else { throw new NoSuchElementException(); } } + @Override public boolean hasMoreElements() { - return (netifs != null && i < netifs.length); + return i < a.length; } }; } + private static Stream streamFromArray(T[] a) { + return StreamSupport.stream( + Spliterators.spliterator( + a, + Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL), + false); + } + private native static NetworkInterface[] getAll() throws SocketException; diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/src/java.base/share/classes/java/security/PermissionCollection.java --- a/jdk/src/java.base/share/classes/java/security/PermissionCollection.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/security/PermissionCollection.java Tue Jun 09 07:10:02 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -26,6 +26,8 @@ package java.security; import java.util.*; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * Abstract class representing a collection of Permission objects. @@ -126,10 +128,35 @@ * Returns an enumeration of all the Permission objects in the collection. * * @return an enumeration of all the Permissions. + * @see #elementsAsStream() */ public abstract Enumeration elements(); /** + * Returns a stream of all the Permission objects in the collection. + * + *

The collection should not be modified (see {@link #add}) during the + * execution of the terminal stream operation. Otherwise, the result of the + * terminal stream operation is undefined. + * + * @implSpec + * The default implementation creates a stream whose source is derived from + * the enumeration returned from a call to {@link #elements()}. + * + * @return a stream of all the Permissions. + * @since 1.9 + */ + public Stream elementsAsStream() { + int characteristics = isReadOnly() + ? Spliterator.NONNULL | Spliterator.IMMUTABLE + : Spliterator.NONNULL; + return StreamSupport.stream( + Spliterators.spliteratorUnknownSize( + elements().asIterator(), characteristics), + false); + } + + /** * Marks this PermissionCollection object as "readonly". After * a PermissionCollection object * is marked as readonly, no new Permission objects can be added to it diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/src/java.base/share/classes/java/util/Collections.java --- a/jdk/src/java.base/share/classes/java/util/Collections.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/util/Collections.java Tue Jun 09 07:10:02 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -4268,6 +4268,7 @@ public boolean hasMoreElements() { return false; } public E nextElement() { throw new NoSuchElementException(); } + public Iterator asIterator() { return emptyIterator(); } } /** @@ -5199,6 +5200,11 @@ * interoperability with legacy APIs that require an enumeration * as input. * + *

The iterator returned from a call to {@link Enumeration#asIterator()} + * does not support removal of elements from the specified collection. This + * is necessary to avoid unintentionally increasing the capabilities of the + * returned enumeration. + * * @param the class of the objects in the collection * @param c the collection for which an enumeration is to be returned. * @return an enumeration over the specified collection. diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/src/java.base/share/classes/java/util/jar/JarFile.java --- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Tue Jun 09 07:10:02 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -265,6 +265,10 @@ public JarEntry nextElement() { return next(); } + + public Iterator asIterator() { + return this; + } } /** diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/src/java.base/share/classes/java/util/zip/ZipFile.java --- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Tue Jun 09 07:10:02 2015 +0100 @@ -526,6 +526,10 @@ return ze; } } + + public Iterator asIterator() { + return this; + } } /** diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/src/java.sql/share/classes/java/sql/DriverManager.java --- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java Tue Jun 09 07:10:02 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -25,11 +25,17 @@ package java.sql; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; import java.util.Iterator; +import java.util.List; import java.util.ServiceLoader; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Stream; + import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -429,29 +435,44 @@ * d.getClass().getName() * * @return the list of JDBC Drivers loaded by the caller's class loader + * @see #drivers() */ @CallerSensitive - public static java.util.Enumeration getDrivers() { - java.util.Vector result = new java.util.Vector<>(); - + public static Enumeration getDrivers() { ensureDriversInitialized(); - Class callerClass = Reflection.getCallerClass(); + return Collections.enumeration(getDrivers(Reflection.getCallerClass())); + } + /** + * Retrieves a Stream with all of the currently loaded JDBC drivers + * to which the current caller has access. + * + * @return the stream of JDBC Drivers loaded by the caller's class loader + * @since 1.9 + */ + @CallerSensitive + public static Stream drivers() { + ensureDriversInitialized(); + + return getDrivers(Reflection.getCallerClass()).stream(); + } + + private static List getDrivers(Class callerClass) { + List result = new ArrayList<>(); // Walk through the loaded registeredDrivers. for (DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if (isDriverAllowed(aDriver.driver, callerClass)) { - result.addElement(aDriver.driver); + result.add(aDriver.driver); } else { println(" skipping: " + aDriver.getClass().getName()); } } - return (result.elements()); + return result; } - /** * Sets the maximum time in seconds that a driver will wait * while attempting to connect to a database once the driver has diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java Tue Jun 09 07:10:02 2015 +0100 @@ -0,0 +1,135 @@ +/* + * 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. + */ + +/* @test + * @bug 8081678 + * @summary Tests for stream returning methods + * @library ../../util/stream/bootlib + * @build java.util.stream.OpTestCase + * @run testng/othervm NetworkInterfaceStreamTest + * @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest + */ + +import org.testng.annotations.Test; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Supplier; +import java.util.stream.OpTestCase; +import java.util.stream.Stream; +import java.util.stream.TestData; + +public class NetworkInterfaceStreamTest extends OpTestCase { + + @Test + public void testNetworkInterfaces() throws SocketException { + Supplier> ss = () -> { + try { + return NetworkInterface.networkInterfaces(); + } + catch (SocketException e) { + throw new RuntimeException(e); + } + }; + + Collection expected = Collections.list(NetworkInterface.getNetworkInterfaces()); + withData(TestData.Factory.ofSupplier("Top-level network interfaces", ss)) + .stream(s -> s) + .expectedResult(expected) + .exercise(); + } + + + private Collection getAllNetworkInterfaces() throws SocketException { + Collection anis = new ArrayList<>(); + for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) { + getAllSubNetworkInterfaces(ni, anis); + } + return anis; + } + + private void getAllSubNetworkInterfaces(NetworkInterface ni, Collection result) { + result.add(ni); + + for (NetworkInterface sni : Collections.list(ni.getSubInterfaces())) { + getAllSubNetworkInterfaces(sni, result); + } + } + + private Stream allNetworkInterfaces() throws SocketException { + return NetworkInterface.networkInterfaces().flatMap(this::allSubNetworkInterfaces); + } + + private Stream allSubNetworkInterfaces(NetworkInterface ni) { + return Stream.concat( + Stream.of(ni), + ni.subInterfaces().flatMap(this::allSubNetworkInterfaces)); + } + + @Test + public void testSubNetworkInterfaces() throws SocketException { + Supplier> ss = () -> { + try { + return allNetworkInterfaces(); + } + catch (SocketException e) { + throw new RuntimeException(e); + } + }; + + Collection expected = getAllNetworkInterfaces(); + withData(TestData.Factory.ofSupplier("All network interfaces", ss)) + .stream(s -> s) + .expectedResult(expected) + .exercise(); + } + + + @Test + public void testInetAddresses() throws SocketException { + Supplier> ss = () -> { + try { + return NetworkInterface.networkInterfaces().flatMap(NetworkInterface::inetAddresses); + } + catch (SocketException e) { + throw new RuntimeException(e); + } + }; + + Collection nis = Collections.list(NetworkInterface.getNetworkInterfaces()); + Collection expected = new ArrayList<>(); + for (NetworkInterface ni : nis) { + expected.addAll(Collections.list(ni.getInetAddresses())); + } + withData(TestData.Factory.ofSupplier("All inet addresses", ss)) + .stream(s -> s) + .expectedResult(expected) + .exercise(); + } + + +} diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java Tue Jun 09 07:10:02 2015 +0100 @@ -0,0 +1,82 @@ +/* + * 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. + */ + +/* @test + * @bug 8081678 + * @summary Tests for stream returning methods + * @library ../../util/stream/bootlib + * @build java.util.stream.OpTestCase + * @run testng/othervm PermissionCollectionStreamTest + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.FilePermission; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Supplier; +import java.util.stream.OpTestCase; +import java.util.stream.Stream; +import java.util.stream.TestData; + +public class PermissionCollectionStreamTest extends OpTestCase { + + @DataProvider + public static Object[][] permissions() { + return new Object[][]{ + { + "FilePermission", + new Permission[]{ + new FilePermission("/home/foobar", "read"), + new FilePermission("/home/foo", "write"), + new FilePermission("/home/foobar", "read,write"), + } + }, + }; + } + + + private PermissionCollection create(Permission[] pa) { + PermissionCollection pc = pa[0].newPermissionCollection(); + for (Permission p : pa) { + pc.add(p); + } + return pc; + } + + @Test(dataProvider = "permissions") + public void testElementsAsStream(String description, Permission[] pa) { + PermissionCollection pc = create(pa); + + Supplier> ss = pc::elementsAsStream; + + Collection expected = Collections.list(pc.elements()); + withData(TestData.Factory.ofSupplier(description, ss)) + .stream(s -> s) + .expectedResult(expected) + .exercise(); + } +} diff -r 6cd3ae8de51c -r 92cc72d2a11a jdk/test/java/sql/testng/test/sql/DriverManagerTests.java --- a/jdk/test/java/sql/testng/test/sql/DriverManagerTests.java Tue Jun 30 17:48:06 2015 -0700 +++ b/jdk/test/java/sql/testng/test/sql/DriverManagerTests.java Tue Jun 09 07:10:02 2015 +0100 @@ -34,7 +34,11 @@ import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; +import java.util.Collection; +import java.util.Collections; import java.util.Properties; +import java.util.stream.Collectors; + import static org.testng.Assert.*; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; @@ -351,4 +355,24 @@ assertTrue(result.equals(reader.readLine())); } } + + /** + * Register some driver implementations and validate that the driver + * elements covered by the Enumeration obtained from + * {@link DriverManager#getDrivers()} are the same as driver elements + * covered by the stream obtained from {@link DriverManager#drivers()}} + */ + @Test + public void tests19() throws Exception { + int n = 8; + for (int i = 0; i < n; i++) { + DriverManager.registerDriver(new StubDriver()); + } + + Collection expectedDrivers = Collections.list(DriverManager.getDrivers()); + assertEquals(expectedDrivers.size(), n); + Collection drivers = DriverManager.drivers().collect(Collectors.toList()); + + assertEquals(drivers, expectedDrivers); + } }