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}