RSocketRequester support for route vars

Closes gh-23310
master
Rossen Stoyanchev 5 years ago
parent 358a6d6f10
commit 56c2987273
  1. 26
      spring-messaging/src/main/java/org/springframework/messaging/rsocket/DefaultRSocketRequester.java
  2. 8
      spring-messaging/src/main/java/org/springframework/messaging/rsocket/RSocketRequester.java
  3. 15
      spring-messaging/src/test/java/org/springframework/messaging/rsocket/DefaultRSocketRequesterTests.java

@ -19,6 +19,8 @@ package org.springframework.messaging.rsocket;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
@ -44,6 +46,7 @@ import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.util.ObjectUtils;
/**
* Default, package-private {@link RSocketRequester} implementation.
@ -58,6 +61,9 @@ final class DefaultRSocketRequester implements RSocketRequester {
static final MimeType ROUTING = new MimeType("message", "x.rsocket.routing.v0");
/** For route variable replacement. */
private static final Pattern VARS_PATTERN = Pattern.compile("\\{([^/]+?)\\}");
private static final Map<String, Object> EMPTY_HINTS = Collections.emptyMap();
@ -105,11 +111,29 @@ final class DefaultRSocketRequester implements RSocketRequester {
}
@Override
public RequestSpec route(String route) {
public RequestSpec route(String route, Object... vars) {
Assert.notNull(route, "'route' is required");
route = expand(route, vars);
return new DefaultRequestSpec(route, metadataMimeType().equals(COMPOSITE_METADATA) ? ROUTING : null);
}
private static String expand(String route, Object... vars) {
if (ObjectUtils.isEmpty(vars)) {
return route;
}
StringBuffer sb = new StringBuffer();
int index = 0;
Matcher matcher = VARS_PATTERN.matcher(route);
while (matcher.find()) {
Assert.isTrue(index < vars.length, () -> "No value for variable '" + matcher.group(1) + "'");
String value = vars[index].toString();
value = value.contains(".") ? value.replaceAll("\\.", "%2E") : value;
matcher.appendReplacement(sb, value);
index++;
}
return sb.toString();
}
@Override
public RequestSpec metadata(Object metadata, @Nullable MimeType mimeType) {
return new DefaultRequestSpec(metadata, mimeType);

@ -66,13 +66,19 @@ public interface RSocketRequester {
/**
* Begin to specify a new request with the given route to a remote handler.
* <p>The route can be a template with placeholders, e.g.
* {@code "flight.{code}"} in which case the supplied route variables are
* expanded into the template after being formatted via {@code toString()}.
* If a formatted variable contains a "." it is replaced with the escape
* sequence "%2E" to avoid treating it as separator by the responder .
* <p>If the connection is set to use composite metadata, the route is
* encoded as {@code "message/x.rsocket.routing.v0"}. Otherwise the route
* is encoded according to the mime type for the connection.
* @param route the route to a handler
* @param routeVars variables to be expanded into the route template
* @return a spec for further defining and executing the request
*/
RequestSpec route(String route);
RequestSpec route(String route, Object... routeVars);
/**
* Begin to specify a new request with the given metadata.

@ -211,13 +211,16 @@ public class DefaultRSocketRequesterTests {
}
@Test
public void supportedMetadataMimeTypes() {
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN,
COMPOSITE_METADATA, this.strategies);
public void routeWithVars() {
RSocketRequester requester = RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, TEXT_PLAIN, this.strategies);
requester.route("a.{b}.{c}", "BBB", "C.C.C").data("body").send().block();
assertThat(this.rsocket.getSavedPayload().getMetadataUtf8()).isEqualTo("a.BBB.C%2EC%2EC");
}
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN,
ROUTING, this.strategies);
@Test
public void supportedMetadataMimeTypes() {
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, COMPOSITE_METADATA, this.strategies);
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, ROUTING, this.strategies);
}
@Test

Loading…
Cancel
Save