Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand All @@ -31,6 +35,7 @@
* strategies for IP addresses.
*
* @author Rob Winch
* @author Andrey Litvitski
* @since 7.1
*/
public final class InetAddressMatchers {
Expand Down Expand Up @@ -86,42 +91,44 @@ public static InetAddressMatcher fromIpAddress(String ipAddress) {
* @author Gábor Vaspöri
* @author Rossen Stoyanchev
* @author Rob Winch
* @author Andrey Litvitski
*/
public static final class Builder {

private final List<InetAddressMatcher> matchers = new ArrayList<>();
private final Set<String> includeAddresses = new LinkedHashSet<>();

private final Set<String> excludeAddresses = new LinkedHashSet<>();
Comment on lines +98 to +100
Copy link
Copy Markdown
Contributor Author

@therepanic therepanic Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be more obvious if we used LinkedHashSet? When debugging, the user will see the addresses added to the list in the order they were added.


private final List<InetAddressMatcher> customMatchers = new ArrayList<>();

private boolean reportOnly;

/**
* Adds an include list matcher that permits only the specified addresses.
* Adds IP address patterns to the include list that permits only the specified
* addresses. If called multiple times, the addresses are combined into a single
* include rule.
* @param addresses the list of IP address patterns to include (cannot be null or
* empty)
* @return this builder for method chaining
* @throws IllegalArgumentException if addresses is null or empty
*/
public Builder includeAddresses(List<String> addresses) {
Assert.notEmpty(addresses, "addresses cannot be empty");
List<InetAddressMatcher> matchers = addresses.stream()
.<InetAddressMatcher>map(IpInetAddressMatcher::new)
.toList();
this.matchers.add(new IncludeListInetAddressMatcher(matchers));
this.includeAddresses.addAll(addresses);
return this;
}

/**
* Adds an exclude list matcher that blocks the specified addresses.
* Adds IP address patterns to the exclude list that blocks the specified
* addresses.
* @param addresses the list of IP address patterns to exclude (cannot be null or
* empty)
* @return this builder for method chaining
* @throws IllegalArgumentException if addresses is null or empty
*/
public Builder excludeAddresses(List<String> addresses) {
Assert.notEmpty(addresses, "addresses cannot be empty");
List<InetAddressMatcher> matchers = addresses.stream()
.<InetAddressMatcher>map(IpInetAddressMatcher::new)
.toList();
this.matchers.add(new ExcludeListInetAddressMatcher(matchers));
this.excludeAddresses.addAll(addresses);
return this;
}

Expand All @@ -135,9 +142,7 @@ public Builder excludeAddresses(List<String> addresses) {
*/
public Builder matchAll(InetAddressMatcher... matchers) {
Assert.notEmpty(matchers, "matchers cannot be empty");
for (InetAddressMatcher matcher : matchers) {
this.matchers.add(matcher);
}
Collections.addAll(this.customMatchers, matchers);
return this;
}

Expand All @@ -157,7 +162,23 @@ public Builder reportOnly() {
* @return the constructed {@link InetAddressMatcher}
*/
public InetAddressMatcher build() {
return new CompositeInetAddressMatcher(this.matchers, this.reportOnly);
List<InetAddressMatcher> result = new ArrayList<>();
if (!this.includeAddresses.isEmpty()) {
result.add(createListMatcher(this.includeAddresses, IncludeListInetAddressMatcher::new));
}
if (!this.excludeAddresses.isEmpty()) {
result.add(createListMatcher(this.excludeAddresses, ExcludeListInetAddressMatcher::new));
}
result.addAll(this.customMatchers);
return new CompositeInetAddressMatcher(result, this.reportOnly);
}

private InetAddressMatcher createListMatcher(Set<String> addresses,
Function<List<InetAddressMatcher>, InetAddressMatcher> constructor) {
List<InetAddressMatcher> matchers = addresses.stream()
.<InetAddressMatcher>map(IpInetAddressMatcher::new)
.toList();
return constructor.apply(matchers);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* Tests for {@link InetAddressMatchers}.
*
* @author Rob Winch
* @author Andrey Litvitski
*/
class InetAddressMatchersTests {

Expand Down Expand Up @@ -200,6 +201,17 @@ void buildWhenMultipleMatchersThenAppliesAndLogic(String testAddress) throws Exc
assertThat(matcher.matches(address)).isEqualTo(expected);
}

@Test
void includeAddressesWhenCalledMultipleTimesThenMatchesAllAddresses() throws Exception {
InetAddressMatcher matcher = InetAddressMatchers.builder()
.includeAddresses(List.of("192.168.1.1"))
.includeAddresses(List.of("10.0.0.1"))
.build();
assertThat(matcher.matches(InetAddress.getByName("192.168.1.1"))).isTrue();
assertThat(matcher.matches(InetAddress.getByName("10.0.0.1"))).isTrue();
assertThat(matcher.matches(InetAddress.getByName("8.8.8.8"))).isFalse();
}

}

@Nested
Expand Down
Loading