Skip to content

Commit

Permalink
Add responder strategies to RSocketStrategies
Browse files Browse the repository at this point in the history
RouteMatcher and MetadataExtractor can now be configured on and
accessed through RSocketStrategies. This simplifies configuration for
client and server responders.

See gh-23314
  • Loading branch information
rstoyanchev committed Jul 24, 2019
1 parent a780cad commit 91b040d
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public class MessageMappingMessageHandler extends AbstractMethodMessageHandler<C
@Nullable
private Validator validator;

@Nullable
private RouteMatcher routeMatcher;

private ConversionService conversionService = new DefaultFormattingConversionService();
Expand All @@ -97,9 +98,6 @@ public class MessageMappingMessageHandler extends AbstractMethodMessageHandler<C


public MessageMappingMessageHandler() {
AntPathMatcher pathMatcher = new AntPathMatcher();
pathMatcher.setPathSeparator(".");
this.routeMatcher = new SimpleRouteMatcher(pathMatcher);
setHandlerPredicate(type -> AnnotatedElementUtils.hasAnnotation(type, Controller.class));
}

Expand Down Expand Up @@ -150,7 +148,9 @@ public void setRouteMatcher(RouteMatcher routeMatcher) {

/**
* Return the {@code RouteMatcher} used to map messages to handlers.
* May be {@code null} before component is initialized.
*/
@Nullable
public RouteMatcher getRouteMatcher() {
return this.routeMatcher;
}
Expand Down Expand Up @@ -203,6 +203,12 @@ protected List<? extends HandlerMethodArgumentResolver> initArgumentResolvers()
resolvers.add(new PayloadMethodArgumentResolver(
getDecoders(), this.validator, getReactiveAdapterRegistry(), true));

if (this.routeMatcher == null) {
AntPathMatcher pathMatcher = new AntPathMatcher();
pathMatcher.setPathSeparator(".");
this.routeMatcher = new SimpleRouteMatcher(pathMatcher);
}

return resolvers;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.RouteMatcher;
import org.springframework.util.SimpleRouteMatcher;

/**
* Default, package-private {@link RSocketStrategies} implementation.
Expand All @@ -52,18 +56,25 @@ final class DefaultRSocketStrategies implements RSocketStrategies {

private final List<Decoder<?>> decoders;

private final ReactiveAdapterRegistry adapterRegistry;
private final RouteMatcher routeMatcher;

private final MetadataExtractor metadataExtractor;

private final DataBufferFactory bufferFactory;

private final ReactiveAdapterRegistry adapterRegistry;


private DefaultRSocketStrategies(List<Encoder<?>> encoders, List<Decoder<?>> decoders,
ReactiveAdapterRegistry adapterRegistry, DataBufferFactory bufferFactory) {
RouteMatcher routeMatcher, MetadataExtractor metadataExtractor,
DataBufferFactory bufferFactory, ReactiveAdapterRegistry adapterRegistry) {

this.encoders = Collections.unmodifiableList(encoders);
this.decoders = Collections.unmodifiableList(decoders);
this.adapterRegistry = adapterRegistry;
this.routeMatcher = routeMatcher;
this.metadataExtractor = metadataExtractor;
this.bufferFactory = bufferFactory;
this.adapterRegistry = adapterRegistry;
}


Expand All @@ -78,15 +89,25 @@ public List<Decoder<?>> decoders() {
}

@Override
public ReactiveAdapterRegistry reactiveAdapterRegistry() {
return this.adapterRegistry;
public RouteMatcher routeMatcher() {
return this.routeMatcher;
}

@Override
public MetadataExtractor metadataExtractor() {
return this.metadataExtractor;
}

@Override
public DataBufferFactory dataBufferFactory() {
return this.bufferFactory;
}

@Override
public ReactiveAdapterRegistry reactiveAdapterRegistry() {
return this.adapterRegistry;
}


/**
* Default RSocketStrategies.Builder implementation.
Expand All @@ -97,6 +118,12 @@ static class DefaultRSocketStrategiesBuilder implements RSocketStrategies.Builde

private final List<Decoder<?>> decoders = new ArrayList<>();

@Nullable
private RouteMatcher routeMatcher;

@Nullable
private MetadataExtractor metadataExtractor;

private ReactiveAdapterRegistry adapterRegistry = ReactiveAdapterRegistry.getSharedInstance();

@Nullable
Expand Down Expand Up @@ -151,6 +178,18 @@ public Builder decoders(Consumer<List<Decoder<?>>> consumer) {
return this;
}

@Override
public Builder routeMatcher(RouteMatcher routeMatcher) {
this.routeMatcher = routeMatcher;
return this;
}

@Override
public Builder metadataExtractor(MetadataExtractor metadataExtractor) {
this.metadataExtractor = metadataExtractor;
return this;
}

@Override
public Builder reactiveAdapterStrategy(ReactiveAdapterRegistry registry) {
Assert.notNull(registry, "ReactiveAdapterRegistry is required");
Expand All @@ -167,12 +206,27 @@ public Builder dataBufferFactory(DataBufferFactory bufferFactory) {
@Override
public RSocketStrategies build() {
return new DefaultRSocketStrategies(
this.encoders, this.decoders, this.adapterRegistry, initBufferFactory());
this.encoders, this.decoders,
this.routeMatcher != null ? this.routeMatcher : initRouteMatcher(),
this.metadataExtractor != null ? this.metadataExtractor : initMetadataExtractor(),
this.bufferFactory != null ? this.bufferFactory : initBufferFactory(),
this.adapterRegistry);
}

private RouteMatcher initRouteMatcher() {
AntPathMatcher pathMatcher = new AntPathMatcher();
pathMatcher.setPathSeparator(".");
return new SimpleRouteMatcher(pathMatcher);
}

private MetadataExtractor initMetadataExtractor() {
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
extractor.metadataToExtract(MimeTypeUtils.TEXT_PLAIN, String.class, MetadataExtractor.ROUTE_KEY);
return extractor;
}

private DataBufferFactory initBufferFactory() {
return this.bufferFactory != null ? this.bufferFactory :
new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT);
return new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MimeType;
import org.springframework.util.RouteMatcher;
import org.springframework.util.SimpleRouteMatcher;

/**
* Access to strategies for use by RSocket requester and responder components.
Expand Down Expand Up @@ -90,17 +93,27 @@ default <T> Decoder<T> decoder(ResolvableType elementType, @Nullable MimeType mi
}

/**
* Return the configured
* {@link Builder#reactiveAdapterStrategy(ReactiveAdapterRegistry) reactiveAdapterRegistry}.
* Return the configured {@link Builder#routeMatcher(RouteMatcher)}.
*/
ReactiveAdapterRegistry reactiveAdapterRegistry();
RouteMatcher routeMatcher();

/**
* Return the configured {@link Builder#metadataExtractor(MetadataExtractor)}.
*/
MetadataExtractor metadataExtractor();

/**
* Return the configured
* {@link Builder#dataBufferFactory(DataBufferFactory) dataBufferFactory}.
*/
DataBufferFactory dataBufferFactory();

/**
* Return the configured
* {@link Builder#reactiveAdapterStrategy(ReactiveAdapterRegistry) reactiveAdapterRegistry}.
*/
ReactiveAdapterRegistry reactiveAdapterRegistry();


/**
* Return a builder to build a new {@code RSocketStrategies} instance.
Expand Down Expand Up @@ -149,6 +162,27 @@ interface Builder {
*/
Builder decoders(Consumer<List<Decoder<?>>> consumer);

/**
* Configure a {@code RouteMatcher} for matching routes to message
* handlers based on route patterns. This option is applicable to
* client or server responders.
* <p>By default, {@link SimpleRouteMatcher} is used, backed by
* {@link AntPathMatcher} with "." as separator. For better
* efficiency consider using the {@code PathPatternRouteMatcher} from
* {@code spring-web} instead.
*/
Builder routeMatcher(RouteMatcher routeMatcher);

/**
* Configure a {@link MetadataExtractor} to extract the route along with
* other metadata. This option is applicable to client or server
* responders.
* <p>By default this is {@link DefaultMetadataExtractor} extracting a
* route from {@code "message/x.rsocket.routing.v0"} or
* {@code "text/plain"} metadata entries.
*/
Builder metadataExtractor(MetadataExtractor metadataExtractor);

/**
* Configure the registry for reactive type support. This can be used to
* to adapt to, and/or determine the semantics of a given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@
import org.springframework.beans.BeanUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.rsocket.ClientRSocketFactoryConfigurer;
import org.springframework.messaging.rsocket.MetadataExtractor;
import org.springframework.messaging.rsocket.RSocketStrategies;
import org.springframework.util.Assert;
import org.springframework.util.RouteMatcher;

/**
* {@link ClientRSocketFactoryConfigurer} to configure and plug in a responder
Expand All @@ -44,12 +42,6 @@ public final class AnnotationClientResponderConfigurer implements ClientRSocketF

private final List<Object> handlers = new ArrayList<>();

@Nullable
private RouteMatcher routeMatcher;

@Nullable
private MetadataExtractor extractor;

@Nullable
private RSocketStrategies strategies;

Expand All @@ -61,24 +53,6 @@ private AnnotationClientResponderConfigurer(List<Object> handlers) {
}


/**
* Configure the {@link RouteMatcher} to use. This is used to set
* {@link RSocketMessageHandler#setRouteMatcher(RouteMatcher)}.
*/
public AnnotationClientResponderConfigurer routeMatcher(RouteMatcher routeMatcher) {
this.routeMatcher = routeMatcher;
return this;
}

/**
* Configure the {@link MetadataExtractor} to use. This is used to set
* {@link RSocketMessageHandler#setMetadataExtractor(MetadataExtractor)}.
*/
public AnnotationClientResponderConfigurer metadataExtractor(MetadataExtractor extractor) {
this.extractor = extractor;
return this;
}

/**
* Configure handlers to detect {@code @MessasgeMapping} handler methods on.
* This is used to set {@link RSocketMessageHandler#setHandlers(List)}.
Expand All @@ -101,12 +75,6 @@ public void configure(RSocketFactory.ClientRSocketFactory factory) {
Assert.notEmpty(this.handlers, "No handlers");
RSocketMessageHandler messageHandler = new RSocketMessageHandler();
messageHandler.setHandlers(this.handlers);
if (this.routeMatcher != null) {
messageHandler.setRouteMatcher(this.routeMatcher);
}
if (this.extractor != null) {
messageHandler.setMetadataExtractor(this.extractor);
}
messageHandler.setRSocketStrategies(this.strategies);
messageHandler.afterPropertiesSet();
factory.acceptor(messageHandler.clientResponder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,16 @@ public List<? extends Encoder<?>> getEncoders() {
/**
* Provide configuration in the form of {@link RSocketStrategies} instance
* which can also be re-used to initialize a client-side
* {@link RSocketRequester}. When this property is set, it also sets
* {@link #setDecoders(List) decoders}, {@link #setEncoders(List) encoders},
* and {@link #setReactiveAdapterRegistry(ReactiveAdapterRegistry)
* reactiveAdapterRegistry}.
* {@link RSocketRequester}.
* <p>When this is set, in turn it sets the following:
* <ul>
* <li>{@link #setDecoders(List)}
* <li>{@link #setEncoders(List)}
* <li>{@link #setRouteMatcher(RouteMatcher)}
* <li>{@link #setMetadataExtractor(MetadataExtractor)}
* <li>{@link #setReactiveAdapterRegistry(ReactiveAdapterRegistry)}
* </ul>
* <p>By default if this is not set, it is initialized from the above.
*/
public void setRSocketStrategies(@Nullable RSocketStrategies rsocketStrategies) {
this.rsocketStrategies = rsocketStrategies;
Expand All @@ -138,12 +144,10 @@ public RSocketStrategies getRSocketStrategies() {
}

/**
* Configure a {@link MetadataExtractor} to extract the route and possibly
* other metadata from the first payload of incoming requests.
* <p>By default this is a {@link DefaultMetadataExtractor} with the
* configured {@link RSocketStrategies} (and decoders), extracting a route
* from {@code "message/x.rsocket.routing.v0"} or {@code "text/plain"}
* metadata entries.
* Configure a {@link MetadataExtractor} to extract the route along with
* other metadata.
* <p>By default this is {@link DefaultMetadataExtractor} extracting a
* route from {@code "message/x.rsocket.routing.v0"} or {@code "text/plain"}.
* @param extractor the extractor to use
*/
public void setMetadataExtractor(MetadataExtractor extractor) {
Expand Down Expand Up @@ -200,20 +204,25 @@ public MimeType getDefaultMetadataMimeType() {

@Override
public void afterPropertiesSet() {

getArgumentResolverConfigurer().addCustomResolver(new RSocketRequesterMethodArgumentResolver());
super.afterPropertiesSet();

if (getMetadataExtractor() == null) {
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
extractor.metadataToExtract(MimeTypeUtils.TEXT_PLAIN, String.class, MetadataExtractor.ROUTE_KEY);
setMetadataExtractor(extractor);
}

if (this.rsocketStrategies == null) {
this.rsocketStrategies = RSocketStrategies.builder()
.decoder(getDecoders().toArray(new Decoder<?>[0]))
.encoder(getEncoders().toArray(new Encoder<?>[0]))
.routeMatcher(getRouteMatcher())
.metadataExtractor(getMetadataExtractor())
.reactiveAdapterStrategy(getReactiveAdapterRegistry())
.build();
}
if (this.metadataExtractor == null) {
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
extractor.metadataToExtract(MimeTypeUtils.TEXT_PLAIN, String.class, MetadataExtractor.ROUTE_KEY);
this.metadataExtractor = extractor;
}
getArgumentResolverConfigurer().addCustomResolver(new RSocketRequesterMethodArgumentResolver());
super.afterPropertiesSet();
}

@Override
Expand Down

0 comments on commit 91b040d

Please sign in to comment.