blob: cf57fdbc39b636b65b7fa9524a0028350331f4c9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.drill.exec.server.options;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import org.apache.drill.common.exceptions.UserException;
import org.apache.drill.common.util.DrillStringUtils;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.server.options.OptionValue.Kind;
import org.apache.drill.exec.util.ImpersonationUtil;
public class TypeValidators {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TypeValidators.class);
public static class NonNegativeLongValidator extends LongValidator {
private final long max;
public NonNegativeLongValidator(String name, long max, OptionDescription description) {
super(name, description);
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (v.num_val > max || v.num_val < 0) {
throw UserException.validationError()
.message(String.format("Option %s must be between %d and %d.", getOptionName(), 0, max))
.build(logger);
}
}
}
public static class PositiveLongValidator extends LongValidator {
protected final long max;
public PositiveLongValidator(String name, long max, OptionDescription description) {
super(name, description);
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (v.num_val > max || v.num_val < 1) {
throw UserException.validationError()
.message(String.format("Option %s must be between %d and %d.", getOptionName(), 1, max))
.build(logger);
}
}
}
public static class PowerOfTwoLongValidator extends PositiveLongValidator {
public PowerOfTwoLongValidator(String name, long max, OptionDescription description) {
super(name, max, description);
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (!isPowerOfTwo(v.num_val)) {
throw UserException.validationError()
.message(String.format("Option %s must be a power of two.", getOptionName()))
.build(logger);
}
}
private static boolean isPowerOfTwo(long num) {
return (num & (num - 1)) == 0;
}
}
public static class RangeDoubleValidator extends DoubleValidator {
protected final double min;
protected final double max;
public RangeDoubleValidator(String name, double min, double max, OptionDescription description) {
super(name, description);
this.min = min;
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (v.float_val > max || v.float_val < min) {
throw UserException.validationError()
.message(String.format("Option %s must be between %f and %f.", getOptionName(), min, max))
.build(logger);
}
}
}
public static class MinRangeDoubleValidator extends RangeDoubleValidator {
private final String maxValidatorName;
public MinRangeDoubleValidator(String name, double min, double max, String maxValidatorName, OptionDescription description) {
super(name, min, max, description);
this.maxValidatorName = maxValidatorName;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
OptionValue maxValue = manager.getOption(maxValidatorName);
if (v.float_val > maxValue.float_val) {
throw UserException.validationError()
.message(String.format("Option %s must be less than or equal to Option %s",
getOptionName(), maxValidatorName))
.build(logger);
}
}
}
public static class MaxRangeDoubleValidator extends RangeDoubleValidator {
private final String minValidatorName;
public MaxRangeDoubleValidator(String name, double min, double max, String minValidatorName, OptionDescription description) {
super(name, min, max, description);
this.minValidatorName = minValidatorName;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
OptionValue minValue = manager.getOption(minValidatorName);
if (v.float_val < minValue.float_val) {
throw UserException.validationError()
.message(String.format("Option %s must be greater than or equal to Option %s",
getOptionName(), minValidatorName))
.build(logger);
}
}
}
public static class BooleanValidator extends TypeValidator {
public BooleanValidator(String name, OptionDescription description) {
super(name, Kind.BOOLEAN, description);
}
}
public static class StringValidator extends TypeValidator {
public StringValidator(String name, OptionDescription description) {
super(name, Kind.STRING, description);
}
}
public static class LongValidator extends TypeValidator {
public LongValidator(String name, OptionDescription description) {
super(name, Kind.LONG, description);
}
}
public static class DoubleValidator extends TypeValidator {
public DoubleValidator(String name, OptionDescription description) {
super(name, Kind.DOUBLE, description);
}
}
public static class IntegerValidator extends LongValidator {
public IntegerValidator(String name, OptionDescription description) {
super(name, description);
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (v.num_val > Integer.MAX_VALUE || v.num_val < Integer.MIN_VALUE) {
throw UserException.validationError()
.message(String.format("Option %s does not have a valid integer value", getOptionName()))
.build(logger);
}
}
}
public static class RangeLongValidator extends LongValidator {
private final long min;
private final long max;
public RangeLongValidator(String name, long min, long max, OptionDescription description) {
super(name, description);
this.min = min;
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (v.num_val > max || v.num_val < min) {
throw UserException.validationError()
.message(String.format("Option %s must be between %d and %d.", getOptionName(), min, max))
.build(logger);
}
}
}
/**
* Validator that checks if the given value is included in a list of acceptable values. Case insensitive.
*/
public static class EnumeratedStringValidator extends StringValidator {
private final Set<String> valuesSet = Sets.newLinkedHashSet();
public EnumeratedStringValidator(String name, OptionDescription description, String... values) {
super(name, description);
for (String value : values) {
valuesSet.add(value.toLowerCase());
}
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
super.validate(v, metaData, manager);
if (!valuesSet.contains(v.string_val.toLowerCase())) {
throw UserException.validationError()
.message(String.format("Option %s must be one of: %s.", getOptionName(), valuesSet))
.build(logger);
}
}
}
/**
* Unless explicitly changed by the user previously, the admin user
* can only be determined at runtime
*/
public static class AdminUsersValidator extends StringValidator {
public final String DEFAULT_ADMIN_USERS = "%drill_process_user%";
public AdminUsersValidator(String name, OptionDescription description) {
super(name, description);
}
public String getAdminUsers(OptionSet optionManager) {
String adminUsers = optionManager.getOption(ExecConstants.ADMIN_USERS_VALIDATOR);
// if this option has not been changed by the user then return the
// process user
if (adminUsers.equals(DEFAULT_ADMIN_USERS)) {
adminUsers = ImpersonationUtil.getProcessUserName();
}
adminUsers = DrillStringUtils.sanitizeCSV(adminUsers);
return adminUsers;
}
}
/**
* Unless explicitly changed by the user previously, the admin user
* groups can only be determined at runtime
*/
public static class AdminUserGroupsValidator extends StringValidator {
public final String DEFAULT_ADMIN_USER_GROUPS = "%drill_process_user_groups%";
public AdminUserGroupsValidator(String name, OptionDescription description) {
super(name, description);
}
public String getAdminUserGroups(OptionSet optionManager) {
String adminUserGroups = optionManager.getOption(ExecConstants.ADMIN_USER_GROUPS_VALIDATOR);
// if this option has not been changed by the user then return the
// process user groups
if (adminUserGroups.equals(DEFAULT_ADMIN_USER_GROUPS)) {
adminUserGroups = Joiner.on(",").join(ImpersonationUtil.getProcessUserGroupNames());
}
adminUserGroups = DrillStringUtils.sanitizeCSV(adminUserGroups);
return adminUserGroups;
}
}
/** Max width is a special validator which computes and validates
* the maxwidth. If the maxwidth is already set in system/session
* the value is returned or else it is computed dynamically based on
* the available number of processors and cpu load average
*/
public static class MaxWidthValidator extends LongValidator{
public MaxWidthValidator(String name, OptionDescription description) {
super(name, description);
}
public int computeMaxWidth(double cpuLoadAverage, long maxWidth) {
// if maxwidth is already set return it
if (maxWidth != 0) {
return (int) maxWidth;
}
// else compute the value and return
else {
int availProc = Runtime.getRuntime().availableProcessors();
long maxWidthPerNode = Math.max(1, Math.min(availProc, Math.round(availProc * cpuLoadAverage)));
return (int) maxWidthPerNode;
}
}
}
/**
* Validator that checks if the given DateTime format template is valid.
* See {@link DateTimeFormatter} for the acceptable values.
*/
public static class DateTimeFormatValidator extends StringValidator {
public DateTimeFormatValidator(String name, OptionDescription description) {
super(name, description);
}
@Override
public void validate(OptionValue v, OptionMetaData metaData, OptionSet manager) {
super.validate(v, metaData, manager);
if (!v.string_val.isEmpty()) {
try {
DateTimeFormatter.ofPattern(v.string_val);
} catch (IllegalArgumentException e) {
throw UserException.validationError()
.message("'%s' is not a valid DateTime format pattern: %s", v.string_val, e.getMessage())
.build(logger);
}
}
}
}
public static abstract class TypeValidator extends OptionValidator {
private final Kind kind;
public TypeValidator(final String name, final Kind kind, final OptionDescription description) {
super(name, description);
this.kind = kind;
}
@Override
public void validate(final OptionValue v, final OptionMetaData metaData, final OptionSet manager) {
if (v.kind != kind) {
throw UserException.validationError()
.message(String.format("Option %s must be of type %s but you tried to set to %s.", getOptionName(),
kind.name(), v.kind.name()))
.build(logger);
}
}
@Override
public Kind getKind() {
return kind;
}
@Override
public String getConfigProperty() {
return ExecConstants.bootDefaultFor(getOptionName());
}
}
}