8081678: Add Stream returning methods to classes where there currently exist only Enumeration returning methods

Reviewed-by: lancea, alanb, chegar, dfuchs, mullan, smarks
This commit is contained in:
Paul Sandoz 2015-06-09 07:10:02 +01:00
parent efa84f658a
commit e56c76e9f7
9 changed files with 429 additions and 89 deletions

View File

@ -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 @@ public final class NetworkInterface {
}
/**
* 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.
* <p>
* If there is a security manager, its {@code checkConnect}
* method is called for each InetAddress. Only InetAddresses where
@ -104,53 +108,56 @@ public final class NetworkInterface {
* 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<InetAddress> getInetAddresses() {
return enumerationFromArray(getCheckedInetAddresses());
}
class checkedAddresses implements Enumeration<InetAddress> {
/**
* Get a Stream of all or a subset of the InetAddresses bound to this
* network interface.
* <p>
* 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<InetAddress> inetAddresses() {
return streamFromArray(getCheckedInetAddresses());
}
private int i=0, count=0;
private InetAddress local_addrs[];
private InetAddress[] getCheckedInetAddresses() {
InetAddress[] local_addrs = new InetAddress[addrs.length];
boolean trusted = true;
checkedAddresses() {
local_addrs = new InetAddress[addrs.length];
boolean trusted = true;
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
try {
sec.checkPermission(new NetPermission("getNetworkInformation"));
} catch (SecurityException e) {
trusted = false;
}
}
for (int j=0; j<addrs.length; j++) {
try {
if (sec != null && !trusted) {
sec.checkConnect(addrs[j].getHostAddress(), -1);
}
local_addrs[count++] = addrs[j];
} catch (SecurityException e) { }
}
}
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 @@ public final class NetworkInterface {
*
* @return an Enumeration object with all of the subinterfaces
* of this network interface
* @see #subInterfaces()
* @since 1.6
*/
public Enumeration<NetworkInterface> getSubInterfaces() {
class subIFs implements Enumeration<NetworkInterface> {
private int i=0;
subIFs() {
}
public NetworkInterface nextElement() {
if (i < childs.length) {
return childs[i++];
} else {
throw new NoSuchElementException();
}
}
public boolean hasMoreElements() {
return (i < childs.length);
}
}
return new subIFs();
return enumerationFromArray(childs);
}
/**
* 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<NetworkInterface> subInterfaces() {
return streamFromArray(childs);
}
/**
@ -326,43 +326,80 @@ public final class NetworkInterface {
}
/**
* 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<NetworkInterface> 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:
* <pre> {@code
* Stream<InetAddress> addrs = NetworkInterface.networkInterfaces()
* .flatMap(NetworkInterface::inetAddresses);
* }</pre>
*
* @return a Stream of NetworkInterfaces found on this machine
* @exception SocketException if an I/O error occurs.
* @since 1.9
*/
public static Stream<NetworkInterface> networkInterfaces()
throws SocketException {
NetworkInterface[] netifs = getAll();
assert netifs != null && netifs.length > 0;
return streamFromArray(netifs);
}
private static <T> Enumeration<T> 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 <T> Stream<T> streamFromArray(T[] a) {
return StreamSupport.stream(
Spliterators.spliterator(
a,
Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL),
false);
}
private native static NetworkInterface[] getAll()
throws SocketException;

View File

@ -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,9 +128,34 @@ public abstract class PermissionCollection implements java.io.Serializable {
* Returns an enumeration of all the Permission objects in the collection.
*
* @return an enumeration of all the Permissions.
* @see #elementsAsStream()
*/
public abstract Enumeration<Permission> elements();
/**
* Returns a stream of all the Permission objects in the collection.
*
* <p> 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<Permission> 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

View File

@ -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 class Collections {
public boolean hasMoreElements() { return false; }
public E nextElement() { throw new NoSuchElementException(); }
public Iterator<E> asIterator() { return emptyIterator(); }
}
/**
@ -5199,6 +5200,11 @@ public class Collections {
* interoperability with legacy APIs that require an enumeration
* as input.
*
* <p>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 <T> 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.

View File

@ -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 @@ class JarFile extends ZipFile {
public JarEntry nextElement() {
return next();
}
public Iterator<JarEntry> asIterator() {
return this;
}
}
/**

View File

@ -526,6 +526,10 @@ class ZipFile implements ZipConstants, Closeable {
return ze;
}
}
public Iterator<ZipEntry> asIterator() {
return this;
}
}
/**

View File

@ -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 @@ public class DriverManager {
* <CODE>d.getClass().getName()</CODE>
*
* @return the list of JDBC Drivers loaded by the caller's class loader
* @see #drivers()
*/
@CallerSensitive
public static java.util.Enumeration<Driver> getDrivers() {
java.util.Vector<Driver> result = new java.util.Vector<>();
public static Enumeration<Driver> 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<Driver> drivers() {
ensureDriversInitialized();
return getDrivers(Reflection.getCallerClass()).stream();
}
private static List<Driver> getDrivers(Class<?> callerClass) {
List<Driver> 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

View File

@ -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<Stream<NetworkInterface>> ss = () -> {
try {
return NetworkInterface.networkInterfaces();
}
catch (SocketException e) {
throw new RuntimeException(e);
}
};
Collection<NetworkInterface> expected = Collections.list(NetworkInterface.getNetworkInterfaces());
withData(TestData.Factory.ofSupplier("Top-level network interfaces", ss))
.stream(s -> s)
.expectedResult(expected)
.exercise();
}
private Collection<NetworkInterface> getAllNetworkInterfaces() throws SocketException {
Collection<NetworkInterface> anis = new ArrayList<>();
for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) {
getAllSubNetworkInterfaces(ni, anis);
}
return anis;
}
private void getAllSubNetworkInterfaces(NetworkInterface ni, Collection<NetworkInterface> result) {
result.add(ni);
for (NetworkInterface sni : Collections.list(ni.getSubInterfaces())) {
getAllSubNetworkInterfaces(sni, result);
}
}
private Stream<NetworkInterface> allNetworkInterfaces() throws SocketException {
return NetworkInterface.networkInterfaces().flatMap(this::allSubNetworkInterfaces);
}
private Stream<NetworkInterface> allSubNetworkInterfaces(NetworkInterface ni) {
return Stream.concat(
Stream.of(ni),
ni.subInterfaces().flatMap(this::allSubNetworkInterfaces));
}
@Test
public void testSubNetworkInterfaces() throws SocketException {
Supplier<Stream<NetworkInterface>> ss = () -> {
try {
return allNetworkInterfaces();
}
catch (SocketException e) {
throw new RuntimeException(e);
}
};
Collection<NetworkInterface> expected = getAllNetworkInterfaces();
withData(TestData.Factory.ofSupplier("All network interfaces", ss))
.stream(s -> s)
.expectedResult(expected)
.exercise();
}
@Test
public void testInetAddresses() throws SocketException {
Supplier<Stream<InetAddress>> ss = () -> {
try {
return NetworkInterface.networkInterfaces().flatMap(NetworkInterface::inetAddresses);
}
catch (SocketException e) {
throw new RuntimeException(e);
}
};
Collection<NetworkInterface> nis = Collections.list(NetworkInterface.getNetworkInterfaces());
Collection<InetAddress> 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();
}
}

View File

@ -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<Stream<Permission>> ss = pc::elementsAsStream;
Collection<Permission> expected = Collections.list(pc.elements());
withData(TestData.Factory.ofSupplier(description, ss))
.stream(s -> s)
.expectedResult(expected)
.exercise();
}
}

View File

@ -34,7 +34,11 @@ import java.io.PrintWriter;
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 @@ public class DriverManagerTests {
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<Driver> expectedDrivers = Collections.list(DriverManager.getDrivers());
assertEquals(expectedDrivers.size(), n);
Collection<Driver> drivers = DriverManager.drivers().collect(Collectors.toList());
assertEquals(drivers, expectedDrivers);
}
}