/* * Copyright 2015 JBoss 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 io.apiman.gateway.platforms.vertx3.api; import io.apiman.common.util.SimpleStringUtils; import io.apiman.gateway.api.rest.contract.IApiResource; import io.apiman.gateway.api.rest.contract.exceptions.NotAuthorizedException; import io.apiman.gateway.engine.IEngine; import io.apiman.gateway.engine.IRegistry; import io.apiman.gateway.engine.async.IAsyncResultHandler; import io.apiman.gateway.engine.beans.Api; import io.apiman.gateway.engine.beans.ApiEndpoint; import io.apiman.gateway.engine.beans.exceptions.PublishingException; import io.apiman.gateway.engine.beans.exceptions.RegistrationException; import io.apiman.gateway.platforms.vertx3.common.config.VertxEngineConfig; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.json.Json; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; /** * API Resource route builder * * @author Marc Savy {@literal <msavy@redhat.com>} */ @SuppressWarnings("nls") public class ApiResourceImpl implements IApiResource, IRouteBuilder { private static final String ORG_ID = "organizationId"; private static final String API_ID = "apiId"; private static final String VER = "version"; private static final String RETIRE = IRouteBuilder.join(ORG_ID, API_ID, VER); private static final String ENDPOINT = IRouteBuilder.join(ORG_ID, API_ID, VER) + "/endpoint"; private VertxEngineConfig apimanConfig; private String host; private IRegistry registry; private RoutingContext routingContext; private IEngine engine; public ApiResourceImpl(VertxEngineConfig apimanConfig, IEngine engine) { this.apimanConfig = apimanConfig; this.registry = engine.getRegistry(); this.engine = engine; this.routingContext = null; } private ApiResourceImpl(VertxEngineConfig apimanConfig, IEngine engine, RoutingContext routingContext) { this.apimanConfig = apimanConfig; this.registry = engine.getRegistry(); this.engine = engine; this.routingContext = routingContext; } @Override public void publish(Api api) throws PublishingException, NotAuthorizedException { registry.publishApi(api, (IAsyncResultHandler<Void>) result -> { if (result.isError()) { Throwable e = result.getError(); if (e instanceof PublishingException) { error(routingContext, HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); } else if (e instanceof NotAuthorizedException) { error(routingContext, HttpResponseStatus.UNAUTHORIZED, e.getMessage(), e); } else { error(routingContext, HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); } } else { end(routingContext, HttpResponseStatus.NO_CONTENT); } }); } public void publish() { try { publish(Json.decodeValue(routingContext.getBodyAsString(), Api.class)); } catch (Exception e) { error(routingContext, HttpResponseStatus.BAD_REQUEST, e.getMessage(), e); } } @Override public void retire(String organizationId, String apiId, String version) throws RegistrationException, NotAuthorizedException { Api api = new Api(); api.setOrganizationId(organizationId); api.setApiId(apiId); api.setVersion(version); registry.retireApi(api, (IAsyncResultHandler<Void>) result -> { if (result.isError()) { Throwable e = result.getError(); if (e instanceof RegistrationException) { error(routingContext, HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); } else if (e instanceof NotAuthorizedException) { error(routingContext, HttpResponseStatus.UNAUTHORIZED, e.getMessage(), e); } else { error(routingContext, HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); } } else { end(routingContext, HttpResponseStatus.NO_CONTENT); } }); } public void retire() { String orgId = routingContext.request().getParam(ORG_ID); String apiId = routingContext.request().getParam(API_ID); String ver = routingContext.request().getParam(VER); retire(orgId, apiId, ver); } @Override public ApiEndpoint getApiEndpoint(String organizationId, String apiId, String version) throws NotAuthorizedException { String scheme = apimanConfig.preferSecure() ? "https" : "http"; int port = apimanConfig.getPort(scheme); String host = this.host; String path = ""; // If endpoint was manually specified if (apimanConfig.getPublicEndpoint() != null) { URI publicEndpoint = URI.create(apimanConfig.getPublicEndpoint()); if (publicEndpoint.getPort() != -1) { port = publicEndpoint.getPort(); } if (publicEndpoint.getScheme() != null && !publicEndpoint.getScheme().isEmpty()) { scheme = publicEndpoint.getScheme(); } if (publicEndpoint.getPath() != null && !publicEndpoint.getPath().isEmpty()) { path = publicEndpoint.getPath(); } if (publicEndpoint.getHost() != null && !publicEndpoint.getHost().isEmpty()) { host = publicEndpoint.getHost(); } } String endpoint = scheme + "://" + host; if (port != 443 && port != 80) endpoint += ":" + port + "/"; endpoint += path; endpoint += SimpleStringUtils.join("/", organizationId, apiId, version); ApiEndpoint endpointObj = new ApiEndpoint(); endpointObj.setEndpoint(endpoint); return endpointObj; } public void getApiEndpoint(RoutingContext routingContext) { if (apimanConfig.getPublicEndpoint() == null) { try { host = new URL(routingContext.request().absoluteURI()).getHost(); } catch (MalformedURLException e) { throw new RuntimeException(e); } } String orgId = routingContext.request().getParam(ORG_ID); String apiId = routingContext.request().getParam(API_ID); String ver = routingContext.request().getParam(VER); try { writeBody(routingContext, getApiEndpoint(orgId, apiId, ver)); } catch (NotAuthorizedException e) { error(routingContext, HttpResponseStatus.UNAUTHORIZED, e.getMessage(), e); } } @Override public void buildRoutes(Router router) { router.put(buildPath("")).handler(routingContext -> { new ApiResourceImpl(apimanConfig, engine, routingContext).publish(); }); router.delete(buildPath(RETIRE)).handler(routingContext -> { new ApiResourceImpl(apimanConfig, engine, routingContext).retire(); }); router.get(buildPath(ENDPOINT)).handler(this::getApiEndpoint); } @Override public String getPath() { return "apis"; } }