1616
1717package org .springframework .cloud .gateway .actuate ;
1818
19+ import java .io .IOException ;
1920import java .net .URI ;
21+ import java .util .ArrayList ;
22+ import java .util .Arrays ;
2023import java .util .HashMap ;
2124import java .util .List ;
2225import java .util .Map ;
2326import java .util .Set ;
2427import java .util .stream .Collectors ;
28+ import java .util .stream .Stream ;
2529
2630import org .apache .commons .logging .Log ;
2731import org .apache .commons .logging .LogFactory ;
2832import reactor .core .publisher .Flux ;
2933import reactor .core .publisher .Mono ;
3034
35+ import org .springframework .boot .actuate .autoconfigure .endpoint .web .WebEndpointProperties ;
3136import org .springframework .cloud .gateway .event .RefreshRoutesEvent ;
3237import org .springframework .cloud .gateway .filter .FilterDefinition ;
3338import org .springframework .cloud .gateway .filter .GlobalFilter ;
3439import org .springframework .cloud .gateway .filter .factory .GatewayFilterFactory ;
3540import org .springframework .cloud .gateway .handler .predicate .PredicateDefinition ;
3641import org .springframework .cloud .gateway .handler .predicate .RoutePredicateFactory ;
42+ import org .springframework .cloud .gateway .route .Route ;
3743import org .springframework .cloud .gateway .route .RouteDefinition ;
3844import org .springframework .cloud .gateway .route .RouteDefinitionLocator ;
3945import org .springframework .cloud .gateway .route .RouteDefinitionWriter ;
4248import org .springframework .context .ApplicationEventPublisher ;
4349import org .springframework .context .ApplicationEventPublisherAware ;
4450import org .springframework .core .Ordered ;
51+ import org .springframework .core .type .MethodMetadata ;
52+ import org .springframework .core .type .classreading .MetadataReader ;
53+ import org .springframework .core .type .classreading .SimpleMetadataReaderFactory ;
4554import org .springframework .http .HttpStatus ;
4655import org .springframework .http .ResponseEntity ;
4756import org .springframework .util .CollectionUtils ;
5160import org .springframework .web .bind .annotation .PathVariable ;
5261import org .springframework .web .bind .annotation .PostMapping ;
5362import org .springframework .web .bind .annotation .RequestBody ;
63+ import org .springframework .web .bind .annotation .RequestMapping ;
64+ import org .springframework .web .bind .annotation .RequestMethod ;
5465import org .springframework .web .bind .annotation .RequestParam ;
5566import org .springframework .web .server .ResponseStatusException ;
5667
@@ -76,16 +87,77 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis
7687
7788 protected ApplicationEventPublisher publisher ;
7889
90+ protected WebEndpointProperties webEndpointProperties ;
91+
92+ private final SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory ();
93+
94+ @ Deprecated
7995 public AbstractGatewayControllerEndpoint (RouteDefinitionLocator routeDefinitionLocator ,
8096 List <GlobalFilter > globalFilters , List <GatewayFilterFactory > gatewayFilters ,
8197 List <RoutePredicateFactory > routePredicates , RouteDefinitionWriter routeDefinitionWriter ,
8298 RouteLocator routeLocator ) {
99+ this (routeDefinitionLocator , globalFilters , gatewayFilters , routePredicates ,
100+ routeDefinitionWriter , routeLocator , new WebEndpointProperties ());
101+ }
102+
103+ public AbstractGatewayControllerEndpoint (RouteDefinitionLocator routeDefinitionLocator ,
104+ List <GlobalFilter > globalFilters , List <GatewayFilterFactory > gatewayFilters ,
105+ List <RoutePredicateFactory > routePredicates , RouteDefinitionWriter routeDefinitionWriter ,
106+ RouteLocator routeLocator , WebEndpointProperties webEndpointProperties ) {
83107 this .routeDefinitionLocator = routeDefinitionLocator ;
84108 this .globalFilters = globalFilters ;
85109 this .GatewayFilters = gatewayFilters ;
86110 this .routePredicates = routePredicates ;
87111 this .routeDefinitionWriter = routeDefinitionWriter ;
88112 this .routeLocator = routeLocator ;
113+ this .webEndpointProperties = webEndpointProperties ;
114+ }
115+
116+ @ GetMapping ("/" )
117+ Mono <List <GatewayEndpointInfo >> getEndpoints () {
118+ List <GatewayEndpointInfo > endpoints = mergeEndpoints (
119+ getAvailableEndpointsForClass (AbstractGatewayControllerEndpoint .class .getName ()),
120+ getAvailableEndpointsForClass (GatewayControllerEndpoint .class .getName ()));
121+
122+ return Flux .fromIterable (endpoints ).map (p -> p )
123+ .flatMap (path -> this .routeLocator .getRoutes ().map (r -> generateHref (r , path )).distinct ().collectList ()
124+ .flatMapMany (Flux ::fromIterable ))
125+ .distinct () // Ensure overall uniqueness
126+ .collectList ();
127+ }
128+
129+ private List <GatewayEndpointInfo > mergeEndpoints (List <GatewayEndpointInfo > listA ,
130+ List <GatewayEndpointInfo > listB ) {
131+ Map <String , List <String >> mergedMap = new HashMap <>();
132+
133+ Stream .concat (listA .stream (), listB .stream ()).forEach (e -> mergedMap
134+ .computeIfAbsent (e .getHref (), k -> new ArrayList <>()).addAll (Arrays .asList (e .getMethods ())));
135+
136+ return mergedMap .entrySet ().stream ().map (entry -> new GatewayEndpointInfo (entry .getKey (), entry .getValue ()))
137+ .collect (Collectors .toList ());
138+ }
139+
140+ private List <GatewayEndpointInfo > getAvailableEndpointsForClass (String className ) {
141+ try {
142+ MetadataReader metadataReader = simpleMetadataReaderFactory .getMetadataReader (className );
143+ Set <MethodMetadata > annotatedMethods = metadataReader .getAnnotationMetadata ()
144+ .getAnnotatedMethods (RequestMapping .class .getName ());
145+
146+ String gatewayActuatorPath = webEndpointProperties .getBasePath () + "/gateway" ;
147+ return annotatedMethods .stream ().map (method -> new GatewayEndpointInfo (gatewayActuatorPath
148+ + ((String []) method .getAnnotationAttributes (RequestMapping .class .getName ()).get ("path" ))[0 ],
149+ ((RequestMethod []) method .getAnnotationAttributes (RequestMapping .class .getName ()).get ("method" ))[0 ]
150+ .name ()))
151+ .collect (Collectors .toList ());
152+ }
153+ catch (IOException exception ) {
154+ log .warn (exception .getMessage ());
155+ throw new ResponseStatusException (HttpStatus .INTERNAL_SERVER_ERROR , exception .getMessage ());
156+ }
157+ }
158+
159+ private GatewayEndpointInfo generateHref (Route r , GatewayEndpointInfo path ) {
160+ return new GatewayEndpointInfo (path .getHref ().replace ("{id}" , r .getId ()), Arrays .asList (path .getMethods ()));
89161 }
90162
91163 @ Override
0 commit comments