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

com.google.api.tools.framework.aspects.versioning.VersionConfigAspect 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.versioning;

import com.google.api.tools.framework.aspects.ConfigAspectBase;
import com.google.api.tools.framework.aspects.http.HttpConfigAspect;
import com.google.api.tools.framework.aspects.http.model.HttpAttribute;
import com.google.api.tools.framework.aspects.http.model.HttpAttribute.LiteralSegment;
import com.google.api.tools.framework.aspects.versioning.model.ApiVersionUtil;
import com.google.api.tools.framework.aspects.versioning.model.RestVersionsAttribute;
import com.google.api.tools.framework.aspects.versioning.model.VersionAttribute;
import com.google.api.tools.framework.model.ConfigAspect;
import com.google.api.tools.framework.model.Interface;
import com.google.api.tools.framework.model.Location;
import com.google.api.tools.framework.model.Method;
import com.google.api.tools.framework.model.Model;
import com.google.api.tools.framework.model.ProtoElement;
import com.google.api.tools.framework.model.SimpleLocation;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.inject.Key;
import com.google.inject.name.Names;
import com.google.protobuf.Api;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * Configuration aspect for versioning.
 */
public class VersionConfigAspect extends ConfigAspectBase {

  public static final Key KEY = Key.get(String.class, Names.named("version"));

  private final Set roots = Sets.newHashSet();

  public static VersionConfigAspect create(Model model) {
    return new VersionConfigAspect(model);
  }

  private VersionConfigAspect(Model model) {
    super(model, "versioning");
    registerLintRule(new ConfigVersionRule(this));
    registerLintRule(new HttpVersionRule(this));
  }

  /**
   * Returns dependencies. Depends on http attributes used for determining the version
   * from the HTTP path.
   */
  @Override
  public List> mergeDependencies() {
    return ImmutableList.>of(HttpConfigAspect.class);
  }

  @Override
  public void startMerging() {
    // Load the roots here since roots in the model was empty when VersionConfigAspect was created.
    for (ProtoElement root: getModel().getRoots()) {
      roots.add(root);
    }

    // Verify the config_version is explicitly specified in the service config.
    if (!getModel().getServiceConfig().hasConfigVersion()) {
      error(SimpleLocation.TOPLEVEL, "config_version is not specified in the service config file.");
    }

    // Detect config version location.
    Location configVersionLocation = getLocationInConfig(
        getModel().getServiceConfig().getConfigVersion(), "value");

    if (getModel().getConfigVersion() > Model.getDevConfigVersion()) {
      error(
          configVersionLocation,
          String.format("config_version %s is invalid, the latest config_version is %s.",
              getModel().getConfigVersion(), Model.getDevConfigVersion()));
    }
  }

  @Override
  public void merge(ProtoElement element) {
    if (element instanceof Interface) {
      merge((Interface) element);
    }
    if (element instanceof Method) {
      merge((Method) element);
    }
  }

  private void merge(Interface iface) {
    Api api = iface.getConfig();
    if (api == null) {
        return;
    }
    // Get user-defined api version, which is optional.
    String apiVersion = api.getVersion();
    String packageName = iface.getFile().getFullName();
    if (Strings.isNullOrEmpty(apiVersion)) {
      // If version is not provided by user, extract major version from package name.
      apiVersion = ApiVersionUtil.extractDefaultMajorVersionFromPackageName(packageName);
    } else {
      // Validate format of user-defined api version .
      if (!ApiVersionUtil.isValidApiVersion(apiVersion)) {
        error(getLocationInConfig(api, "version"),
            "Invalid version '%s' defined in API '%s'.", apiVersion, api.getName());
      }

      // Validate that the version in the package name is consistent with what user provides.
      String apiVersionFromPackageName =
          ApiVersionUtil.extractDefaultMajorVersionFromPackageName(packageName);
      if (!apiVersionFromPackageName.equals(
          ApiVersionUtil.extractMajorVersionFromSemanticVersion(apiVersion))) {
        error(iface,
            "User-defined api version '%s' is inconsistent with the one in package name '%s'.",
            apiVersion, packageName);
      }
    }
    iface.putAttribute(VersionAttribute.KEY, VersionAttribute.create(apiVersion));
  }

  private void merge(Method method) {
    String restVersion = deriveApiVersion(method);
    method.putAttribute(VersionAttribute.KEY, VersionAttribute.create(restVersion));
    // UM uses the logical version with a suffix appended, if defined.
    String versionSuffix = method.getModel().getApiV1VersionSuffix();
    method.putAttribute(VersionAttribute.USAGE_MANAGER_KEY,
        VersionAttribute.create(ApiVersionUtil.appendVersionSuffix(restVersion, versionSuffix)));

    // Add the rest version into RestVersionsAttribute only if parent of the method is included in
    // the model roots.
    if (roots.contains(method.getParent())) {
      if (getModel().hasAttribute(RestVersionsAttribute.KEY)) {
        getModel().getAttribute(RestVersionsAttribute.KEY).getVersions().add(restVersion);
      } else {
        getModel().putAttribute(RestVersionsAttribute.KEY,
            new RestVersionsAttribute(new LinkedHashSet<>(ImmutableList.of(restVersion))));
      }
    }
  }

  @SuppressWarnings("deprecation")
  private String deriveApiVersion(Method element) {

    // Derive the version from the prefix of the http path. Validation of
    // syntax of version in path happens elsewhere, so we take just the first path segment
    // literal. If none is given, assume 'v1'.
    HttpAttribute http = element.getAttribute(HttpAttribute.KEY);
    if (http == null || http.getPath().isEmpty()
        || !(http.getPath().get(0) instanceof LiteralSegment)) {
      return "v1";
    }
    return ((LiteralSegment) http.getPath().get(0)).getLiteral();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy