Skip to content

Commit

Permalink
Add SubnetInfo.iterableAddressStrings()
Browse files Browse the repository at this point in the history
- Make new class SubnetAddressStringIterable private
- Make new class SubnetAddressStringIterator private
- Move private methods to statics
  • Loading branch information
garydgregory committed Oct 13, 2024
1 parent 851aa7a commit 779d77c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 50 deletions.
3 changes: 2 additions & 1 deletion src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ The <action> type attribute can be add,update,fix,remove.
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Gary Gregory">org.apache.commons.net.nntp.Article#getChild().</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">org.apache.commons.net.nntp.Article#getNext().</action>
<action type="add" dev="ggregory" due-to="Lixiongyou, Gary Gregory">Add SubnetAddressIterable and SubnetAddressIterator #298.</action>
<action type="add" dev="ggregory" due-to="Lixiongyou, Gary Gregory">Add SubnetAddressStringIterable and SubnetAddressStringIterator #298.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add SubnetInfo.iterableAddressStrings().</action>
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 70 to 77 #261, #278, #280, #285, #298, #293.</action>
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-lang3 from 3.14.0 to 3.17.0 #268, #273, #281.</action>
Expand Down
99 changes: 53 additions & 46 deletions src/main/java/org/apache/commons/net/util/SubnetUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ public class SubnetUtils {

/**
* Allows an object to be the target of the "for-each loop" statement for a SubnetInfo.
*
* @since 3.18.0
*/
public static final class SubnetAddressIterable implements Iterable<String> {
private static final class SubnetAddressStringIterable implements Iterable<String> {

private final SubnetInfo subnetInfo;

Expand All @@ -42,20 +40,20 @@ public static final class SubnetAddressIterable implements Iterable<String> {
*
* @param subnetInfo the SubnetInfo to iterate.
*/
public SubnetAddressIterable(final SubnetInfo subnetInfo) {
private SubnetAddressStringIterable(final SubnetInfo subnetInfo) {
this.subnetInfo = subnetInfo;
}

@Override
public Iterator<String> iterator() {
return new SubnetAddressIterator(subnetInfo);
return new SubnetAddressStringIterator(subnetInfo);
}
}

/**
* Iterates over a SubnetInfo.
*/
private static final class SubnetAddressIterator implements Iterator<String> {
private static final class SubnetAddressStringIterator implements Iterator<String> {

private int currentAddress;

Expand All @@ -66,7 +64,7 @@ private static final class SubnetAddressIterator implements Iterator<String> {
*
* @param subnetInfo the SubnetInfo to iterate.
*/
public SubnetAddressIterator(final SubnetInfo subnetInfo) {
private SubnetAddressStringIterator(final SubnetInfo subnetInfo) {
this.subnetInfo = subnetInfo;
currentAddress = subnetInfo.low();
}
Expand All @@ -78,9 +76,7 @@ public boolean hasNext() {

@Override
public String next() {
final String address = subnetInfo.format(subnetInfo.toArray(currentAddress));
currentAddress++;
return address;
return format(toArray4(currentAddress++));
}
}

Expand Down Expand Up @@ -109,28 +105,13 @@ private long broadcastLong() {
return broadcast & UNSIGNED_INT_MASK;
}

/**
* Converts a 4-element array into dotted decimal format.
*/
private String format(final int[] octets) {
final int last = octets.length - 1;
final StringBuilder builder = new StringBuilder();
for (int i = 0;; i++) {
builder.append(octets[i]);
if (i == last) {
return builder.toString();
}
builder.append('.');
}
}

/**
* Converts this instance's address into dotted decimal String.
*
* @return a dotted decimal String.
*/
public String getAddress() {
return format(toArray(address));
return format(toArray4(address));
}

/**
Expand Down Expand Up @@ -175,7 +156,7 @@ public String[] getAllAddresses() {
return addresses;
}
for (int add = low(), j = 0; add <= high(); ++add, ++j) {
addresses[j] = format(toArray(add));
addresses[j] = format(toArray4(add));
}
return addresses;
}
Expand All @@ -186,7 +167,7 @@ public String[] getAllAddresses() {
* @return the broadcast address for this subnet.
*/
public String getBroadcastAddress() {
return format(toArray(broadcast));
return format(toArray4(broadcast));
}

/**
Expand All @@ -195,7 +176,7 @@ public String getBroadcastAddress() {
* @return the CIDR signature for this subnet.
*/
public String getCidrSignature() {
return format(toArray(address)) + "/" + Integer.bitCount(netmask);
return format(toArray4(address)) + "/" + Integer.bitCount(netmask);
}

/**
Expand All @@ -204,7 +185,7 @@ public String getCidrSignature() {
* @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address
*/
public String getHighAddress() {
return format(toArray(high()));
return format(toArray4(high()));
}

/**
Expand All @@ -213,7 +194,7 @@ public String getHighAddress() {
* @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address
*/
public String getLowAddress() {
return format(toArray(low()));
return format(toArray4(low()));
}

/**
Expand All @@ -222,7 +203,7 @@ public String getLowAddress() {
* @return the network mask for this subnet.
*/
public String getNetmask() {
return format(toArray(netmask));
return format(toArray4(netmask));
}

/**
Expand All @@ -231,7 +212,7 @@ public String getNetmask() {
* @return the network address for this subnet.
*/
public String getNetworkAddress() {
return format(toArray(network));
return format(toArray4(network));
}

/**
Expand All @@ -240,7 +221,7 @@ public String getNetworkAddress() {
* @return the next address for this subnet.
*/
public String getNextAddress() {
return format(toArray(address + 1));
return format(toArray4(address + 1));
}

/**
Expand All @@ -249,7 +230,7 @@ public String getNextAddress() {
* @return the previous address for this subnet.
*/
public String getPreviousAddress() {
return format(toArray(address - 1));
return format(toArray4(address - 1));
}

private int high() {
Expand Down Expand Up @@ -285,6 +266,16 @@ public boolean isInRange(final String address) {
return isInRange(toInteger(address));
}

/**
* Creates a new Iterable of address Strings.
*
* @return a new Iterable of address Strings
* @since 3.12.0
*/
public Iterable<String> iterableAddressStrings() {
return new SubnetAddressStringIterable(this);
}

private int low() {
return isInclusiveHostCount() ? network : broadcastLong() - networkLong() > 1 ? network + 1 : 0;
}
Expand All @@ -294,17 +285,6 @@ private long networkLong() {
return network & UNSIGNED_INT_MASK;
}

/**
* Converts a packed integer address into a 4-element array
*/
private int[] toArray(final int val) {
final int[] ret = new int[4];
for (int j = 3; j >= 0; --j) {
ret[j] |= val >>> 8 * (3 - j) & 0xff;
}
return ret;
}

/**
* {@inheritDoc}
*
Expand All @@ -327,12 +307,28 @@ public String toString() {
}

private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})";

private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,2})"; // 0 -> 32

private static final Pattern ADDRESS_PATTERN = Pattern.compile(IP_ADDRESS);
private static final Pattern CIDR_PATTERN = Pattern.compile(SLASH_FORMAT);
private static final int NBITS = 32;
private static final String PARSE_FAIL = "Could not parse [%s]";

/**
* Converts a 4-element array into dotted decimal format.
*/
private static String format(final int[] octets) {
final int last = octets.length - 1;
final StringBuilder builder = new StringBuilder();
for (int i = 0;; i++) {
builder.append(octets[i]);
if (i == last) {
return builder.toString();
}
builder.append('.');
}
}
/**
* Extracts the components of a dotted decimal address and pack into an integer using a regex match
*/
Expand All @@ -355,6 +351,17 @@ private static int rangeCheck(final int value, final int begin, final int end) {
throw new IllegalArgumentException("Value [" + value + "] not in range [" + begin + "," + end + "]");
}

/**
* Converts a packed integer address into a 4-element array
*/
private static int[] toArray4(final int val) {
final int[] ret = new int[4];
for (int j = 3; j >= 0; --j) {
ret[j] |= val >>> 8 * (3 - j) & 0xff;
}
return ret;
}

/**
* Converts a dotted decimal format address to a packed integer format.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.FieldSource;

/**
* Tests {@link SubnetUtils}.
*/
@SuppressWarnings("deprecation") // deliberate use of deprecated methods
public class SubnetUtilsTest {

Expand Down Expand Up @@ -461,9 +464,9 @@ public void testSubnetAddressIterable() {
}

private void testSubnetAddressIterable(final String cidrNotation, final long max) {
final SubnetUtils utils = new SubnetUtils(cidrNotation);
final SubnetUtils subnetUtils = new SubnetUtils(cidrNotation);
final List<String> addressList = new ArrayList<>();
new SubnetUtils.SubnetAddressIterable(utils.getInfo()).forEach(addressList::add);
subnetUtils.getInfo().iterableAddressStrings().forEach(addressList::add);
assertEquals(max, addressList.size());
LongStream.rangeClosed(1, max).forEach(i -> addressList.contains("192.168.1." + i));
assertFalse(addressList.contains("192.168.1.0"));
Expand All @@ -478,7 +481,7 @@ public void testSubnetAddressIterableCount(final ImmutablePair<String, Long> pai
final SubnetUtils subnetUtils = new SubnetUtils(cidrNotation);
// Fixture values includes counting the host
subnetUtils.setInclusiveHostCount(true);
assertEquals(max, IterableUtils.size(new SubnetUtils.SubnetAddressIterable(subnetUtils.getInfo())));
assertEquals(max, IterableUtils.size(subnetUtils.getInfo().iterableAddressStrings()));
}

@Test
Expand Down

0 comments on commit 779d77c

Please sign in to comment.