/*
* 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.util.Set;
import com.google.common.collect.Sets;
import org.apache.drill.common.exceptions.UserException;
import org.apache.drill.exec.server.options.OptionValue.Kind;
import org.apache.drill.exec.server.options.OptionValue.OptionType;
import static com.google.common.base.Preconditions.checkArgument;
public class TypeValidators {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TypeValidators.class);
public static class PositiveLongValidator extends LongValidator {
private final long max;
public PositiveLongValidator(String name, long max, long def) {
super(name, def);
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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, long def) {
super(name, max, def);
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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 {
private final double min;
private final double max;
public RangeDoubleValidator(String name, double min, double max, double def) {
super(name, def);
this.min = min;
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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, double def, String maxValidatorName) {
super(name, min, max, def);
this.maxValidatorName = maxValidatorName;
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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, double def, String minValidatorName) {
super(name, min, max, def);
this.minValidatorName = minValidatorName;
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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, boolean def) {
this(name, def, false);
}
public BooleanValidator(String name, boolean def, boolean isAdminOption) {
super(name, Kind.BOOLEAN, OptionValue.createBoolean(OptionType.SYSTEM, name, def), isAdminOption);
}
}
public static class StringValidator extends TypeValidator {
public StringValidator(String name, String def) {
this(name, def, false);
}
public StringValidator(String name, String def, boolean isAdminOption) {
super(name, Kind.STRING, OptionValue.createString(OptionType.SYSTEM, name, def), isAdminOption);
}
}
public static class LongValidator extends TypeValidator {
public LongValidator(String name, long def) {
this(name, def, false);
}
public LongValidator(String name, long def, boolean isAdminOption) {
super(name, Kind.LONG, OptionValue.createLong(OptionType.SYSTEM, name, def), isAdminOption);
}
}
public static class DoubleValidator extends TypeValidator {
public DoubleValidator(String name, double def) {
this(name, def, false);
}
public DoubleValidator(String name, double def, boolean isAdminOption) {
super(name, Kind.DOUBLE, OptionValue.createDouble(OptionType.SYSTEM, name, def), isAdminOption);
}
}
public static class RangeLongValidator extends LongValidator {
private final long min;
private final long max;
public RangeLongValidator(String name, long min, long max, long def) {
super(name, def);
this.min = min;
this.max = max;
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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, String def, String... values) {
super(name, def);
valuesSet.add(def.toLowerCase());
for (String value : values) {
valuesSet.add(value.toLowerCase());
}
}
@Override
public void validate(final OptionValue v, final OptionSet manager) {
super.validate(v, 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);
}
}
}
public static abstract class TypeValidator extends OptionValidator {
private final Kind kind;
private final OptionValue defaultValue;
public TypeValidator(final String name, final Kind kind, final OptionValue defValue) {
this(name, kind, defValue, false);
}
public TypeValidator(final String name, final Kind kind, final OptionValue defValue, final boolean isAdminOption) {
super(name, isAdminOption);
checkArgument(defValue.type == OptionType.SYSTEM, "Default value must be SYSTEM type.");
this.kind = kind;
this.defaultValue = defValue;
}
@Override
public OptionValue getDefault() {
return defaultValue;
}
@Override
public void validate(final OptionValue v, 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);
}
if (isAdminOption() && v.type != OptionType.SYSTEM) {
throw UserException.validationError()
.message("Admin related settings can only be set at SYSTEM level scope. Given scope '%s'.", v.type)
.build(logger);
}
}
@Override
public Kind getKind() {
return kind;
}
}
}