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

com.google.api.tools.framework.aspects.http.RestPatterns Maven / Gradle / Ivy

There is a newer version: 0.0.8
Show newest version
/*
 * Copyright (C) 2016 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.tools.framework.aspects.http;

import com.google.api.tools.framework.aspects.http.model.MethodKind;
import com.google.api.tools.framework.aspects.http.model.RestKind;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;

import java.io.PrintStream;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

/**
 * Contains pattern objects for rest method and segments.
 */
public class RestPatterns {

  // Represents a rest method pattern.
  @AutoValue
  abstract static class MethodPattern {

    // The http method.
    abstract MethodKind httpMethod();

    // A regular expression which the rpc name must match.
    abstract Pattern nameRegexp();

    // A pattern which the last segment of the path must match.
    @Nullable abstract SegmentPattern lastSegmentPattern();

    // The implied rest kind.
    @Nullable abstract RestKind restKind();

    // The implied prefix to use for custom methods.
    abstract String customPrefix();

    // Documentation of the pattern.
    abstract String description();

    static MethodPattern create(MethodKind methodKind, String nameRegexp,
        SegmentPattern lastSegment, RestKind restKind, String customPrefix, String description) {
      return new AutoValue_RestPatterns_MethodPattern(methodKind, Pattern.compile(nameRegexp),
          lastSegment, restKind, customPrefix, description);
    }

    static MethodPattern create(MethodKind methodKind, String nameRegexp,
          SegmentPattern lastSegment, RestKind restKind, String description) {
      return create(methodKind, nameRegexp, lastSegment, restKind, "", description);
    }

    // Produce readable output for this pattern. This is used in error messages, as in
    // 'rpc Get.* as HTTP GET /'. We don't print the rest kind.
    @Override
    public String toString() {
      StringBuilder result = new StringBuilder();
      result.append("rpc ");
      result.append(nameRegexp().pattern());
      result.append(" as HTTP ");
      result.append(httpMethod().toString());
      if (lastSegmentPattern() != null) {
        result.append(" ");
        result.append(pathDisplay());
      }
      return result.toString();
    }

    private String pathDisplay() {
      if (lastSegmentPattern() != null) {
        switch (lastSegmentPattern()) {
          case VARIABLE:
            return "/";
          case CUSTOM_VERB:
          case CUSTOM_VERB_WITH_COLON:
            return ":";
          case LITERAL:
            return "/";
        }
      }
      return "";
    }
  }

  // A pattern for a path segment.
  enum SegmentPattern {
    VARIABLE,
    LITERAL,
    // matches both legacy custom method segment which uses / and standard
    // conforming custom method which uses :.
    CUSTOM_VERB,
    // matches only one platform conforming custom method which uses :.
    CUSTOM_VERB_WITH_COLON,
  }

  // Declares all the currently allowed rest method patterns. If none of those
  // matches, a warning will be produced.
  static final ImmutableList METHOD_PATTERNS =
      ImmutableList.builder()

        // First list all standard methods. They have priority in matching.
        // Note that the only source of ambiguity here is a legacy custom
        // method which uses / instead of :, otherwise
        // our patterns would be unique.
        .add(MethodPattern.create(
            MethodKind.GET,
            "Get.*",
            SegmentPattern.VARIABLE,
            RestKind.GET,
            "Gets a resource."
        ))
        .add(MethodPattern.create(
            MethodKind.GET,
            "List.*",
            SegmentPattern.LITERAL,
            RestKind.LIST,
            "Lists all resources"
        ))
        .add(MethodPattern.create(
            MethodKind.PUT,
            "Update.*",
            SegmentPattern.VARIABLE,
            RestKind.UPDATE,
            "Update a resource."
        ))
        .add(MethodPattern.create(
            MethodKind.PUT,
            "(Create|Insert).*",
            SegmentPattern.VARIABLE,
            RestKind.CREATE,
            "Create a resource."
        ))
        .add(MethodPattern.create(
            MethodKind.PATCH,
            "(Update|Patch).*",
            SegmentPattern.VARIABLE,
            RestKind.PATCH,
            "Patch a resource."
        ))
        .add(MethodPattern.create(
            MethodKind.DELETE,
            "Delete.*",
            SegmentPattern.VARIABLE,
            RestKind.DELETE,
            "Delete a resource"
        ))
        .add(MethodPattern.create(
            MethodKind.POST,
            "(Create|Insert).*",
            SegmentPattern.LITERAL,
            RestKind.CREATE,
            "Create a resource"
        ))

        // Next list all custom methods.
        .add(MethodPattern.create(
            MethodKind.GET,
            "Get.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "get",
            "Custom get resource."
        ))
        .add(MethodPattern.create(
            MethodKind.GET,
            "List.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "list",
            "Custom list resources."
        ))
        .add(MethodPattern.create(
            MethodKind.GET,
            ".*",
            SegmentPattern.CUSTOM_VERB_WITH_COLON,
            RestKind.CUSTOM,
            "General custom get method."
        ))
        .add(MethodPattern.create(
            MethodKind.PUT,
            "Update.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "update",
            "Custom update resource."
        ))
        .add(MethodPattern.create(
            MethodKind.PUT,
            "Create.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "create",
            "Custom create resource."
        ))
        .add(MethodPattern.create(
            MethodKind.PATCH,
            "Patch.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "patch",
            "Custom patch resource."
        ))
        .add(MethodPattern.create(
            MethodKind.PATCH,
            "Update.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "update",
            "Custom update resource"
        ))
        .add(MethodPattern.create(
            MethodKind.DELETE,
            "Delete.*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "delete",
            "Custom delete resource"
        ))
        .add(MethodPattern.create(
            MethodKind.POST,
            ".*",
            SegmentPattern.CUSTOM_VERB,
            RestKind.CUSTOM,
            "General custom method."
        ))
        .build();

  /**
   * Main entry point for generating a table of supported REST patterns.
   */
  public static void main(String[] args) {
    PrintStream out = System.out;
    out.println("HTTP method | RPC name regexp | Path | REST verb | REST name | Remarks");
    out.println("------------|-----------------|------|-----------|-----------|--------");
    for (MethodPattern pattern : METHOD_PATTERNS) {
      out.print("`" + pattern.httpMethod() + "`");
      out.print(" | ");
      out.print("`" + pattern.nameRegexp().pattern().replace("|", "\\|") + "`");
      out.print(" | ");
      out.print("`" + pattern.pathDisplay() + "`");
      out.print(" | ");
      out.print("`" + pattern.restKind() + "`");
      out.print(" | ");
      out.print("`" + restNameDisplay(pattern) + "`");
      out.print(" | ");
      out.print(pattern.description());
      out.println();
    }
  }

  private static String restNameDisplay(MethodPattern pattern) {
    if (pattern.restKind() == RestKind.CUSTOM) {
      return pattern.customPrefix().isEmpty() ? "" : pattern.customPrefix() + "";
    }
    return pattern.restKind().toString().toLowerCase();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy