All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kiwiproject.validation.Ipv4AddressValidator Maven / Gradle / Ivy

Go to download

Kiwi is a utility library. We really like Google's Guava, and also use Apache Commons. But if they don't have something we need, and we think it is useful, this is where we put it.

There is a newer version: 4.5.2
Show newest version
package org.kiwiproject.validation;

import static java.util.Objects.isNull;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.isBlank;

import com.google.common.annotations.VisibleForTesting;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Validates that a string value is a valid IPV4 address.
 *
 * @implNote The logic here was adapted from the Apache Commons Validator's {@code InetAddressValidator}, re-written
 * in a (somewhat) functional style that (we think) is more understandable and more easily testable since individual
 * checks have been extracted into helper methods.
 */
public class Ipv4AddressValidator implements ConstraintValidator {

    private static final String IPV4_REGEX = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
    private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4_REGEX);
    private static final int IPV4_MAX_OCTET_VALUE = 255;
    private static final int INVALID_IP_SEGMENT = -1;

    private Ipv4Address ipv4Address;

    @Override
    public void initialize(Ipv4Address constraintAnnotation) {
        this.ipv4Address = constraintAnnotation;
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (isNull(value)) {
            return ipv4Address.allowNull();
        }

        var matcher = IPV4_PATTERN.matcher(value);
        if (!matcher.matches()) {
            return false;
        }

        var segments = segmentsOf(matcher);
        return allSegmentsAreValid(segments);
    }

    private Stream segmentsOf(Matcher matcher) {
        return IntStream.rangeClosed(1, matcher.groupCount())
                .mapToObj(matcher::group)
                .collect(toList())
                .stream();
    }

    private boolean allSegmentsAreValid(Stream segmentStream) {
        var invalidSegmentCount = segmentStream.mapToInt(Ipv4AddressValidator::ipSegmentAsInt)
                .filter(Ipv4AddressValidator::isInvalidIpSegment)
                .count();

        return invalidSegmentCount == 0;
    }

    @VisibleForTesting
    static int ipSegmentAsInt(String ipSegment) {
        if (isBlank(ipSegment)) {
            return INVALID_IP_SEGMENT;
        }

        if (hasMoreThanOneDigitStartingWithZero(ipSegment)) {
            return INVALID_IP_SEGMENT;
        }

        try {
            return Integer.parseInt(ipSegment);
        } catch (NumberFormatException e) {
            return INVALID_IP_SEGMENT;
        }
    }

    private static boolean hasMoreThanOneDigitStartingWithZero(String ipSegment) {
        return ipSegment.length() > 1 && ipSegment.startsWith("0");
    }

    @VisibleForTesting
    static boolean isInvalidIpSegment(int ipSegment) {
        return ipSegment < 0 || ipSegment > IPV4_MAX_OCTET_VALUE;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy