com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkApiImporter.java Source code

Java tutorial

Introduction

Here is the source code for com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkApiImporter.java

Source

/*
 * Copyright 2010-2015 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 com.amazonaws.service.apigateway.importer.impl.sdk;

import com.amazonaws.services.apigateway.model.ApiGateway;
import com.amazonaws.services.apigateway.model.CreateDeploymentInput;
import com.amazonaws.services.apigateway.model.CreateModelInput;
import com.amazonaws.services.apigateway.model.CreateResourceInput;
import com.amazonaws.services.apigateway.model.CreateRestApiInput;
import com.amazonaws.services.apigateway.model.Model;
import com.amazonaws.services.apigateway.model.Models;
import com.amazonaws.services.apigateway.model.NotFoundException;
import com.amazonaws.services.apigateway.model.Resource;
import com.amazonaws.services.apigateway.model.Resources;
import com.amazonaws.services.apigateway.model.RestApi;
import com.google.common.util.concurrent.RateLimiter;
import com.google.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import static com.amazonaws.service.apigateway.importer.util.PatchUtils.createPatchDocument;
import static com.amazonaws.service.apigateway.importer.util.PatchUtils.createReplaceOperation;

public class ApiGatewaySdkApiImporter {

    private static final Log LOG = LogFactory.getLog(ApiGatewaySdkApiImporter.class);

    @Inject
    protected ApiGateway apiGateway;

    // keep track of the models created/updated from the definition file. Any orphaned models left in the API will be deleted
    protected HashSet<String> processedModels = new HashSet<>();

    public void deleteApi(String apiId) {
        deleteApi(apiGateway.getRestApiById(apiId));
    }

    public void deploy(String apiId, String deploymentStage) {
        LOG.info(String.format("Creating deployment for API %s and stage %s", apiId, deploymentStage));

        CreateDeploymentInput input = new CreateDeploymentInput();
        input.setStageName(deploymentStage);

        apiGateway.getRestApiById(apiId).createDeployment(input);
    }

    protected RestApi createApi(String name, String description) {
        LOG.info("Creating API with name " + name);

        CreateRestApiInput input = new CreateRestApiInput();
        input.setName(name);
        input.setDescription(description);

        return apiGateway.createRestApi(input);
    }

    protected void rollback(RestApi api) {
        deleteApi(api);
    }

    protected void deleteApi(RestApi api) {
        LOG.info("Deleting API " + api.getId());
        api.deleteRestApi();
    }

    protected Optional<Resource> getRootResource(RestApi api) {
        for (Resource r : buildResourceList(api)) {
            if ("/".equals(r.getPath())) {
                return Optional.of(r);
            }
        }
        return Optional.empty();
    }

    // todo: optimize number of calls to this as it is an expensive operation
    protected List<Resource> buildResourceList(RestApi api) {
        List<Resource> resourceList = new ArrayList<>();

        Resources resources = api.getResources();
        resourceList.addAll(resources.getItem());

        LOG.debug("Building list of resources. Stack trace: ", new Throwable());

        final RateLimiter rl = RateLimiter.create(2);
        while (resources._isLinkAvailable("next")) {
            rl.acquire();
            resources = resources.getNext();
            resourceList.addAll(resources.getItem());
        }

        return resourceList;
    }

    protected void deleteDefaultModels(RestApi api) {
        buildModelList(api).stream().forEach(model -> {
            LOG.info("Removing default model " + model.getName());
            try {
                model.deleteModel();
            } catch (Throwable ignored) {
            } // todo: temporary catch until API fix
        });
    }

    protected List<Model> buildModelList(RestApi api) {
        List<Model> modelList = new ArrayList<>();

        Models models = api.getModels();
        modelList.addAll(models.getItem());

        while (models._isLinkAvailable("next")) {
            models = models.getNext();
            modelList.addAll(models.getItem());
        }

        return modelList;
    }

    protected RestApi getApi(String id) {
        return apiGateway.getRestApiById(id);
    }

    protected void createModel(RestApi api, String modelName, String description, String schema,
            String modelContentType) {
        this.processedModels.add(modelName);

        CreateModelInput input = new CreateModelInput();

        input.setName(modelName);
        input.setDescription(description);
        input.setContentType(modelContentType);
        input.setSchema(schema);

        api.createModel(input);
    }

    protected void updateModel(RestApi api, String modelName, String schema) {
        this.processedModels.add(modelName);

        api.getModelByName(modelName).updateModel(createPatchDocument(createReplaceOperation("/schema", schema)));
    }

    protected void cleanupModels(RestApi api, Set<String> models) {
        List<Model> existingModels = buildModelList(api);
        Stream<Model> modelsToDelete = existingModels.stream().filter(model -> !models.contains(model.getName()));

        modelsToDelete.forEach(model -> {
            LOG.info("Removing deleted model " + model.getName());
            model.deleteModel();
        });
    }

    protected Optional<Resource> getResource(String parentResourceId, String pathPart, List<Resource> resources) {
        for (Resource r : resources) {
            if (pathEquals(pathPart, r.getPathPart()) && r.getParentId().equals(parentResourceId)) {
                return Optional.of(r);
            }
        }
        return Optional.empty();
    }

    protected boolean pathEquals(String p1, String p2) {
        return (StringUtils.isBlank(p1) && StringUtils.isBlank(p2)) || p1.equals(p2);
    }

    protected Optional<Resource> getResource(RestApi api, String fullPath) {
        for (Resource r : buildResourceList(api)) {
            if (r.getPath().equals(fullPath)) {
                return Optional.of(r);
            }
        }

        return Optional.empty();
    }

    protected Optional<Model> getModel(RestApi api, String modelName) {
        try {
            return Optional.of(api.getModelByName(modelName));
        } catch (Exception ignored) {
            return Optional.empty();
        }
    }

    protected boolean methodExists(Resource resource, String httpMethod) {
        return resource.getResourceMethods().get(httpMethod.toUpperCase()) != null;
    }

    protected void deleteResource(Resource resource) {
        if (resource._isLinkAvailable("resource:delete")) {
            try {
                resource.deleteResource();
            } catch (NotFoundException error) {
            }
        }
        // can't delete root resource
    }

    /**
     * Build the full resource path, including base path, add any missing leading '/', remove any trailing '/',
     * and remove any double '/'
     * @param basePath the base path
     * @param resourcePath the resource path
     * @return the full path
     */
    protected String buildResourcePath(String basePath, String resourcePath) {
        if (basePath == null) {
            basePath = "";
        }
        String base = trimSlashes(basePath);
        if (!base.equals("")) {
            base = "/" + base;
        }
        String result = StringUtils.removeEnd(base + "/" + trimSlashes(resourcePath), "/");
        if (result.equals("")) {
            result = "/";
        }
        return result;
    }

    private String trimSlashes(String path) {
        return StringUtils.removeEnd(StringUtils.removeStart(path, "/"), "/");
    }

    protected Resource createResource(RestApi api, String parentResourceId, String part, List<Resource> resources) {
        final Optional<Resource> existingResource = getResource(parentResourceId, part, resources);

        // create resource if doesn't exist
        if (!existingResource.isPresent()) {

            LOG.info("Creating resource '" + part + "' on " + parentResourceId);

            CreateResourceInput input = new CreateResourceInput();
            input.setPathPart(part);
            Resource resource = api.getResourceById(parentResourceId);

            Resource created = resource.createResource(input);

            resources.add(created);

            return created;
        } else {
            return existingResource.get();
        }
    }

    protected String getStringValue(Object in) {
        return in == null ? null : String.valueOf(in); // use null value instead of "null"
    }

}