Skip to content

Commit 30fac62

Browse files
garyrussellartembilan
authored andcommitted
INT-4388: Add UdpServerListeningEvent
JIRA: https://jira.spring.io/browse/INT-4388 Publish an event when the UDP server socket is established. * Polishing - remove unreachable assertions
1 parent 23687e4 commit 30fac62

File tree

7 files changed

+110
-20
lines changed

7 files changed

+110
-20
lines changed

spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
2121
import java.util.concurrent.Executors;
2222
import java.util.concurrent.ThreadFactory;
2323

24+
import org.springframework.context.ApplicationEventPublisher;
25+
import org.springframework.context.ApplicationEventPublisherAware;
2426
import org.springframework.integration.endpoint.MessageProducerSupport;
2527
import org.springframework.scheduling.SchedulingAwareRunnable;
2628
import org.springframework.util.Assert;
@@ -33,27 +35,30 @@
3335
* @since 2.0
3436
*/
3537
public abstract class AbstractInternetProtocolReceivingChannelAdapter
36-
extends MessageProducerSupport implements SchedulingAwareRunnable, CommonSocketOptions {
38+
extends MessageProducerSupport
39+
implements ApplicationEventPublisherAware, SchedulingAwareRunnable, CommonSocketOptions {
3740

3841
private final int port;
3942

40-
private volatile int soTimeout = 0;
43+
private ApplicationEventPublisher applicationEventPublisher;
4144

42-
private volatile int soReceiveBufferSize = -1;
45+
private int soTimeout = 0;
4346

44-
private volatile int receiveBufferSize = 2048;
47+
private int soReceiveBufferSize = -1;
4548

46-
private volatile boolean active;
49+
private int receiveBufferSize = 2048;
4750

48-
private volatile boolean listening;
51+
private String localAddress;
4952

50-
private volatile String localAddress;
53+
private Executor taskExecutor;
5154

52-
private volatile Executor taskExecutor;
55+
private boolean taskExecutorSet;
5356

54-
private volatile boolean taskExecutorSet;
57+
private int poolSize = 5;
5558

56-
private volatile int poolSize = 5;
59+
private volatile boolean active;
60+
61+
private volatile boolean listening;
5762

5863

5964
public AbstractInternetProtocolReceivingChannelAdapter(int port) {
@@ -182,6 +187,15 @@ public Executor getTaskExecutor() {
182187
return this.taskExecutor;
183188
}
184189

190+
protected ApplicationEventPublisher getApplicationEventPublisher() {
191+
return this.applicationEventPublisher;
192+
}
193+
194+
@Override
195+
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
196+
this.applicationEventPublisher = applicationEventPublisher;
197+
}
198+
185199
/**
186200
* @return the active
187201
*/

spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionServerExceptionEvent.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,7 +31,6 @@ public class TcpConnectionServerExceptionEvent extends IpIntegrationEvent {
3131
public TcpConnectionServerExceptionEvent(Object connectionFactory, Throwable cause) {
3232
super(connectionFactory, cause);
3333
Assert.notNull(cause, "'cause' cannot be null");
34-
Assert.notNull(connectionFactory, "'connectionFactory' cannot be null");
3534
}
3635

3736
}

spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionServerListeningEvent.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2016 the original author or authors.
2+
* Copyright 2015-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
1717
package org.springframework.integration.ip.tcp.connection;
1818

1919
import org.springframework.integration.ip.event.IpIntegrationEvent;
20-
import org.springframework.util.Assert;
2120

2221
/**
2322
* {@link IpIntegrationEvent} emitted when a server begins listening. Useful
@@ -35,7 +34,6 @@ public class TcpConnectionServerListeningEvent extends IpIntegrationEvent {
3534

3635
public TcpConnectionServerListeningEvent(TcpServerConnectionFactory connectionFactory, int port) {
3736
super(connectionFactory);
38-
Assert.notNull(connectionFactory, "'connectionFactory' cannot be null");
3937
this.port = port;
4038
}
4139

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.ip.udp;
18+
19+
import org.springframework.integration.ip.event.IpIntegrationEvent;
20+
21+
/**
22+
* {@link IpIntegrationEvent} emitted when a server begins listening. Useful
23+
* when the configured port is zero and the operating system chooses the port.
24+
* Also useful to avoid polling the {@code isListening()} if you need to wait
25+
* before starting some other process to connect to the socket.
26+
*
27+
* @author Gary Russell
28+
* @since 5.0.2
29+
*/
30+
@SuppressWarnings("serial")
31+
public class UdpServerListeningEvent extends IpIntegrationEvent {
32+
33+
private final int port;
34+
35+
public UdpServerListeningEvent(UnicastReceivingChannelAdapter adapter, int port) {
36+
super(adapter);
37+
this.port = port;
38+
}
39+
40+
public int getPort() {
41+
return this.port;
42+
}
43+
44+
}

spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
import java.util.regex.Matcher;
2929
import java.util.regex.Pattern;
3030

31+
import org.springframework.context.ApplicationEventPublisher;
3132
import org.springframework.integration.ip.AbstractInternetProtocolReceivingChannelAdapter;
3233
import org.springframework.integration.ip.IpHeaders;
3334
import org.springframework.messaging.Message;
@@ -108,6 +109,11 @@ protected void onInit() {
108109
public void run() {
109110
getSocket();
110111

112+
ApplicationEventPublisher publisher = getApplicationEventPublisher();
113+
if (publisher != null) {
114+
publisher.publishEvent(new UdpServerListeningEvent(this, getPort()));
115+
}
116+
111117
if (logger.isDebugEnabled()) {
112118
logger.debug("UDP Receiver running on port:" + this.getPort());
113119
}

spring-integration-ip/src/test/java/org/springframework/integration/ip/dsl/IpIntegrationTests.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 the original author or authors.
2+
* Copyright 2016-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,13 +21,18 @@
2121
import static org.junit.Assert.assertEquals;
2222
import static org.junit.Assert.assertNotNull;
2323
import static org.junit.Assert.assertThat;
24+
import static org.junit.Assert.assertTrue;
25+
26+
import java.util.concurrent.CountDownLatch;
27+
import java.util.concurrent.TimeUnit;
2428

2529
import org.junit.Test;
2630
import org.junit.runner.RunWith;
2731

2832
import org.springframework.beans.factory.annotation.Autowired;
2933
import org.springframework.beans.factory.annotation.Qualifier;
3034
import org.springframework.context.ApplicationEventPublisher;
35+
import org.springframework.context.ApplicationListener;
3136
import org.springframework.context.annotation.Bean;
3237
import org.springframework.context.annotation.Configuration;
3338
import org.springframework.integration.channel.QueueChannel;
@@ -43,6 +48,7 @@
4348
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
4449
import org.springframework.integration.ip.tcp.serializer.TcpCodecs;
4550
import org.springframework.integration.ip.udp.MulticastSendingMessageHandler;
51+
import org.springframework.integration.ip.udp.UdpServerListeningEvent;
4652
import org.springframework.integration.ip.udp.UnicastReceivingChannelAdapter;
4753
import org.springframework.integration.ip.util.TestingUtilities;
4854
import org.springframework.integration.support.MessageBuilder;
@@ -77,6 +83,9 @@ public class IpIntegrationTests {
7783
@Autowired
7884
private QueueChannel udpIn;
7985

86+
@Autowired
87+
private Config config;
88+
8089
@Test
8190
public void testTcpAdapters() throws Exception {
8291
ApplicationEventPublisher publisher = e -> { };
@@ -119,8 +128,9 @@ public void testTcpGateways() {
119128
}
120129

121130
@Test
122-
public void testUdp() {
123-
TestingUtilities.waitListening(this.udpInbound, null);
131+
public void testUdp() throws Exception {
132+
assertTrue(this.config.listeningLatch.await(10, TimeUnit.SECONDS));
133+
assertEquals(this.udpInbound.getPort(), this.config.serverPort);
124134
Message<String> outMessage = MessageBuilder.withPayload("foo")
125135
.setHeader("udp_dest", "udp://localhost:" + this.udpInbound.getPort())
126136
.build();
@@ -148,6 +158,10 @@ public void testUdpInheritance() {
148158
@EnableIntegration
149159
public static class Config {
150160

161+
private final CountDownLatch listeningLatch = new CountDownLatch(1);
162+
163+
private volatile int serverPort;
164+
151165
@Bean
152166
public AbstractServerConnectionFactory server1() {
153167
return Tcp.netServer(0)
@@ -181,6 +195,14 @@ public IntegrationFlow outUdpAdapter() {
181195
return f -> f.handle(Udp.outboundAdapter(m -> m.getHeaders().get("udp_dest")));
182196
}
183197

198+
@Bean
199+
public ApplicationListener<UdpServerListeningEvent> events() {
200+
return (ApplicationListener<UdpServerListeningEvent>) event -> {
201+
this.serverPort = event.getPort();
202+
this.listeningLatch.countDown();
203+
};
204+
}
205+
184206
}
185207

186208
}

src/reference/asciidoc/ip.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ public IntegrationFlow udpIn() {
181181
}
182182
----
183183

184+
==== Server Listening Events
185+
186+
Starting with _version 5.0.2_, a `UdpServerListeningEvent` is emitted when an inbound adapter is started and has begun listening.
187+
This is useful when the adapter is configured to listen on port 0, meaning that the operating system chooses the port.
188+
It can also be used instead of polling `isListening()`, if you need to wait before starting some other process that will
189+
connect to the socket.
190+
184191
==== Advanced Outbound Configuration
185192

186193
The `destination-expression` and `socket-expression` options are available

0 commit comments

Comments
 (0)