Skip to content

Commit f6b879d

Browse files
committed
Add client responder configuration
Prior to this commit, the `RSocketRequester.Builder` would allow to configure directly annotated handlers for processing server requests. This lead to a package tangle where the `o.s.messaging.rsocket` would use classes from `o.s.messaging.rsocket.annotation.support` package. This commit introduces the `ClientResponder` interface for configuring a responder on the client requester. This is compatible with future changes with a parallel implementation of a functional variant for RSocket handlers. Closes spring-projectsgh-23170
1 parent 507d128 commit f6b879d

File tree

6 files changed

+146
-22
lines changed

6 files changed

+146
-22
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2002-2019 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+
* https://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.messaging.rsocket;
18+
19+
import java.util.function.BiFunction;
20+
21+
import io.rsocket.ConnectionSetupPayload;
22+
import io.rsocket.RSocket;
23+
24+
import org.springframework.util.RouteMatcher;
25+
26+
/**
27+
* Handle requests sent by the RSocket server to the client.
28+
* @author Brian Clozel
29+
* @since 5.2
30+
*/
31+
public interface ClientResponder {
32+
33+
/**
34+
* Create a client Socket acceptor for handling server requests.
35+
* @param matcher the route matcher for routing incoming requests
36+
* @param strategies the codecs strategies for (de)serializing messages
37+
* @return a client Socket acceptor
38+
*/
39+
BiFunction<ConnectionSetupPayload, RSocket, RSocket> toSocketAcceptor(
40+
RouteMatcher matcher, RSocketStrategies strategies);
41+
42+
}

spring-messaging/src/main/java/org/springframework/messaging/rsocket/DefaultRSocketRequesterBuilder.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.net.URI;
2020
import java.util.ArrayList;
21-
import java.util.Arrays;
2221
import java.util.List;
2322
import java.util.function.Consumer;
2423
import java.util.stream.Stream;
@@ -31,9 +30,11 @@
3130
import reactor.core.publisher.Mono;
3231

3332
import org.springframework.lang.Nullable;
34-
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
33+
import org.springframework.util.AntPathMatcher;
3534
import org.springframework.util.Assert;
3635
import org.springframework.util.MimeType;
36+
import org.springframework.util.RouteMatcher;
37+
import org.springframework.util.SimpleRouteMatcher;
3738

3839
/**
3940
* Default implementation of {@link RSocketRequester.Builder}.
@@ -54,9 +55,13 @@ final class DefaultRSocketRequesterBuilder implements RSocketRequester.Builder {
5455
@Nullable
5556
private RSocketStrategies strategies;
5657

58+
@Nullable
59+
private RouteMatcher routeMatcher;
60+
5761
private List<Consumer<RSocketStrategies.Builder>> strategiesConfigurers = new ArrayList<>();
5862

59-
private List<Object> handlers = new ArrayList<>();
63+
@Nullable
64+
private ClientResponder clientResponder;
6065

6166
@Override
6267
public RSocketRequester.Builder dataMimeType(@Nullable MimeType mimeType) {
@@ -84,8 +89,14 @@ public RSocketRequester.Builder rsocketStrategies(@Nullable RSocketStrategies st
8489
}
8590

8691
@Override
87-
public RSocketRequester.Builder annotatedHandlers(Object... handlers) {
88-
this.handlers.addAll(Arrays.asList(handlers));
92+
public RSocketRequester.Builder routeMatcher(@Nullable RouteMatcher routeMatcher) {
93+
this.routeMatcher = routeMatcher;
94+
return this;
95+
}
96+
97+
@Override
98+
public RSocketRequester.Builder responder(@Nullable ClientResponder responder) {
99+
this.clientResponder = responder;
89100
return this;
90101
}
91102

@@ -120,12 +131,8 @@ private Mono<RSocketRequester> doConnect(ClientTransport transport) {
120131
rsocketFactory.dataMimeType(dataMimeType.toString());
121132
rsocketFactory.metadataMimeType(this.metadataMimeType.toString());
122133

123-
if (!this.handlers.isEmpty()) {
124-
RSocketMessageHandler messageHandler = new RSocketMessageHandler();
125-
messageHandler.setHandlers(this.handlers);
126-
messageHandler.setRSocketStrategies(rsocketStrategies);
127-
messageHandler.afterPropertiesSet();
128-
rsocketFactory.acceptor(messageHandler.clientAcceptor());
134+
if (this.clientResponder != null) {
135+
rsocketFactory.acceptor(this.clientResponder.toSocketAcceptor(getRouteMatcher(), rsocketStrategies));
129136
}
130137
rsocketFactory.frameDecoder(PayloadDecoder.ZERO_COPY);
131138
this.factoryConfigurers.forEach(consumer -> consumer.accept(rsocketFactory));
@@ -148,6 +155,10 @@ private RSocketStrategies getRSocketStrategies() {
148155
}
149156
}
150157

158+
private RouteMatcher getRouteMatcher() {
159+
return this.routeMatcher != null ? this.routeMatcher : new SimpleRouteMatcher(new AntPathMatcher("."));
160+
}
161+
151162
private MimeType getDataMimeType(RSocketStrategies strategies) {
152163
if (this.dataMimeType != null) {
153164
return this.dataMimeType;

spring-messaging/src/main/java/org/springframework/messaging/rsocket/RSocketRequester.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
import org.springframework.core.ParameterizedTypeReference;
3131
import org.springframework.core.ReactiveAdapterRegistry;
3232
import org.springframework.lang.Nullable;
33-
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
3433
import org.springframework.util.MimeType;
34+
import org.springframework.util.RouteMatcher;
3535

3636
/**
3737
* A thin wrapper around a sending {@link RSocket} with a fluent API accepting
@@ -65,7 +65,6 @@ public interface RSocketRequester {
6565
*/
6666
MimeType metadataMimeType();
6767

68-
6968
/**
7069
* Begin to specify a new request with the given route to a remote handler.
7170
* <p>If the connection is set to use composite metadata, the route is
@@ -158,9 +157,19 @@ interface Builder {
158157
/**
159158
* Set the {@link RSocketStrategies} to use for access to encoders,
160159
* decoders, and a factory for {@code DataBuffer's}.
160+
* @param strategies the codecs strategies to use
161161
*/
162162
RSocketRequester.Builder rsocketStrategies(@Nullable RSocketStrategies strategies);
163163

164+
/**
165+
* Set the {@link RouteMatcher} to use for matching incoming requests.
166+
* <p>If none is set, then the responder will use a default
167+
* {@link org.springframework.util.SimpleRouteMatcher} instance backed
168+
* by and {@link org.springframework.util.AntPathMatcher}.
169+
* @param routeMatcher the route matcher to use with the responder
170+
*/
171+
RSocketRequester.Builder routeMatcher(@Nullable RouteMatcher routeMatcher);
172+
164173
/**
165174
* Customize the {@link RSocketStrategies}.
166175
* <p>By default this starts out with an empty builder, i.e.
@@ -171,15 +180,13 @@ interface Builder {
171180
RSocketRequester.Builder rsocketStrategies(Consumer<RSocketStrategies.Builder> configurer);
172181

173182
/**
174-
* Add handlers for processing requests sent by the server.
175-
* <p>This is a shortcut for registering client handlers (i.e. annotated controllers)
176-
* to a {@link RSocketMessageHandler} and configuring it as an acceptor.
177-
* You can take full control by manually registering an acceptor on the
178-
* {@link io.rsocket.RSocketFactory.ClientRSocketFactory} using
179-
* {@link #rsocketFactory(Consumer)} instead.
180-
* @param handlers the client handlers to configure on the requester
183+
* Configure a client responder for processing requests sent by the server.
184+
* <p>This is a shortcut for registering an acceptor on the
185+
* {@link io.rsocket.RSocketFactory.ClientRSocketFactory}
186+
* using {@link #rsocketFactory(Consumer)} instead.
187+
* @param responder the responder to use for processing requests sent by the server
181188
*/
182-
RSocketRequester.Builder annotatedHandlers(Object... handlers);
189+
RSocketRequester.Builder responder(ClientResponder responder);
183190

184191
/**
185192
* Connect to the RSocket server over TCP.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2002-2019 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+
* https://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.messaging.rsocket.annotation.support;
18+
19+
import java.util.Arrays;
20+
import java.util.List;
21+
import java.util.function.BiFunction;
22+
23+
import io.rsocket.ConnectionSetupPayload;
24+
import io.rsocket.RSocket;
25+
26+
import org.springframework.messaging.rsocket.ClientResponder;
27+
import org.springframework.messaging.rsocket.RSocketStrategies;
28+
import org.springframework.util.Assert;
29+
import org.springframework.util.RouteMatcher;
30+
31+
/**
32+
* Default implementation of {@link ClientResponder} for annotated handlers.
33+
* @author Brian Clozel
34+
*/
35+
class DefaultClientResponder implements ClientResponder {
36+
37+
private final List<Object> handlers;
38+
39+
DefaultClientResponder(Object... handlers) {
40+
Assert.notEmpty(handlers, "handlers should not be empty");
41+
this.handlers = Arrays.asList(handlers);
42+
}
43+
44+
@Override
45+
public BiFunction<ConnectionSetupPayload, RSocket, RSocket> toSocketAcceptor(RouteMatcher routeMatcher, RSocketStrategies strategies) {
46+
RSocketMessageHandler messageHandler = new RSocketMessageHandler();
47+
messageHandler.setHandlers(this.handlers);
48+
messageHandler.setRSocketStrategies(strategies);
49+
messageHandler.setRouteMatcher(routeMatcher);
50+
messageHandler.afterPropertiesSet();
51+
return messageHandler.clientAcceptor();
52+
}
53+
54+
}

spring-messaging/src/main/java/org/springframework/messaging/rsocket/annotation/support/RSocketMessageHandler.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.messaging.MessageDeliveryException;
3535
import org.springframework.messaging.handler.annotation.reactive.MessageMappingMessageHandler;
3636
import org.springframework.messaging.handler.invocation.reactive.HandlerMethodReturnValueHandler;
37+
import org.springframework.messaging.rsocket.ClientResponder;
3738
import org.springframework.messaging.rsocket.RSocketRequester;
3839
import org.springframework.messaging.rsocket.RSocketStrategies;
3940
import org.springframework.util.Assert;
@@ -52,6 +53,7 @@
5253
* side adapters.
5354
*
5455
* @author Rossen Stoyanchev
56+
* @author Brian Clozel
5557
* @since 5.2
5658
*/
5759
public class RSocketMessageHandler extends MessageMappingMessageHandler {
@@ -232,6 +234,14 @@ public BiFunction<ConnectionSetupPayload, RSocket, RSocket> clientAcceptor() {
232234
return this::createRSocket;
233235
}
234236

237+
/**
238+
* Configure a {@link ClientResponder} for handling requests sent by the server.
239+
* @param handlers the annotated handlers to configure
240+
*/
241+
public static ClientResponder clientResponder(Object... handlers) {
242+
return new DefaultClientResponder(handlers);
243+
}
244+
235245
private MessagingRSocket createRSocket(ConnectionSetupPayload setupPayload, RSocket rsocket) {
236246
String s = setupPayload.dataMimeType();
237247
MimeType dataMimeType = StringUtils.hasText(s) ? MimeTypeUtils.parseMimeType(s) : this.defaultDataMimeType;

spring-messaging/src/test/java/org/springframework/messaging/rsocket/RSocketServerToClientIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private static void connectAndVerify(String destination) {
104104
RSocketRequester requester = null;
105105
try {
106106
requester = RSocketRequester.builder()
107-
.annotatedHandlers(new ClientHandler())
107+
.responder(RSocketMessageHandler.clientResponder(new ClientHandler()))
108108
.rsocketStrategies(context.getBean(RSocketStrategies.class))
109109
.connectTcp("localhost", server.address().getPort())
110110
.block();

0 commit comments

Comments
 (0)