MessageValidator.java

  1. /*
  2.  * Copyright 2019 Providence Authors
  3.  *
  4.  * Licensed to the Apache Software Foundation (ASF) under one
  5.  * or more contributor license agreements. See the NOTICE file
  6.  * distributed with this work for additional information
  7.  * regarding copyright ownership. The ASF licenses this file
  8.  * to you under the Apache License, Version 2.0 (the
  9.  * "License"); you may not use this file except in compliance
  10.  * with the License. You may obtain a copy of the License at
  11.  *
  12.  *   http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing,
  15.  * software distributed under the License is distributed on an
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17.  * KIND, either express or implied. See the License for the
  18.  * specific language governing permissions and limitations
  19.  * under the License.
  20.  */
  21. package net.morimekta.providence.util;

  22. import net.morimekta.providence.PMessage;
  23. import net.morimekta.providence.PMessageOrBuilder;
  24. import net.morimekta.providence.descriptor.PField;
  25. import net.morimekta.providence.descriptor.PMessageDescriptor;

  26. import javax.annotation.Nonnull;
  27. import java.util.function.Consumer;
  28. import java.util.function.Function;
  29. import java.util.function.Predicate;

  30. /**
  31.  * Class that handles validation of the structure or content of a message
  32.  * type. This this can do much more fine grained validation than just assigning
  33.  * required fields.
  34.  *
  35.  * @param <M> The message type to be validated.
  36.  * @param <E> The exception to be thrown on validation failure.
  37.  * @deprecated Use {@link MessageValidation}.
  38.  */
  39. @Deprecated
  40. public class MessageValidator<
  41.         M extends PMessage<M>,
  42.         E extends Exception> {
  43.     private final MessageValidation<M, E> validation;

  44.     /**
  45.      * Validate a message using the built expectations.
  46.      *
  47.      * @param message The message to be validated.
  48.      * @throws E On not valid message.
  49.      */
  50.     @SuppressWarnings("unchecked")
  51.     public void validate(PMessageOrBuilder<M> message) throws E {
  52.         validation.validate(message);
  53.     }

  54.     /**
  55.      * Just see if the message is valid or not. Does not
  56.      *
  57.      * @param message The message to be validated.
  58.      * @return True if the message is valid, false otherwise.
  59.      */
  60.     @SuppressWarnings("unchecked")
  61.     public boolean isValid(PMessageOrBuilder<M> message) {
  62.         return validation.isValid(message);
  63.     }

  64.     /**
  65.      * Just see if the message is valid or not. Does not
  66.      *
  67.      * @param message         The message to be validated.
  68.      * @param messageConsumer Consumer of validation errors on the message.
  69.      */
  70.     @SuppressWarnings("unchecked")
  71.     public void collectValidationErrors(PMessageOrBuilder<M> message, Consumer<String> messageConsumer) {
  72.         try {
  73.             validation.validate(message);
  74.         } catch (Exception e) {
  75.             messageConsumer.accept(e.getMessage());
  76.         }
  77.     }


  78.     /**
  79.      * Create a message validator that throws specific exception on failure.
  80.      *
  81.      * @param descriptor The message type descriptor to be validated.
  82.      * @param onMismatch Function producer for thrown exceptions.
  83.      * @param <M>        Message type.
  84.      * @param <E>        Exception type.
  85.      * @return The message validator builder.
  86.      */
  87.     public static <M extends PMessage<M>, E extends Exception>
  88.     MessageValidator.Builder<M, E> builder(
  89.             @Nonnull PMessageDescriptor<M> descriptor,
  90.             @Nonnull Function<String, E> onMismatch) {
  91.         return new Builder<>(descriptor, onMismatch);
  92.     }

  93.     /**
  94.      * Builder vlass for message validators.
  95.      *
  96.      * @param <M> Message type.
  97.      * @param <E> Exception type.
  98.      * @deprecated Use {@link MessageValidation}.
  99.      */
  100.     @Deprecated
  101.     public static class Builder<
  102.             M extends PMessage<M>,
  103.             E extends Exception> {
  104.         /**
  105.          * Build the validator.
  106.          *
  107.          * @return The validator instance.
  108.          */
  109.         @Nonnull
  110.         public MessageValidator<M, E> build() {
  111.             return new MessageValidator<>(this);
  112.         }

  113.         /**
  114.          * Make a specific expectation for the message.
  115.          *
  116.          * @param text      The message text on expectation failure.
  117.          * @param predicate Expectation predicate.
  118.          * @return The builder instance.
  119.          */
  120.         @Nonnull
  121.         public Builder<M, E> expect(@Nonnull String text,
  122.                                     @Nonnull Predicate<M> predicate) {
  123.             builder.expect(new MessageValidation.PredicateExpectation<>(predicate, text));
  124.             return this;
  125.         }

  126.         /**
  127.          * Given the field and type descriptor (which must match the field type),
  128.          * build an inner validator to check the value of the field.
  129.          *
  130.          * @param field           The field to check.
  131.          * @param descriptor      The message descriptor matching the field.
  132.          * @param builderConsumer Consumer to configure the inner validator.
  133.          * @param <M2>            The inner message type.
  134.          * @return The builder instance.
  135.          */
  136.         @Nonnull
  137.         public <M2 extends PMessage<M2>>
  138.         Builder<M, E> expect(@Nonnull PField<M> field,
  139.                              @Nonnull PMessageDescriptor<M2> descriptor,
  140.                              @Nonnull Consumer<Builder<M2, E>> builderConsumer) {
  141.             builder.expectIfPresent(field, descriptor, b2 -> {
  142.                 builderConsumer.accept(new Builder<>(b2));
  143.             });
  144.             return this;
  145.         }

  146.         /**
  147.          * Expect the message to be non-null value.
  148.          *
  149.          * @return The builder instance.
  150.          */
  151.         @Nonnull
  152.         public Builder<M, E> expectNotNull() {
  153.             builder.expectNotNull();
  154.             return this;
  155.         }

  156.         /**
  157.          * Expect the message to be non-null value.
  158.          *
  159.          * @param text The failure message on null value.
  160.          * @return The builder instance.
  161.          */
  162.         @Nonnull
  163.         public Builder<M, E> expectNotNull(@Nonnull String text) {
  164.             builder.expectNotNull();
  165.             return this;
  166.         }

  167.         /**
  168.          * Expect field to be present on message.
  169.          *
  170.          * @param fields The fields to be present.
  171.          * @return The builder instance.
  172.          */
  173.         @Nonnull
  174.         @SafeVarargs
  175.         public final Builder<M, E> expectPresent(@Nonnull PField<M>... fields) {
  176.             builder.expectPresent(fields);
  177.             return this;
  178.         }

  179.         /**
  180.          * Expect field to be present on message.
  181.          *
  182.          * @param text  The failure message on missing field.
  183.          * @param field The field to be present.
  184.          * @return The builder instance.
  185.          */
  186.         @Nonnull
  187.         public Builder<M, E> expectPresent(@Nonnull String text, @Nonnull PField<M> field) {
  188.             builder.expect(new MessageValidation.PredicateExpectation<>(message -> message.has(field), text));
  189.             return this;
  190.         }

  191.         /**
  192.          * Expect field to be present on message.
  193.          *
  194.          * @param fields The fields to be present.
  195.          * @return The builder instance.
  196.          */
  197.         @Nonnull
  198.         @SafeVarargs
  199.         public final Builder<M, E> expectMissing(@Nonnull PField<M>... fields) {
  200.             builder.expectMissing(fields);
  201.             return this;
  202.         }

  203.         /**
  204.          * Expect field to be present on message.
  205.          *
  206.          * @param text  The failure message on present field.
  207.          * @param field The field to be present.
  208.          * @return The builder instance.
  209.          */
  210.         @Nonnull
  211.         public Builder<M, E> expectMissing(@Nonnull String text, @Nonnull PField<M> field) {
  212.             builder.expect(new MessageValidation.PredicateExpectation<>(message -> !message.has(field), text));
  213.             return this;
  214.         }

  215.         private Builder(PMessageDescriptor<M> descriptor, @Nonnull Function<String, E> onMismatch) {
  216.             builder = MessageValidation.builder(descriptor, e -> onMismatch.apply(e.getMessage()));
  217.         }
  218.         private Builder(MessageValidation.Builder<M, E> builder) {
  219.             this.builder = builder;
  220.         }

  221.         private final MessageValidation.Builder<M, E> builder;
  222.     }

  223.     private MessageValidator(Builder<M, E> builder) {
  224.         validation = builder.builder.build();
  225.     }
  226. }