All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.smithy.model.validation.node.NodeValidatorPlugin Maven / Gradle / Ivy

/*
 * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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 software.amazon.smithy.model.validation.node;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import software.amazon.smithy.model.FromSourceLocation;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.selector.Selector;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.validation.NodeValidationVisitor;
import software.amazon.smithy.model.validation.Severity;
import software.amazon.smithy.utils.ListUtils;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
 * Applies pluggable validation when validating {@link Node} values against
 * the schema of a {@link Shape} (e.g., when validating that the values
 * provided for a trait in the model are valid for the shape of the trait).
 */
@SmithyInternalApi
public interface NodeValidatorPlugin {
     String[] EMPTY_STRING_ARRAY = new String[0];

    /**
     * Applies the plugin to the given shape, node value, and model.
     *
     * @param shape Shape being checked.
     * @param value Value being evaluated.
     * @param context Evaluation context.
     * @param emitter Consumer to notify of validation event locations and messages.
     */
    void apply(Shape shape, Node value, Context context, Emitter emitter);

    /**
     * @return Gets the built-in Node validation plugins.
     */
    static List getBuiltins() {
        return ListUtils.of(
                new NonNumericFloatValuesPlugin(),
                new BlobLengthPlugin(),
                new CollectionLengthPlugin(),
                new IdRefPlugin(),
                new MapLengthPlugin(),
                new PatternTraitPlugin(),
                new RangeTraitPlugin(),
                new StringEnumPlugin(),
                new IntEnumPlugin(),
                new StringLengthPlugin(),
                new UniqueItemsPlugin());
    }

    /**
     * Validation context to pass to each NodeValidatorPlugin.
     */
    @SmithyInternalApi
    final class Context {
        private final Model model;
        private final Set features;
        private MemberShape referringMember;

        // Use an LRU cache to ensure the Selector cache doesn't grow too large
        // when given bad inputs.
        private final Map> selectorResults = new LinkedHashMap>(
                50 + 1, .75F, true) {
            @Override
            public boolean removeEldestEntry(Map.Entry> eldest) {
                return size() > 50;
            }
        };

        /**
         * @param model Model being evaluated.
         */
        public Context(Model model) {
            this(model, Collections.emptySet());
        }

        public Context(Model model, Set features) {
            this.model = model;
            this.features = features;
        }

        /**
         * Get the model being evaluated.
         *
         * @return Returns the model.
         */
        public Model model() {
            return model;
        }

        /**
         * Select and memoize shapes from the model using a Selector.
         *
         * 

The cache used by this method is not thread-safe, though that's * fine because NodeValidatorPlugins using the same Context all run * within the same thread. * * @param selector Selector to evaluate. * @return Returns the matching shapes. */ public Set select(Selector selector) { return selectorResults.computeIfAbsent(selector, s -> s.select(model)); } public boolean hasFeature(NodeValidationVisitor.Feature feature) { return features.contains(feature); } public void setReferringMember(MemberShape referringMember) { this.referringMember = referringMember; } public Optional getReferringMember() { return Optional.ofNullable(referringMember); } } @SmithyInternalApi @FunctionalInterface interface Emitter { void accept(FromSourceLocation sourceLocation, Severity severity, String message, String... additionalEventIdParts); default void accept(FromSourceLocation sourceLocation, String message) { accept(sourceLocation, Severity.ERROR, message, EMPTY_STRING_ARRAY); } default void accept(FromSourceLocation sourceLocation, Severity severity, String message) { accept(sourceLocation, severity, message, EMPTY_STRING_ARRAY); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy