Package com.google.api.explorer.client.editors

Source Code of com.google.api.explorer.client.editors.EditorFactory$UrlEncodingValidator

/*
* Copyright (C) 2011 Google Inc.
* Licensed 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 com.google.api.explorer.client.editors;

import com.google.api.explorer.client.base.Schema;
import com.google.api.explorer.client.base.Schema.Type;
import com.google.api.explorer.client.base.UrlEncoder;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;

import java.math.BigInteger;
import java.util.List;

/**
* Factory for {@link Editor}s that will produce the appropriate editor based on
*  the properties of the parameter being edited. The factory will also add
* appropriate {@link Validator}s.
*
* @author jasonhall@google.com (Jason Hall)
*/
public class EditorFactory {

  private static final List<String> TRUE_FALSE =
      ImmutableList.of(Boolean.TRUE.toString(), Boolean.FALSE.toString());

  @VisibleForTesting
  static UrlEncoder urlEncoder = UrlEncoder.DEFAULT;

  /**
   * Identifies the relevant {@link Editor} implementation for the given
   * {@link Schema}.
   */
  public static Editor forParameter(Schema parameter) {
    return forParameter(parameter, false);
  }

  /**
   * Identifies the revelant {@link Editor} implementation for the given
   * parameter, ignoring whether the parameter is repeated.
   *
   * @param ignoreRepeated is necessary because a {@link RepeatedEditor} wraps
   *        an inner {@link Editor} implementation to display repeatedly. When
   *        ignoreRepeated is true, this method is used to identify the
   *        correct inner editor to use.
   */
  static Editor forParameter(Schema parameter, boolean ignoreRepeated) {
    if (!ignoreRepeated && parameter.isRepeated()) {
      return new RepeatedEditor(forParameter(parameter, true));
    }

    // In most cases we'll just want to use a BasicEditor.
    Editor editor = new BasicEditor();

    Type type = parameter.getType();
    // If the parameter expects a boolean value, use an EnumEditor with values
    // "true" and "false".
    if (type == Type.BOOLEAN) {
      editor = new EnumEditor(TRUE_FALSE, null);
    }

    // Get possible enum values and descriptions. If enum values are specified,
    // then use an EnumEditor.
    List<String> enumValues = parameter.getEnumValues();
    List<String> enumDescriptions = parameter.getEnumDescriptions();

    if (enumValues != null && !enumValues.isEmpty()) {
      editor = new EnumEditor(enumValues, enumDescriptions);
    }

    // If the parameter expects an integer value, add an IntegerValidator.
    String minimum = parameter.getMinimum();
    String maximum = parameter.getMaximum();
    final String pattern = parameter.getPattern();

    maybeAddValidatorTo(editor, new IntegerValidator(), type == Type.INTEGER);
    maybeAddValidatorTo(
        editor, new MinimumMaximumValidator(minimum, maximum), minimum != null || maximum != null);
    maybeAddValidatorTo(editor, new DecimalValidator(), type == Type.NUMBER);
    maybeAddValidatorTo(editor, new RequiredValidator(), parameter.isRequired());
    maybeAddValidatorTo(editor, new PatternValidator(pattern), pattern != null);
    editor.addValidator(new UrlEncodingValidator());

    return editor;
  }

  /**
   * Conditionally adds the given validator to the given editor, if the
   * condition is true.
   */
  private static void maybeAddValidatorTo(Editor editor, Validator validator, boolean condition) {
    if (condition) {
      editor.addValidator(validator);
    }
  }

  @VisibleForTesting
  static final class MinimumMaximumValidator implements Validator {
    private final BigInteger minimum;
    private final BigInteger maximum;

    MinimumMaximumValidator(String minimum, String maximum) {
      this.minimum = minimum == null ? null : new BigInteger(minimum);
      this.maximum = maximum == null ? null : new BigInteger(maximum);
    }

    /**
     * Returns true if all values are parseable integers within the bounds of
     * the minimum and maximum.
     */
    @Override
    public ValidationResult isValid(List<String> values) {
      for (String value : values) {
        if (value.isEmpty()) {
          continue;
        }
        BigInteger val;
        try {
          val = new BigInteger(value);
        } catch (NumberFormatException nfe) {
          return SimpleValidationResult.createError("Must be an integer.");
        }
        if (minimum != null && val.compareTo(minimum) == -1) {
          return SimpleValidationResult.createError("Must be >= " + minimum);
        }
        if (maximum != null && val.compareTo(maximum) == 1) {
          return SimpleValidationResult.createError("Must be <= " + maximum);
        }
      }
      return SimpleValidationResult.STATUS_VALID;
    }
  }

  @VisibleForTesting
  static class IntegerValidator extends PatternValidator {
    private static final String INTEGER_PATTERN = "-?[0-9]+";

    public IntegerValidator() {
      super(INTEGER_PATTERN);
    }
  }

  @VisibleForTesting
  static final class DecimalValidator extends PatternValidator {
    private static final String DECIMAL_PATTERN = "-?[0-9]+(\\.[0-9]+)?";

    public DecimalValidator() {
      super(DECIMAL_PATTERN);
    }
  }

  @VisibleForTesting
  static class PatternValidator implements Validator {
    @VisibleForTesting
    final String pattern;

    private PatternValidator(String pattern) {
      this.pattern = pattern;
    }

    /** Returns true if all values are either empty or match the pattern. */
    @Override
    public ValidationResult isValid(List<String> values) {
      for (String value : values) {
        if (!value.isEmpty() && !value.matches(pattern)) {
          return SimpleValidationResult.createError("Must match pattern " + pattern);
        }
      }
      return SimpleValidationResult.STATUS_VALID;
    }
  }

  @VisibleForTesting
  static final class RequiredValidator implements Validator {
    /**
     * Returns true if at least one string is given, and none of the values are
     * empty.
     */
    @Override
    public ValidationResult isValid(List<String> values) {

      if (values.isEmpty()) {
        return SimpleValidationResult.createError("Required parameter.");
      }
      for (String value : values) {
        if (value.isEmpty()) {
          return SimpleValidationResult.createError("Required parameter.");
        }
      }
      return SimpleValidationResult.STATUS_VALID;
    }
  }

  @VisibleForTesting
  static final class UrlEncodingValidator implements Validator {

    /**
     * Returns invalid if url encoding made a change to the string
     */
    @Override
    public ValidationResult isValid(List<String> values) {
      if (!values.isEmpty()) {
        for (String value : values) {
          if (value != null) {
            boolean neededEncoding = !value.equals(urlEncoder.encodePathSegment(value));
            if (neededEncoding) {
              return SimpleValidationResult.createInfo("This parameter was URL encoded.");
            }
          }
        }
      }
      return SimpleValidationResult.STATUS_VALID;
    }
  }
}
TOP

Related Classes of com.google.api.explorer.client.editors.EditorFactory$UrlEncodingValidator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.