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

com.nepxion.discovery.plugin.strategy.gateway.route.AbstractGatewayStrategyRoute Maven / Gradle / Ivy

package com.nepxion.discovery.plugin.strategy.gateway.route;

/**
 * 

Title: Nepxion Discovery

*

Description: Nepxion Discovery

*

Copyright: Copyright (c) 2017-2050

*

Company: Nepxion

* @author Ning Zhang * @author Haojun Ren * @version 1.0 */ import reactor.core.Disposable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.net.URI; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ExecutorService; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.config.GatewayProperties; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionLocator; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.web.util.UriComponentsBuilder; import com.fasterxml.jackson.core.type.TypeReference; import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.entity.GatewayStrategyRouteEntity; import com.nepxion.discovery.common.exception.DiscoveryException; import com.nepxion.discovery.common.future.DiscoveryFutureCallback; import com.nepxion.discovery.common.future.DiscoveryFutureResolver; import com.nepxion.discovery.common.thread.DiscoveryThreadPoolFactory; import com.nepxion.discovery.common.util.JsonUtil; import com.nepxion.discovery.plugin.framework.event.PluginPublisher; import com.nepxion.discovery.plugin.strategy.gateway.event.GatewayStrategyRouteAddedEvent; import com.nepxion.discovery.plugin.strategy.gateway.event.GatewayStrategyRouteDeletedEvent; import com.nepxion.discovery.plugin.strategy.gateway.event.GatewayStrategyRouteModifiedEvent; import com.nepxion.discovery.plugin.strategy.gateway.event.GatewayStrategyRouteUpdatedAllEvent; public abstract class AbstractGatewayStrategyRoute implements GatewayStrategyRoute, ApplicationEventPublisherAware { private static final Logger LOG = LoggerFactory.getLogger(AbstractGatewayStrategyRoute.class); private ExecutorService executorService = DiscoveryThreadPoolFactory.getExecutorService("gateway-route"); @Autowired private RouteDefinitionLocator routeDefinitionLocator; @Autowired private RouteDefinitionWriter routeDefinitionWriter; @Autowired private GatewayProperties gatewayProperties; @Autowired private PluginPublisher pluginPublisher; private ApplicationEventPublisher applicationEventPublisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } @Override public synchronized void add(GatewayStrategyRouteEntity gatewayStrategyRouteEntity) { if (gatewayStrategyRouteEntity == null) { throw new DiscoveryException("Gateway dynamic route is null"); } Map routeDefinitionMap = locateRoutes(); String routeId = gatewayStrategyRouteEntity.getId(); if (routeDefinitionMap.containsKey(routeId)) { throw new DiscoveryException("Gateway dynamic route for routeId=[" + routeId + "] is duplicated"); } RouteDefinition routeDefinition = convertRoute(gatewayStrategyRouteEntity); addRoute(routeDefinition); LOG.info("Added Gateway dynamic route={}", routeDefinition); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); pluginPublisher.asyncPublish(new GatewayStrategyRouteAddedEvent(gatewayStrategyRouteEntity)); } @Override public synchronized void modify(GatewayStrategyRouteEntity gatewayStrategyRouteEntity) { if (gatewayStrategyRouteEntity == null) { throw new DiscoveryException("Gateway dynamic route is null"); } Map routeDefinitionMap = locateRoutes(); String routeId = gatewayStrategyRouteEntity.getId(); if (!routeDefinitionMap.containsKey(routeId)) { throw new DiscoveryException("Gateway dynamic route for routeId=[" + routeId + "] isn't found"); } RouteDefinition routeDefinition = convertRoute(gatewayStrategyRouteEntity); modifyRoute(routeDefinition); LOG.info("Modified Gateway dynamic route={}", routeDefinition); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); pluginPublisher.asyncPublish(new GatewayStrategyRouteModifiedEvent(gatewayStrategyRouteEntity)); } @Override public synchronized void delete(String routeId) { if (StringUtils.isEmpty(routeId)) { throw new DiscoveryException("RouteId is empty"); } Map routeDefinitionMap = locateRoutes(); RouteDefinition routeDefinition = routeDefinitionMap.get(routeId); if (routeDefinition == null) { throw new DiscoveryException("Gateway dynamic route for routeId=[" + routeId + "] isn't found"); } deleteRoute(routeDefinition); LOG.info("Deleted Gateway dynamic route for routeId={}", routeId); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); pluginPublisher.asyncPublish(new GatewayStrategyRouteDeletedEvent(routeId)); } @Override public synchronized void updateAll(List gatewayStrategyRouteEntityList) { if (gatewayStrategyRouteEntityList == null) { throw new DiscoveryException("Gateway dynamic routes are null"); } boolean isIdDuplicated = isIdDuplicated(gatewayStrategyRouteEntityList); if (isIdDuplicated) { throw new DiscoveryException("Gateway dynamic routes have duplicated routeIds"); } Map dynamicRouteDefinitionMap = gatewayStrategyRouteEntityList.stream().collect(Collectors.toMap(GatewayStrategyRouteEntity::getId, this::convertRoute)); Map currentRouteDefinitionMap = locateRoutes(); List addRouteDefinitionList = new ArrayList(dynamicRouteDefinitionMap.size()); List modifyRouteDefinitionList = new ArrayList(dynamicRouteDefinitionMap.size()); List deleteRouteDefinitionList = new ArrayList(dynamicRouteDefinitionMap.size()); for (Map.Entry entry : dynamicRouteDefinitionMap.entrySet()) { String routeId = entry.getKey(); RouteDefinition routeDefinition = entry.getValue(); if (!currentRouteDefinitionMap.containsKey(routeId)) { addRouteDefinitionList.add(routeDefinition); } } for (Map.Entry entry : dynamicRouteDefinitionMap.entrySet()) { String routeId = entry.getKey(); RouteDefinition routeDefinition = entry.getValue(); if (currentRouteDefinitionMap.containsKey(routeId)) { RouteDefinition currentRouteDefinition = currentRouteDefinitionMap.get(routeId); if (!currentRouteDefinition.equals(routeDefinition)) { modifyRouteDefinitionList.add(routeDefinition); } } } for (Map.Entry entry : currentRouteDefinitionMap.entrySet()) { String routeId = entry.getKey(); RouteDefinition routeDefinition = entry.getValue(); if (!dynamicRouteDefinitionMap.containsKey(routeId)) { deleteRouteDefinitionList.add(routeDefinition); } } for (RouteDefinition routeDefinition : addRouteDefinitionList) { addRoute(routeDefinition); } for (RouteDefinition routeDefinition : modifyRouteDefinitionList) { modifyRoute(routeDefinition); } for (RouteDefinition routeDefinition : deleteRouteDefinitionList) { deleteRoute(routeDefinition); } LOG.info("--- Gateway Dynamic Routes Update Information ----"); LOG.info("Total count={}", gatewayStrategyRouteEntityList.size()); LOG.info("Added count={}", addRouteDefinitionList.size()); LOG.info("Modified count={}", modifyRouteDefinitionList.size()); LOG.info("Deleted count={}", deleteRouteDefinitionList.size()); LOG.info("--------------------------------------------------"); if (addRouteDefinitionList.isEmpty() && modifyRouteDefinitionList.isEmpty() && deleteRouteDefinitionList.isEmpty()) { return; } applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); pluginPublisher.asyncPublish(new GatewayStrategyRouteUpdatedAllEvent(gatewayStrategyRouteEntityList)); } @Override public synchronized void updateAll(String gatewayStrategyRouteConfig) { if (StringUtils.isBlank(gatewayStrategyRouteConfig)) { gatewayStrategyRouteConfig = DiscoveryConstant.EMPTY_JSON_RULE_MULTIPLE; } List gatewayStrategyRouteEntityList = JsonUtil.fromJson(gatewayStrategyRouteConfig, new TypeReference>() { }); updateAll(gatewayStrategyRouteEntityList); } @Override public GatewayStrategyRouteEntity view(String routeId) { if (StringUtils.isEmpty(routeId)) { throw new DiscoveryException("RouteId is empty"); } RouteDefinition routeDefinition = locateRoutes().get(routeId); if (routeDefinition == null) { throw new DiscoveryException("Gateway dynamic route for routeId=[" + routeId + "] isn't found"); } return convertRoute(routeDefinition); } @Override public List viewAll() { List gatewayStrategyRouteEntityList = new ArrayList(); Map routeDefinitionMap = locateRoutes(); for (Map.Entry entry : routeDefinitionMap.entrySet()) { RouteDefinition routeDefinition = entry.getValue(); GatewayStrategyRouteEntity gatewayStrategyRouteEntity = convertRoute(routeDefinition); gatewayStrategyRouteEntityList.add(gatewayStrategyRouteEntity); } return gatewayStrategyRouteEntityList; } public Map locateRoutes() { /* Map routeDefinitionMap = new HashMap(); Flux routeDefinitions = routeDefinitionLocator.getRouteDefinitions(); Disposable disposable = null; try { disposable = routeDefinitions.subscribe(routeDefinition -> routeDefinitionMap.put(routeDefinition.getId(), routeDefinition)); try { Thread.sleep(100); } catch (InterruptedException e) { } } finally { if (disposable != null) { disposable.dispose(); } } return routeDefinitionMap; */ Flux routeDefinitions = routeDefinitionLocator.getRouteDefinitions(); try { return DiscoveryFutureResolver.call(executorService, new DiscoveryFutureCallback>() { @Override public Map callback() { List routeDefinitionList = routeDefinitions.collectList().block(); return routeDefinitionList.stream().collect(Collectors.toMap(RouteDefinition::getId, RouteDefinition -> RouteDefinition)); } }); } catch (Exception e) { return new HashMap(); } } private boolean isIdDuplicated(List gatewayStrategyRouteEntityList) { Set gatewayStrategyRouteEntitySet = new TreeSet(new Comparator() { public int compare(GatewayStrategyRouteEntity gatewayStrategyRouteEntity1, GatewayStrategyRouteEntity gatewayStrategyRouteEntity2) { return gatewayStrategyRouteEntity1.getId().compareTo(gatewayStrategyRouteEntity2.getId()); } }); gatewayStrategyRouteEntitySet.addAll(gatewayStrategyRouteEntityList); return gatewayStrategyRouteEntitySet.size() < gatewayStrategyRouteEntityList.size(); } public RouteDefinition convertRoute(GatewayStrategyRouteEntity gatewayStrategyRouteEntity) { RouteDefinition routeDefinition = new RouteDefinition(); routeDefinition.setId(gatewayStrategyRouteEntity.getId()); routeDefinition.setUri(convertURI(gatewayStrategyRouteEntity.getUri())); List predicateList = gatewayStrategyRouteEntity.getPredicates(); List userPredicates = gatewayStrategyRouteEntity.getUserPredicates(); List predicateDefinitionList = new ArrayList(predicateList.size() + userPredicates.size()); for (String predicate : predicateList) { predicateDefinitionList.add(new PredicateDefinition(predicate)); } for (GatewayStrategyRouteEntity.Predicate predicate : userPredicates) { PredicateDefinition predicateDefinition = new PredicateDefinition(); predicateDefinition.setName(predicate.getName()); predicateDefinition.setArgs(predicate.getArgs()); predicateDefinitionList.add(predicateDefinition); } routeDefinition.setPredicates(predicateDefinitionList); List filterList = gatewayStrategyRouteEntity.getFilters(); List userFilters = gatewayStrategyRouteEntity.getUserFilters(); List filterDefinitionList = new ArrayList(filterList.size() + userFilters.size()); for (String filter : filterList) { filterDefinitionList.add(new FilterDefinition(filter)); } for (GatewayStrategyRouteEntity.Filter filter : userFilters) { FilterDefinition filterDefinition = new FilterDefinition(); filterDefinition.setName(filter.getName()); filterDefinition.setArgs(filter.getArgs()); filterDefinitionList.add(filterDefinition); } routeDefinition.setFilters(filterDefinitionList); routeDefinition.setOrder(gatewayStrategyRouteEntity.getOrder()); // Metadata isn't supported in Finchley and Greenwich try { routeDefinition.setMetadata(gatewayStrategyRouteEntity.getMetadata()); } catch (Throwable e) { } return routeDefinition; } public GatewayStrategyRouteEntity convertRoute(RouteDefinition routeDefinition) { GatewayStrategyRouteEntity gatewayStrategyRouteEntity = new GatewayStrategyRouteEntity(); gatewayStrategyRouteEntity.setId(routeDefinition.getId()); gatewayStrategyRouteEntity.setUri(routeDefinition.getUri().toString()); gatewayStrategyRouteEntity.setOrder(routeDefinition.getOrder()); // Metadata isn't supported in Finchley and Greenwich try { gatewayStrategyRouteEntity.setMetadata(routeDefinition.getMetadata()); } catch (Throwable e) { } convertPredicates(routeDefinition.getPredicates(), gatewayStrategyRouteEntity.getPredicates(), gatewayStrategyRouteEntity.getUserPredicates()); convertFilters(routeDefinition.getFilters(), gatewayStrategyRouteEntity.getFilters(), gatewayStrategyRouteEntity.getUserFilters()); return gatewayStrategyRouteEntity; } public void convertPredicates(List predicateDefinitionList, List predicateList, List userPredicateList) { for (PredicateDefinition predicateDefinition : predicateDefinitionList) { String name = predicateDefinition.getName(); Map args = predicateDefinition.getArgs(); boolean internal = isInternal(args); if (internal) { predicateList.add(String.format("%s=%s", name, StringUtils.join(args.values(), ","))); } else { GatewayStrategyRouteEntity.Predicate predicate = new GatewayStrategyRouteEntity.Predicate(); predicate.setName(predicateDefinition.getName()); predicate.setArgs(predicateDefinition.getArgs()); userPredicateList.add(predicate); } } } public void convertFilters(List filterDefinitionList, List filterList, List userFilterList) { for (FilterDefinition filterDefinition : filterDefinitionList) { String name = filterDefinition.getName(); Map args = filterDefinition.getArgs(); boolean internal = isInternal(args); if (internal) { filterList.add(String.format("%s=%s", name, StringUtils.join(args.values(), ","))); } else { GatewayStrategyRouteEntity.Filter filter = new GatewayStrategyRouteEntity.Filter(); filter.setName(filterDefinition.getName()); filter.setArgs(filterDefinition.getArgs()); userFilterList.add(filter); } } } public boolean isInternal(Map args) { for (Map.Entry entry : args.entrySet()) { String key = entry.getKey(); // 如果key包含_genkey_,表示为网关内置配置,例如,Path,RewritePath的key都会以_genkey_来命名 if (key.contains("_genkey_")) { return true; } } return false; } public URI convertURI(String value) { URI uri; if (value.toLowerCase().startsWith("http") || value.toLowerCase().startsWith("https")) { uri = UriComponentsBuilder.fromHttpUrl(value).build().toUri(); } else { uri = URI.create(value); } return uri; } public void addRoute(RouteDefinition routeDefinition) { Disposable disposable = null; try { disposable = routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe(); } finally { if (disposable != null) { disposable.dispose(); } } } public void modifyRoute(RouteDefinition routeDefinition) { deleteRoute(routeDefinition); addRoute(routeDefinition); } public void deleteRoute(RouteDefinition routeDefinition) { Disposable disposable = null; try { disposable = routeDefinitionWriter .delete(Mono.just(routeDefinition.getId())) .onErrorResume(new Function>() { @Override public Mono apply(Throwable throwable) { if (throwable instanceof NotFoundException) { gatewayProperties.getRoutes().removeIf(new Predicate() { @Override public boolean test(RouteDefinition routeCandidate) { return routeCandidate.getId().equals(routeDefinition.getId()); } }); return Mono.empty(); } return Mono.error(throwable); } }).subscribe(); } finally { if (disposable != null) { disposable.dispose(); } } } public void clearRoutes() { Map routeDefinitionMap = locateRoutes(); for (Map.Entry entry : routeDefinitionMap.entrySet()) { RouteDefinition routeDefinition = entry.getValue(); deleteRoute(routeDefinition); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy