| /* |
| * 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()); |
| } |
| } |
| } |