001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.messaging.rsocket;
018
019import java.util.List;
020import java.util.function.Consumer;
021
022import io.rsocket.Payload;
023
024import org.springframework.core.ReactiveAdapterRegistry;
025import org.springframework.core.ResolvableType;
026import org.springframework.core.codec.Decoder;
027import org.springframework.core.codec.Encoder;
028import org.springframework.core.io.buffer.DataBufferFactory;
029import org.springframework.core.io.buffer.DefaultDataBufferFactory;
030import org.springframework.core.io.buffer.NettyDataBufferFactory;
031import org.springframework.lang.Nullable;
032import org.springframework.util.AntPathMatcher;
033import org.springframework.util.MimeType;
034import org.springframework.util.RouteMatcher;
035import org.springframework.util.SimpleRouteMatcher;
036
037/**
038 * Access to strategies for use by RSocket requester and responder components.
039 *
040 * @author Rossen Stoyanchev
041 * @since 5.2
042 */
043public interface RSocketStrategies {
044
045        /**
046         * Return the configured {@link Builder#encoder(Encoder[]) encoders}.
047         * @see #encoder(ResolvableType, MimeType)
048         */
049        List<Encoder<?>> encoders();
050
051        /**
052         * Find a compatible Encoder for the given element type.
053         * @param elementType the element type to match
054         * @param mimeType the MimeType to match
055         * @param <T> for casting the Encoder to the expected element type
056         * @return the matching Encoder
057         * @throws IllegalArgumentException if no matching Encoder is found
058         */
059        @SuppressWarnings("unchecked")
060        default <T> Encoder<T> encoder(ResolvableType elementType, @Nullable MimeType mimeType) {
061                for (Encoder<?> encoder : encoders()) {
062                        if (encoder.canEncode(elementType, mimeType)) {
063                                return (Encoder<T>) encoder;
064                        }
065                }
066                throw new IllegalArgumentException("No encoder for " + elementType);
067        }
068
069        /**
070         * Return the configured {@link Builder#decoder(Decoder[]) decoders}.
071         * @see #decoder(ResolvableType, MimeType)
072         */
073        List<Decoder<?>> decoders();
074
075        /**
076         * Find a compatible Decoder for the given element type.
077         * @param elementType the element type to match
078         * @param mimeType the MimeType to match
079         * @param <T> for casting the Decoder to the expected element type
080         * @return the matching Decoder
081         * @throws IllegalArgumentException if no matching Decoder is found
082         */
083        @SuppressWarnings("unchecked")
084        default <T> Decoder<T> decoder(ResolvableType elementType, @Nullable MimeType mimeType) {
085                for (Decoder<?> decoder : decoders()) {
086                        if (decoder.canDecode(elementType, mimeType)) {
087                                return (Decoder<T>) decoder;
088                        }
089                }
090                throw new IllegalArgumentException("No decoder for " + elementType);
091        }
092
093        /**
094         * Return the configured {@link Builder#routeMatcher(RouteMatcher)}.
095         */
096        RouteMatcher routeMatcher();
097
098        /**
099         * Return the configured
100         * {@link Builder#reactiveAdapterStrategy(ReactiveAdapterRegistry) reactiveAdapterRegistry}.
101         */
102        ReactiveAdapterRegistry reactiveAdapterRegistry();
103
104        /**
105         * Return the configured
106         * {@link Builder#dataBufferFactory(DataBufferFactory) dataBufferFactory}.
107         */
108        DataBufferFactory dataBufferFactory();
109
110        /**
111         * Return the configured {@link Builder#metadataExtractor(MetadataExtractor)}.
112         */
113        MetadataExtractor metadataExtractor();
114
115        /**
116         * Return a builder to create a new {@link RSocketStrategies} instance
117         * replicated from the current instance.
118         */
119        default Builder mutate() {
120                return new DefaultRSocketStrategies.DefaultRSocketStrategiesBuilder(this);
121        }
122
123
124        /**
125         * Create an {@code RSocketStrategies} instance with default settings.
126         * Equivalent to {@code RSocketStrategies.builder().build()}. See individual
127         * builder methods for details on default settings.
128         */
129        static RSocketStrategies create() {
130                return new DefaultRSocketStrategies.DefaultRSocketStrategiesBuilder().build();
131        }
132
133        /**
134         * Return a builder to prepare a new {@code RSocketStrategies} instance.
135         * The builder applies default settings, see individual builder methods for
136         * details.
137         */
138        static Builder builder() {
139                return new DefaultRSocketStrategies.DefaultRSocketStrategiesBuilder();
140        }
141
142
143        /**
144         * The builder options for creating {@code RSocketStrategies}.
145         */
146        interface Builder {
147
148                /**
149                 * Append to the list of encoders to use for serializing Objects to the
150                 * data or metadata of a {@link Payload}.
151                 * <p>By default this is initialized with encoders for {@code String},
152                 * {@code byte[]}, {@code ByteBuffer}, and {@code DataBuffer}.
153                 */
154                Builder encoder(Encoder<?>... encoder);
155
156                /**
157                 * Apply the consumer to the list of configured encoders, immediately.
158                 */
159                Builder encoders(Consumer<List<Encoder<?>>> consumer);
160
161                /**
162                 * Append to the list of decoders to use for de-serializing Objects from
163                 * the data or metadata of a {@link Payload}.
164                 * <p>By default this is initialized with decoders for {@code String},
165                 * {@code byte[]}, {@code ByteBuffer}, and {@code DataBuffer}.
166                 */
167                Builder decoder(Decoder<?>... decoder);
168
169                /**
170                 * Apply the consumer to the list of configured decoders, immediately.
171                 */
172                Builder decoders(Consumer<List<Decoder<?>>> consumer);
173
174                /**
175                 * Configure a {@code RouteMatcher} for matching routes to message
176                 * handlers based on route patterns. This option is applicable to
177                 * client or server responders.
178                 * <p>By default, {@link SimpleRouteMatcher} is used, backed by
179                 * {@link AntPathMatcher} with "." as separator. For better
180                 * efficiency consider switching to {@code PathPatternRouteMatcher} from
181                 * {@code spring-web} instead.
182                 */
183                Builder routeMatcher(@Nullable RouteMatcher routeMatcher);
184
185                /**
186                 * Configure the registry for reactive type support. This can be used to
187                 * to adapt to, and/or determine the semantics of a given
188                 * {@link org.reactivestreams.Publisher Publisher}.
189                 * <p>By default this {@link ReactiveAdapterRegistry#getSharedInstance()}.
190                 */
191                Builder reactiveAdapterStrategy(@Nullable ReactiveAdapterRegistry registry);
192
193                /**
194                 * Configure the DataBufferFactory to use for allocating buffers when
195                 * preparing requests or creating responses.
196                 * <p>By default this is set to {@link NettyDataBufferFactory} with
197                 * pooled, allocated buffers for zero copy. RSocket must also be
198                 * <a href="https://github.com/rsocket/rsocket-java#zero-copy">configured</a>
199                 * for zero copy. For client setup, {@link RSocketRequester.Builder}
200                 * adapts automatically to the {@code DataBufferFactory} configured
201                 * here, and sets the frame decoder in
202                 * {@link io.rsocket.core.RSocketConnector RSocketConnector}
203                 * accordingly. For server setup, the
204                 * {@link io.rsocket.core.RSocketServer RSocketServer} must be configured
205                 * accordingly for zero copy too.
206                 * <p>If using {@link DefaultDataBufferFactory} instead, there is no
207                 * need for related config changes in RSocket.
208                 */
209                Builder dataBufferFactory(@Nullable DataBufferFactory bufferFactory);
210
211                /**
212                 * Configure a {@link MetadataExtractor} to extract the route along with
213                 * other metadata. This option is applicable to client or server
214                 * responders.
215                 * <p>By default this is {@link DefaultMetadataExtractor} created with
216                 * the {@link #decoder(Decoder[]) configured} decoders and extracting a
217                 * route from {@code "message/x.rsocket.routing.v0"} metadata.
218                 */
219                Builder metadataExtractor(@Nullable MetadataExtractor metadataExtractor);
220
221                /**
222                 * Apply the consumer to the {@link MetadataExtractorRegistry} in order
223                 * to register extra metadata entry extractors.
224                 */
225                Builder metadataExtractorRegistry(Consumer<MetadataExtractorRegistry> consumer);
226
227                /**
228                 * Build the {@code RSocketStrategies} instance.
229                 */
230                RSocketStrategies build();
231        }
232
233}