Skip to content

Files

Latest commit

 

History

History
91 lines (65 loc) · 5.53 KB

developer_guide.md

File metadata and controls

91 lines (65 loc) · 5.53 KB

Developer Guide — Virtual Schema Common Java

Adapter Property Validation

Virtual schema adapter properties are user input and must be validated before being used. On the one hand to protect users from typos and misunderstandings and on the other to secure the adapter and prevent injection of malicious parameters.

Validators

This library offers several validators that make checking the adapter properties easy.

In a typical scenario you have some base properties that all adapters know. This library for example understands the LOG_LEVEL property that lets users change the log level.

Virtual Schema dialects (like the one for MariaDB) offer additional properties. That is why the validation is controlled by higher level modules in the dialect.

Let's look at the simplest possible Validator first, a validator for boolean values.

import com.exasol.adapter.properties.AdapterProperties;
import com.exasol.adapter.properties.PropertyValidator;
import com.exasol.adapter.properties.ValidationResult;
import com.exasol.adapter.properties.ValidatorFactory;

import java.util.Map;

final AdapterProperties adapterProperties = new AdapterProperties(Map.of("THE_PARAMETER", true));

final ValidatorFactory factory = ValidatorFactory.create(adapterProperties);
final PropertyValidator validator = factory.bool("THE_PARAMETER");
final ValidationResult result = validator.validate();

In a real adapter the properties would of course not be constructed by hand but rather be passed as part of handling an adapter request. For the sake of simplicity however, this example takes a shortcut.

The ValidatorFactory is responsible for creating all validators. It also keeps track of which parameters are covered by validators, but we will get to that later.

Each validator implements the interface PropertyValidator, where the most important method is validate. This method returns a validation result consisting of an indicator whether the validation succeeded and an error message if it did not.

Validator Class Factory Method Purpose
AndValidator and(validator1, validator2, ...) Short-circuits validation on first failure
BooleanValidator bool(propertyName) Validates that a property value is a boolean
AllOfValidator allOf(validator1, validator2, ...) Runs all validators without short-circuiting
CoverageValidator allCovered() Validates that all properties have been checked by validators
EnumerationValidator enumeration(propertyName, enumClass) Validates that a property value is one of the values defined in an enumeration
ExasolObjectIdValidator exasolObjectId(propertyName) Validates that a property value follows Exasol's object ID format rules
IntegerValidator integer(propertyName) Validates that a property value is a valid integer
IntegerValidator integer(propertyName, min, max) Validates that a property value is an integer within specified boundaries
MultiSelectValidator multiSelect(propertyName, enumClass) Validates a given value is a comma separated list of enum values; non-empty
MultiSelectValidator multiSelect(propertyName, enumClass, emptyAllowed) Validates a given value is a comma separated list of enum values
RequiredValidator required(propertyName) Validates that a property exists
StringValidator matches(propertyName, pattern) Validates property against regex pattern
UnixPathValidator path(propertyName) Validates a given value is a valid path without dangerous contents

Validator Composition

To allow complex validation the factory has a couple of methods that allow creating compositions of validators.

factory.and(
        factory.required("REQUIRED_PARAMETER"),
        factory.bool("REQUIRED_PARAMETER")
)

This allows defining a parameter as required and a boolean. The AndValidator short-circuits on the first failure. That means, that if the parameter is not set, the boolean check will be skipped.

For this particular combination, there is also a shorthand form:

factory.required(factory.bool("REQUIRED_PARAMETER"))

This is much more convenient.

If short-circuiting is not an option — for example because you want to present all validation failures at once instead of forcing users in to a trial-and-error loop — use the AllOfValidator.

factory.allOf(
        factory.matches("HOST", "\\w+"),
        factory.integer("PORT")
)

We recommend also checking that no unwanted properties are set with the CoverageValidator. Put that one at the very end.

factory.allOf(
        // … all your other validators
        factory.allCovered()
)