16
16
17
17
package org .springframework .integration .endpoint ;
18
18
19
+ import org .reactivestreams .Publisher ;
20
+
19
21
import org .springframework .beans .factory .BeanFactory ;
20
22
import org .springframework .beans .factory .SmartInitializingSingleton ;
21
23
import org .springframework .core .AttributeAccessor ;
22
24
import org .springframework .integration .IntegrationPattern ;
23
25
import org .springframework .integration .IntegrationPatternType ;
26
+ import org .springframework .integration .channel .ReactiveStreamsSubscribableChannel ;
24
27
import org .springframework .integration .core .MessageProducer ;
25
28
import org .springframework .integration .core .MessagingTemplate ;
26
29
import org .springframework .integration .history .MessageHistory ;
36
39
import org .springframework .util .Assert ;
37
40
import org .springframework .util .StringUtils ;
38
41
42
+ import reactor .core .Disposable ;
43
+ import reactor .core .Disposables ;
44
+ import reactor .core .publisher .Flux ;
45
+
39
46
/**
40
47
* A support class for producer endpoints that provides a setter for the
41
48
* output channel and a convenience method for sending Messages.
47
54
public abstract class MessageProducerSupport extends AbstractEndpoint implements MessageProducer , TrackableComponent ,
48
55
SmartInitializingSingleton , IntegrationPattern {
49
56
57
+ private final Disposable .Composite reactiveSubscriptions = Disposables .composite ();
58
+
50
59
private final MessagingTemplate messagingTemplate = new MessagingTemplate ();
51
60
52
61
private ErrorMessageStrategy errorMessageStrategy = new DefaultErrorMessageStrategy ();
@@ -196,13 +205,10 @@ protected void sendMessage(Message<?> messageArg) {
196
205
if (message == null ) {
197
206
throw new MessagingException ("cannot send a null message" );
198
207
}
199
- if (this .shouldTrack ) {
200
- message = MessageHistory .write (message , this , getMessageBuilderFactory ());
201
- }
208
+ message = trackMessageIfAny (message );
202
209
try {
203
- MessageChannel messageChannel = getOutputChannel ();
204
- Assert .state (messageChannel != null , "The 'outputChannel' or `outputChannelName` must be configured" );
205
- this .messagingTemplate .send (messageChannel , message );
210
+ MessageChannel outputChannel = getRequiredOutputChannel ();
211
+ this .messagingTemplate .send (outputChannel , message );
206
212
}
207
213
catch (RuntimeException ex ) {
208
214
if (!sendErrorMessageIfNecessary (message , ex )) {
@@ -211,14 +217,37 @@ protected void sendMessage(Message<?> messageArg) {
211
217
}
212
218
}
213
219
220
+ protected void subscribeToPublisher (Publisher <? extends Message <?>> publisher ) {
221
+ MessageChannel outputChannel = getRequiredOutputChannel ();
222
+ Flux <Message <?>> messageFlux =
223
+ Flux .from (publisher )
224
+ .map (this ::trackMessageIfAny );
225
+ if (outputChannel instanceof ReactiveStreamsSubscribableChannel ) {
226
+ ((ReactiveStreamsSubscribableChannel ) outputChannel ).subscribeTo (messageFlux );
227
+ }
228
+ else {
229
+ this .reactiveSubscriptions .add (
230
+ messageFlux
231
+ .doOnNext ((message ) -> {
232
+ try {
233
+ sendMessage (message );
234
+ }
235
+ catch (Exception ex ) {
236
+ logger .error ("Error sending a message: " + message , ex );
237
+ }
238
+ })
239
+ .subscribe ());
240
+ }
241
+ }
242
+
214
243
/**
215
244
* Send an error message based on the exception and message.
216
245
* @param message the message.
217
246
* @param exception the exception.
218
247
* @return true if the error channel is available and message sent.
219
248
* @since 4.3.10
220
249
*/
221
- protected final boolean sendErrorMessageIfNecessary (Message <?> message , RuntimeException exception ) {
250
+ protected final boolean sendErrorMessageIfNecessary (Message <?> message , Exception exception ) {
222
251
MessageChannel channel = getErrorChannel ();
223
252
if (channel != null ) {
224
253
this .messagingTemplate .send (channel , buildErrorMessage (message , exception ));
@@ -235,9 +264,8 @@ protected final boolean sendErrorMessageIfNecessary(Message<?> message, RuntimeE
235
264
* @return the error message.
236
265
* @since 4.3.10
237
266
*/
238
- protected final ErrorMessage buildErrorMessage (Message <?> message , RuntimeException exception ) {
239
- return this .errorMessageStrategy .buildErrorMessage (exception ,
240
- getErrorMessageAttributes (message ));
267
+ protected final ErrorMessage buildErrorMessage (Message <?> message , Exception exception ) {
268
+ return this .errorMessageStrategy .buildErrorMessage (exception , getErrorMessageAttributes (message ));
241
269
}
242
270
243
271
/**
@@ -252,4 +280,25 @@ protected AttributeAccessor getErrorMessageAttributes(Message<?> message) {
252
280
return ErrorMessageUtils .getAttributeAccessor (message , null );
253
281
}
254
282
283
+ private MessageChannel getRequiredOutputChannel () {
284
+ MessageChannel messageChannel = getOutputChannel ();
285
+ Assert .state (messageChannel != null , "The 'outputChannel' or `outputChannelName` must be configured" );
286
+ return messageChannel ;
287
+ }
288
+
289
+ private Message <?> trackMessageIfAny (Message <?> message ) {
290
+ if (this .shouldTrack ) {
291
+ return MessageHistory .write (message , this , getMessageBuilderFactory ());
292
+ }
293
+ else {
294
+ return message ;
295
+ }
296
+ }
297
+
298
+ @ Override
299
+ public void destroy () {
300
+ this .reactiveSubscriptions .dispose ();
301
+ super .destroy ();
302
+ }
303
+
255
304
}
0 commit comments