18
18
19
19
import java .lang .reflect .Method ;
20
20
import java .util .ArrayList ;
21
+ import java .util .Arrays ;
21
22
import java .util .Collection ;
22
23
import java .util .HashMap ;
23
24
import java .util .List ;
24
25
import java .util .Map ;
25
26
import java .util .Map .Entry ;
26
27
import java .util .concurrent .atomic .AtomicInteger ;
28
+ import java .util .function .Function ;
29
+ import java .util .stream .Collectors ;
30
+ import java .util .stream .Stream ;
27
31
28
32
import org .springframework .beans .BeansException ;
29
33
import org .springframework .context .ApplicationContext ;
42
46
import org .springframework .integration .router .RecipientListRouterManagement ;
43
47
import org .springframework .integration .support .context .NamedComponent ;
44
48
import org .springframework .integration .support .management .MappingMessageRouterManagement ;
49
+ import org .springframework .lang .Nullable ;
45
50
import org .springframework .messaging .MessageChannel ;
46
51
import org .springframework .messaging .MessageHandler ;
47
- import org .springframework .util .StringUtils ;
48
52
49
53
/**
50
54
* Builds the runtime object model graph.
@@ -67,11 +71,17 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
67
71
68
72
private String applicationName ;
69
73
74
+ private Function <NamedComponent , Map <String , Object >> additionalPropertiesCallback ;
75
+
70
76
@ Override
71
77
public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
72
78
this .applicationContext = applicationContext ; //NOSONAR (sync)
73
79
}
74
80
81
+ protected ApplicationContext getApplicationContext () {
82
+ return this .applicationContext ;
83
+ }
84
+
75
85
/**
76
86
* Set the application name that will appear in the 'contentDescriptor' under
77
87
* the 'name' key. If not provided, the property 'spring.application.name' from
@@ -82,6 +92,24 @@ public void setApplicationName(String applicationName) {
82
92
this .applicationName = applicationName ; //NOSONAR (sync)
83
93
}
84
94
95
+ /**
96
+ * Specify a callback {@link Function} to be called against each {@link NamedComponent}
97
+ * to populate additional properties to the target {@link IntegrationNode}.
98
+ * @param additionalPropertiesCallback the {@link Function} to use for properties.
99
+ * @since 5.1
100
+ */
101
+ public void setAdditionalPropertiesCallback (
102
+ @ Nullable Function <NamedComponent , Map <String , Object >> additionalPropertiesCallback ) {
103
+ this .additionalPropertiesCallback = additionalPropertiesCallback ;
104
+ }
105
+
106
+ @ Override
107
+ public void onApplicationEvent (ContextRefreshedEvent event ) {
108
+ if (event .getApplicationContext ().equals (this .applicationContext )) {
109
+ buildGraph ();
110
+ }
111
+ }
112
+
85
113
/**
86
114
* Return the cached graph. Although the graph is cached, the data therein (stats
87
115
* etc.) are dynamic.
@@ -99,11 +127,27 @@ public Graph getGraph() {
99
127
return this .graph ;
100
128
}
101
129
102
- @ Override
103
- public void onApplicationEvent (ContextRefreshedEvent event ) {
104
- if (event .getApplicationContext ().equals (this .applicationContext )) {
105
- buildGraph ();
106
- }
130
+ /**
131
+ * Rebuild the graph, re-cache it, and return it. Use this method if the application
132
+ * components have changed (added or removed).
133
+ * @return the graph.
134
+ * @see #getGraph()
135
+ */
136
+ public Graph rebuild () {
137
+ return buildGraph ();
138
+ }
139
+
140
+ /**
141
+ * Get beans for the provided type from the application context.
142
+ * This method can be extended for some custom logic, e.g. get beans
143
+ * from the parent application context as well.
144
+ * @param type the type for beans to obtain
145
+ * @param <T> the type for beans to obtain
146
+ * @return a {@link Map} of bean for the provided type
147
+ * @since 5.1
148
+ */
149
+ protected <T > Map <String , T > getBeansOfType (Class <T > type ) {
150
+ return this .applicationContext .getBeansOfType (type , true , false );
107
151
}
108
152
109
153
private synchronized Graph buildGraph () {
@@ -135,95 +179,129 @@ private synchronized Graph buildGraph() {
135
179
}
136
180
137
181
private Map <String , MessageChannelNode > channels (Collection <IntegrationNode > nodes ) {
138
- Map <String , MessageChannel > channels = this .applicationContext
139
- .getBeansOfType (MessageChannel .class , true , false );
140
- Map <String , MessageChannelNode > channelNodes = new HashMap <>();
141
- for (Entry <String , MessageChannel > entry : channels .entrySet ()) {
142
- MessageChannel channel = entry .getValue ();
143
- MessageChannelNode channelNode = this .nodeFactory .channelNode (entry .getKey (), channel );
144
- String beanName = entry .getKey ();
145
- nodes .add (channelNode );
146
- channelNodes .put (beanName , channelNode );
147
- }
148
- return channelNodes ;
182
+ return getBeansOfType (MessageChannel .class )
183
+ .entrySet ()
184
+ .stream ()
185
+ .map (e -> {
186
+ MessageChannel messageChannel = e .getValue ();
187
+ MessageChannelNode messageChannelNode = this .nodeFactory .channelNode (e .getKey (), messageChannel );
188
+ if (messageChannel instanceof NamedComponent ) {
189
+ messageChannelNode .addProperties (getAdditionalPropertiesIfAny ((NamedComponent ) messageChannel ));
190
+ }
191
+ return messageChannelNode ;
192
+ })
193
+ .peek (nodes ::add )
194
+ .collect (Collectors .toMap (MessageChannelNode ::getName , Function .identity ()));
149
195
}
150
196
151
197
private void pollingAdapters (Collection <IntegrationNode > nodes , Collection <LinkNode > links ,
152
198
Map <String , MessageChannelNode > channelNodes ) {
153
199
154
- Map <String , SourcePollingChannelAdapter > spcas = this .applicationContext
155
- .getBeansOfType (SourcePollingChannelAdapter .class , true , false );
156
- for (Entry <String , SourcePollingChannelAdapter > entry : spcas .entrySet ()) {
157
- SourcePollingChannelAdapter adapter = entry .getValue ();
158
- MessageSourceNode sourceNode = this .nodeFactory .sourceNode (entry .getKey (), adapter );
159
- nodes .add (sourceNode );
160
- producerLink (links , channelNodes , sourceNode );
161
- }
200
+ getBeansOfType (SourcePollingChannelAdapter .class )
201
+ .entrySet ()
202
+ .stream ()
203
+ .map (e -> {
204
+ SourcePollingChannelAdapter sourceAdapter = e .getValue ();
205
+ MessageSourceNode sourceNode = this .nodeFactory .sourceNode (e .getKey (), sourceAdapter );
206
+ sourceNode .addProperties (getAdditionalPropertiesIfAny (sourceAdapter ));
207
+ return sourceNode ;
208
+ })
209
+ .peek (nodes ::add )
210
+ .forEach (sourceNode -> producerLink (links , channelNodes , sourceNode ));
162
211
}
163
212
164
213
private void gateways (Collection <IntegrationNode > nodes , Collection <LinkNode > links ,
165
214
Map <String , MessageChannelNode > channelNodes ) {
166
215
167
- Map <String , MessagingGatewaySupport > gateways = this .applicationContext
168
- .getBeansOfType (MessagingGatewaySupport .class , true , false );
169
- for (Entry <String , MessagingGatewaySupport > entry : gateways .entrySet ()) {
170
- MessagingGatewaySupport gateway = entry .getValue ();
171
- MessageGatewayNode gatewayNode = this .nodeFactory .gatewayNode (entry .getKey (), gateway );
172
- nodes .add (gatewayNode );
173
- producerLink (links , channelNodes , gatewayNode );
174
- }
175
- Map <String , GatewayProxyFactoryBean > gpfbs = this .applicationContext
176
- .getBeansOfType (GatewayProxyFactoryBean .class , true , false );
216
+ getBeansOfType (MessagingGatewaySupport .class )
217
+ .entrySet ()
218
+ .stream ()
219
+ .map (e -> {
220
+ MessagingGatewaySupport gateway = e .getValue ();
221
+ MessageGatewayNode gatewayNode = this .nodeFactory .gatewayNode (e .getKey (), gateway );
222
+ gatewayNode .addProperties (getAdditionalPropertiesIfAny (gateway ));
223
+ return gatewayNode ;
224
+ })
225
+ .peek (nodes ::add )
226
+ .forEach (gatewayNode -> producerLink (links , channelNodes , gatewayNode ));
227
+
228
+ Map <String , GatewayProxyFactoryBean > gpfbs = getBeansOfType (GatewayProxyFactoryBean .class );
229
+
177
230
for (Entry <String , GatewayProxyFactoryBean > entry : gpfbs .entrySet ()) {
178
- Map <Method , MessagingGatewaySupport > methodMap = entry .getValue ().getGateways ();
179
- for (Entry <Method , MessagingGatewaySupport > gwEntry : methodMap .entrySet ()) {
180
- MessagingGatewaySupport gateway = gwEntry .getValue ();
181
- Method method = gwEntry .getKey ();
182
- Class <?>[] parameterTypes = method .getParameterTypes ();
183
- String [] parameterTypeNames = new String [parameterTypes .length ];
184
- int i = 0 ;
185
- for (Class <?> type : parameterTypes ) {
186
- parameterTypeNames [i ++] = type .getName ();
187
- }
188
- String signature = method .getName () +
189
- "(" + StringUtils .arrayToCommaDelimitedString (parameterTypeNames ) + ")" ;
190
- MessageGatewayNode gatewayNode = this .nodeFactory .gatewayNode (
191
- entry .getKey ().substring (1 ) + "." + signature , gateway );
192
- nodes .add (gatewayNode );
193
- producerLink (links , channelNodes , gatewayNode );
194
- }
231
+ entry .getValue ()
232
+ .getGateways ()
233
+ .entrySet ()
234
+ .stream ()
235
+ .map (e -> {
236
+ MessagingGatewaySupport gateway = e .getValue ();
237
+ Method method = e .getKey ();
238
+
239
+ String nodeName =
240
+ entry .getKey ().substring (1 ) + "." +
241
+ method .getName () +
242
+ "(" +
243
+ Arrays .stream (method .getParameterTypes ())
244
+ .map (Class ::getName )
245
+ .collect (Collectors .joining ("," ))
246
+ + ")" ;
247
+
248
+ MessageGatewayNode gatewayNode = this .nodeFactory .gatewayNode (nodeName , gateway );
249
+ gatewayNode .addProperties (getAdditionalPropertiesIfAny (gateway ));
250
+ return gatewayNode ;
251
+ })
252
+ .peek (nodes ::add )
253
+ .forEach (gatewayNode -> producerLink (links , channelNodes , gatewayNode ));
195
254
}
196
255
}
197
256
198
257
private void producers (Collection <IntegrationNode > nodes , Collection <LinkNode > links ,
199
258
Map <String , MessageChannelNode > channelNodes ) {
200
259
201
- Map <String , MessageProducerSupport > producers = this .applicationContext
202
- .getBeansOfType (MessageProducerSupport .class , true , false );
203
- for (Entry <String , MessageProducerSupport > entry : producers .entrySet ()) {
204
- MessageProducerSupport producer = entry .getValue ();
205
- MessageProducerNode producerNode = this .nodeFactory .producerNode (entry .getKey (), producer );
206
- nodes .add (producerNode );
207
- producerLink (links , channelNodes , producerNode );
208
- }
260
+ getBeansOfType (MessageProducerSupport .class )
261
+ .entrySet ()
262
+ .stream ()
263
+ .map (e -> {
264
+ MessageProducerSupport producer = e .getValue ();
265
+ MessageProducerNode producerNode = this .nodeFactory .producerNode (e .getKey (), producer );
266
+ producerNode .addProperties (getAdditionalPropertiesIfAny (producer ));
267
+ return producerNode ;
268
+ })
269
+ .peek (nodes ::add )
270
+ .forEach (producerNode -> producerLink (links , channelNodes , producerNode ));
209
271
}
210
272
211
273
private void consumers (Collection <IntegrationNode > nodes , Collection <LinkNode > links ,
212
274
Map <String , MessageChannelNode > channelNodes ) {
213
275
214
- Map <String , IntegrationConsumer > consumers = this .applicationContext .getBeansOfType (IntegrationConsumer .class ,
215
- true , false );
216
- for (Entry <String , IntegrationConsumer > entry : consumers .entrySet ()) {
217
- IntegrationConsumer consumer = entry .getValue ();
218
- MessageHandlerNode handlerNode = consumer instanceof PollingConsumer
219
- ? this .nodeFactory .polledHandlerNode (entry .getKey (), (PollingConsumer ) consumer )
220
- : this .nodeFactory .handlerNode (entry .getKey (), consumer );
221
- nodes .add (handlerNode );
222
- MessageChannelNode channelNode = channelNodes .get (handlerNode .getInput ());
223
- if (channelNode != null ) {
224
- links .add (new LinkNode (channelNode .getNodeId (), handlerNode .getNodeId (), LinkNode .Type .input ));
225
- }
226
- producerLink (links , channelNodes , handlerNode );
276
+ getBeansOfType (IntegrationConsumer .class )
277
+ .entrySet ()
278
+ .stream ()
279
+ .map (e -> {
280
+ IntegrationConsumer consumer = e .getValue ();
281
+ MessageHandlerNode handlerNode =
282
+ consumer instanceof PollingConsumer
283
+ ? this .nodeFactory .polledHandlerNode (e .getKey (), (PollingConsumer ) consumer )
284
+ : this .nodeFactory .handlerNode (e .getKey (), consumer );
285
+ handlerNode .addProperties (getAdditionalPropertiesIfAny (consumer ));
286
+ return handlerNode ;
287
+ })
288
+ .peek (nodes ::add )
289
+ .forEach (handlerNode -> {
290
+ MessageChannelNode channelNode = channelNodes .get (handlerNode .getInput ());
291
+ if (channelNode != null ) {
292
+ links .add (new LinkNode (channelNode .getNodeId (), handlerNode .getNodeId (), LinkNode .Type .input ));
293
+ }
294
+ producerLink (links , channelNodes , handlerNode );
295
+ });
296
+ }
297
+
298
+ @ Nullable
299
+ private Map <String , Object > getAdditionalPropertiesIfAny (NamedComponent namedComponent ) {
300
+ if (this .additionalPropertiesCallback != null ) {
301
+ return this .additionalPropertiesCallback .apply (namedComponent );
302
+ }
303
+ else {
304
+ return null ;
227
305
}
228
306
}
229
307
@@ -260,16 +338,6 @@ private void producerLink(Collection<LinkNode> links, Map<String, MessageChannel
260
338
}
261
339
}
262
340
263
- /**
264
- * Rebuild the graph, re-cache it, and return it. Use this method if the application
265
- * components have changed (added or removed).
266
- * @return the graph.
267
- * @see #getGraph()
268
- */
269
- public Graph rebuild () {
270
- return buildGraph ();
271
- }
272
-
273
341
private static final class NodeFactory {
274
342
275
343
private final AtomicInteger nodeId = new AtomicInteger ();
@@ -363,15 +431,17 @@ else if (handler instanceof RecipientListRouterManagement) {
363
431
private MessageHandlerNode compositeHandler (String name , IntegrationConsumer consumer ,
364
432
CompositeMessageHandler handler , String output , String errors , boolean polled ) {
365
433
366
- List <MessageHandler > handlers = handler .getHandlers ();
367
- List <CompositeMessageHandlerNode .InnerHandler > innerHandlers = new ArrayList <>();
368
- for (MessageHandler innerHandler : handlers ) {
369
- if (innerHandler instanceof NamedComponent ) {
370
- NamedComponent named = (NamedComponent ) innerHandler ;
371
- innerHandlers .add (new CompositeMessageHandlerNode .InnerHandler (named .getComponentName (),
372
- named .getComponentType ()));
373
- }
374
- }
434
+ List <CompositeMessageHandlerNode .InnerHandler > innerHandlers =
435
+ handler .getHandlers ()
436
+ .stream ()
437
+ .filter (NamedComponent .class ::isInstance )
438
+ .map (NamedComponent .class ::cast )
439
+ .map (named ->
440
+ new CompositeMessageHandlerNode .InnerHandler (
441
+ named .getComponentName (),
442
+ named .getComponentType ()))
443
+ .collect (Collectors .toList ());
444
+
375
445
String inputChannel = consumer .getInputChannel () != null ? consumer .getInputChannel ().toString () : null ;
376
446
return polled
377
447
? new ErrorCapableCompositeMessageHandlerNode (this .nodeId .incrementAndGet (), name , handler ,
@@ -395,12 +465,11 @@ private MessageHandlerNode discardingHandler(String name, IntegrationConsumer co
395
465
private MessageHandlerNode routingHandler (String name , IntegrationConsumer consumer , MessageHandler handler ,
396
466
MappingMessageRouterManagement router , String output , String errors , boolean polled ) {
397
467
398
- Collection <String > routes = router .getChannelMappings ().values ();
399
- Collection <String > dynamicChannelNames = router .getDynamicChannelNames ();
400
- if (dynamicChannelNames .size () > 0 ) {
401
- routes = new ArrayList <String >(routes );
402
- routes .addAll (dynamicChannelNames );
403
- }
468
+ Collection <String > routes =
469
+ Stream .concat (router .getChannelMappings ().values ().stream (),
470
+ router .getDynamicChannelNames ().stream ())
471
+ .collect (Collectors .toList ());
472
+
404
473
String inputChannel = consumer .getInputChannel () != null ? consumer .getInputChannel ().toString () : null ;
405
474
return polled
406
475
? new ErrorCapableRoutingNode (this .nodeId .incrementAndGet (), name , handler ,
@@ -413,11 +482,12 @@ private MessageHandlerNode recipientListRoutingHandler(String name, IntegrationC
413
482
MessageHandler handler , RecipientListRouterManagement router , String output , String errors ,
414
483
boolean polled ) {
415
484
416
- Collection <?> recipients = router .getRecipients ();
417
- List <String > routes = new ArrayList <>(recipients .size ());
418
- for (Object recipient : recipients ) {
419
- routes .add (((Recipient ) recipient ).getChannel ().toString ());
420
- }
485
+ List <String > routes =
486
+ router .getRecipients ()
487
+ .stream ()
488
+ .map (recipient -> ((Recipient ) recipient ).getChannel ().toString ())
489
+ .collect (Collectors .toList ());
490
+
421
491
String inputChannel = consumer .getInputChannel () != null ? consumer .getInputChannel ().toString () : null ;
422
492
return polled
423
493
? new ErrorCapableRoutingNode (this .nodeId .incrementAndGet (), name , handler ,
0 commit comments