package org.ovirt.engine.core.common.utils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.metadata.ConstraintDescriptor;
import org.ovirt.engine.core.common.businessentities.BusinessEntitiesDefinitions;
import org.ovirt.engine.core.common.businessentities.VmPool;
import org.ovirt.engine.core.common.errors.EngineMessage;
public class ValidationUtils {
public static final String NO_SPECIAL_CHARACTERS_EXTRA_I18N = "^[\\p{L}0-9._\\+-]*$";
public static final String NO_SPECIAL_CHARACTERS_I18N = "^[\\p{L}0-9._-]*$";
public static final String NO_SPECIAL_CHARACTERS = "[0-9a-zA-Z_-]+";
public static final String ONLY_I18N_ASCII_OR_NONE = "[\\p{ASCII}\\p{L}]*";
public static final String ONLY_ASCII_OR_NONE = "[\\p{ASCII}]*";
public static final String NO_SPECIAL_CHARACTERS_WITH_DOT = "[0-9a-zA-Z-_\\.]+";
public static final String NO_TRIMMING_WHITE_SPACES_PATTERN = "^$|\\S.*\\S";
public static final String IPV4_PATTERN_NON_EMPTY =
"\\b((25[0-5]|2[0-4]\\d|[01]\\d\\d|\\d?\\d)\\.){3}(25[0-5]|2[0-4]\\d|[01]\\d\\d|\\d?\\d)";
public static final String IPV4_PATTERN = "^" + IPV4_PATTERN_NON_EMPTY + "$|^$";
private static final String IPV6_ADDRESS_BLOCK = "[0-9a-fA-F]{1,4}";
private static final String IPV6_HEX_COMPRESSED_PATTERN =
"((?:" + IPV6_ADDRESS_BLOCK + "(?::" + IPV6_ADDRESS_BLOCK + ")*)?)::((?:" +
IPV6_ADDRESS_BLOCK + "(?::" + IPV6_ADDRESS_BLOCK + ")*)?)";
private static final String IPV6_STD_PATTERN = "(?:" + IPV6_ADDRESS_BLOCK + ":){7}" + IPV6_ADDRESS_BLOCK;
public static final String IPV6_PATTERN = "(?:" + IPV6_STD_PATTERN + "|" + IPV6_HEX_COMPRESSED_PATTERN + ")";
public static final String IPV4_OR_IPV6_PATTERN = IPV4_PATTERN + "|" + IPV6_PATTERN;
public static final String IPV6_FOR_URI = "\\[" + IPV6_PATTERN + "\\]";
public static final String ANY_IP_PATTERN = "^(" + IPV4_PATTERN_NON_EMPTY + "|" + IPV6_PATTERN +")$";
public static final String FQDN_PATTERN =
"([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]))*";
public static final String HOSTNAME_FOR_URI =
"(?:" + FQDN_PATTERN + "|" + IPV4_PATTERN + "|" + IPV6_FOR_URI + ")";
public static final String SUBNET_PREFIX_PATTERN = "(?:3[0-2]|[12]?[0-9])";
public static final String CIDR_FORMAT_PATTERN = "^" + IPV4_PATTERN_NON_EMPTY + "/" + SUBNET_PREFIX_PATTERN + "$";
public static final String ISO_SUFFIX = ".iso";
public static final String ISO_SUFFIX_PATTERN = "^$|^.+\\.iso$";
public static final String BASE_64_PATTERN =
"^([A-Za-z0-9+/]{4})*(()|[A-Za-z0-9+/][AQgw]==|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=)$";
public static final String KEY_EQUALS_VALUE_SPACE_SEPARATED = "^[^\\s=]+=[^\\s=]+(\\s+[^\\s=]+=[^\\s=]+)*$";
public static final String EMPTY_STRING = "^$";
public static final String NO_WHITESPACE = "[^\\s]+";
/**
* the mask will be replaced with zero-padded number in the generated names of the VMs in the pool, see
* NameForVmInPoolGeneratorTest PoolNameValidationTest for valid and invalid expressions of this pattern
*/
public static final String POOL_NAME_PATTERN = "^[\\p{L}0-9._-]+[" + VmPool.MASK_CHARACTER
+ "]*[\\p{L}0-9._-]*$|^[\\p{L}0-9._-]*[" + VmPool.MASK_CHARACTER + "]*[\\p{L}0-9._-]+$";
private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
/***
* This function validates a hostname according to URI RFC's.
*/
public static boolean validHostname(String address) {
if (address == null || address.trim().isEmpty()) {
return false;
}
return isValidIpAddressOrHostname(address) || isValidIpv6Address(address);
}
private static boolean isValidIpAddressOrHostname(String address) {
try {
URI uri = new URI("http://" + address);
return address.equals(uri.getHost());
} catch (URISyntaxException use) {
return false;
}
}
private static boolean isValidIpv6Address(String address) {
final String quotedIpv6 = "[" + address + "]";
return isValidIpAddressOrHostname(quotedIpv6);
}
public static boolean validUri(String addr) {
try {
new URI(addr);
return true;
} catch (URISyntaxException use) {
return false;
}
}
public static Validator getValidator() {
return validator;
}
/**
* @return A list of error message keys representing the violations, or empty list if no violations occurred.
*/
public static <T> List<String> validateInputs(List<Class<?>> validationGroupList, T parameters) {
List<String> messages = Collections.emptyList();
Set<ConstraintViolation<T>> violations = ValidationUtils.getValidator().validate(parameters,
validationGroupList.toArray(new Class<?>[validationGroupList.size()]));
if (!violations.isEmpty()) {
messages = new ArrayList<>(violations.size());
for (ConstraintViolation<T> constraintViolation : violations) {
messages.add(constraintViolation.getMessage());
ConstraintDescriptor<?> constraintDescriptor = constraintViolation.getConstraintDescriptor();
//this will extract all violation attributes and will create messages of the type:
//${violationkey} violationValue
//these values can later be used for formatting the returned messages.
if(constraintDescriptor != null) {
Map<String, Object> violationAttributes = constraintDescriptor.getAttributes();
for (Map.Entry violationAttribute : violationAttributes.entrySet()) {
String propertyName = violationAttribute.getKey().toString();
Object value = violationAttribute.getValue();
messages.add(createSetVariableString(propertyName, value));
}
}
if (constraintViolation.getPropertyPath() != null) {
messages.add(EngineMessage.ACTION_TYPE_FAILED_ATTRIBUTE_PATH.name());
messages.add(createSetVariableString("path", constraintViolation.getPropertyPath()));
}
messages.add(createSetVariableString("validatedValue", constraintViolation.getInvalidValue()));
}
}
return messages;
}
private static String createSetVariableString(String propertyName, Object value) {
final String setVariableValueFormat = "$%s %s";
return String.format(setVariableValueFormat, propertyName, value);
}
public static boolean validatePort(int port) {
return (port >= BusinessEntitiesDefinitions.NETWORK_MIN_LEGAL_PORT) && (port <= BusinessEntitiesDefinitions.NETWORK_MAX_LEGAL_PORT);
}
}