1717package org .springframework .boot .autoconfigure .elasticsearch ;
1818
1919import java .net .URI ;
20- import java .net .URISyntaxException ;
2120import java .time .Duration ;
21+ import java .util .List ;
22+ import java .util .stream .Stream ;
2223
2324import org .apache .http .HttpHost ;
2425import org .apache .http .auth .AuthScope ;
3738import org .springframework .boot .autoconfigure .condition .ConditionalOnClass ;
3839import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
3940import org .springframework .boot .autoconfigure .condition .ConditionalOnSingleCandidate ;
41+ import org .springframework .boot .autoconfigure .elasticsearch .ElasticsearchConnectionDetails .Node ;
42+ import org .springframework .boot .autoconfigure .elasticsearch .ElasticsearchConnectionDetails .Node .Protocol ;
4043import org .springframework .boot .context .properties .PropertyMapper ;
4144import org .springframework .context .annotation .Bean ;
4245import org .springframework .context .annotation .Configuration ;
4750 *
4851 * @author Stephane Nicoll
4952 * @author Filip Hrisafov
53+ * @author Moritz Halbritter
54+ * @author Andy Wilkinson
55+ * @author Phillip Webb
5056 */
5157class ElasticsearchRestClientConfigurations {
5258
@@ -56,20 +62,27 @@ static class RestClientBuilderConfiguration {
5662
5763 private final ElasticsearchProperties properties ;
5864
59- RestClientBuilderConfiguration (ElasticsearchProperties properties ) {
65+ private final ElasticsearchConnectionDetails connectionDetails ;
66+
67+ RestClientBuilderConfiguration (ElasticsearchProperties properties ,
68+ ObjectProvider <ElasticsearchConnectionDetails > connectionDetails ) {
6069 this .properties = properties ;
70+ this .connectionDetails = connectionDetails
71+ .getIfAvailable (() -> new PropertiesElasticsearchConnectionDetails (properties ));
6172 }
6273
6374 @ Bean
6475 RestClientBuilderCustomizer defaultRestClientBuilderCustomizer () {
65- return new DefaultRestClientBuilderCustomizer (this .properties );
76+ return new DefaultRestClientBuilderCustomizer (this .properties , this . connectionDetails );
6677 }
6778
6879 @ Bean
6980 RestClientBuilder elasticsearchRestClientBuilder (
7081 ObjectProvider <RestClientBuilderCustomizer > builderCustomizers ) {
71- HttpHost [] hosts = this .properties .getUris ().stream ().map (this ::createHttpHost ).toArray (HttpHost []::new );
72- RestClientBuilder builder = RestClient .builder (hosts );
82+ RestClientBuilder builder = RestClient .builder (this .connectionDetails .getNodes ()
83+ .stream ()
84+ .map ((node ) -> new HttpHost (node .hostname (), node .port (), node .protocol ().getScheme ()))
85+ .toArray (HttpHost []::new ));
7386 builder .setHttpClientConfigCallback ((httpClientBuilder ) -> {
7487 builderCustomizers .orderedStream ().forEach ((customizer ) -> customizer .customize (httpClientBuilder ));
7588 return httpClientBuilder ;
@@ -78,36 +91,14 @@ RestClientBuilder elasticsearchRestClientBuilder(
7891 builderCustomizers .orderedStream ().forEach ((customizer ) -> customizer .customize (requestConfigBuilder ));
7992 return requestConfigBuilder ;
8093 });
81- if (this .properties .getPathPrefix () != null ) {
82- builder .setPathPrefix (this .properties .getPathPrefix ());
94+ String pathPrefix = this .connectionDetails .getPathPrefix ();
95+ if (pathPrefix != null ) {
96+ builder .setPathPrefix (pathPrefix );
8397 }
8498 builderCustomizers .orderedStream ().forEach ((customizer ) -> customizer .customize (builder ));
8599 return builder ;
86100 }
87101
88- private HttpHost createHttpHost (String uri ) {
89- try {
90- return createHttpHost (URI .create (uri ));
91- }
92- catch (IllegalArgumentException ex ) {
93- return HttpHost .create (uri );
94- }
95- }
96-
97- private HttpHost createHttpHost (URI uri ) {
98- if (!StringUtils .hasLength (uri .getUserInfo ())) {
99- return HttpHost .create (uri .toString ());
100- }
101- try {
102- return HttpHost .create (new URI (uri .getScheme (), null , uri .getHost (), uri .getPort (), uri .getPath (),
103- uri .getQuery (), uri .getFragment ())
104- .toString ());
105- }
106- catch (URISyntaxException ex ) {
107- throw new IllegalStateException (ex );
108- }
109- }
110-
111102 }
112103
113104 @ Configuration (proxyBeanMethods = false )
@@ -146,8 +137,12 @@ static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCust
146137
147138 private final ElasticsearchProperties properties ;
148139
149- DefaultRestClientBuilderCustomizer (ElasticsearchProperties properties ) {
140+ private final ElasticsearchConnectionDetails connectionDetails ;
141+
142+ DefaultRestClientBuilderCustomizer (ElasticsearchProperties properties ,
143+ ElasticsearchConnectionDetails connectionDetails ) {
150144 this .properties = properties ;
145+ this .connectionDetails = connectionDetails ;
151146 }
152147
153148 @ Override
@@ -156,7 +151,7 @@ public void customize(RestClientBuilder builder) {
156151
157152 @ Override
158153 public void customize (HttpAsyncClientBuilder builder ) {
159- builder .setDefaultCredentialsProvider (new PropertiesCredentialsProvider (this .properties ));
154+ builder .setDefaultCredentialsProvider (new ConnectionDetailsCredentialsProvider (this .connectionDetails ));
160155 map .from (this .properties ::isSocketKeepAlive )
161156 .to ((keepAlive ) -> builder
162157 .setDefaultIOReactorConfig (IOReactorConfig .custom ().setSoKeepAlive (keepAlive ).build ()));
@@ -176,28 +171,20 @@ public void customize(RequestConfig.Builder builder) {
176171
177172 }
178173
179- private static class PropertiesCredentialsProvider extends BasicCredentialsProvider {
174+ private static class ConnectionDetailsCredentialsProvider extends BasicCredentialsProvider {
180175
181- PropertiesCredentialsProvider ( ElasticsearchProperties properties ) {
182- if ( StringUtils . hasText ( properties . getUsername ())) {
183- Credentials credentials = new UsernamePasswordCredentials ( properties . getUsername (),
184- properties .getPassword ());
176+ ConnectionDetailsCredentialsProvider ( ElasticsearchConnectionDetails connectionDetails ) {
177+ String username = connectionDetails . getUsername ();
178+ if ( StringUtils . hasText ( username )) {
179+ Credentials credentials = new UsernamePasswordCredentials ( username , connectionDetails .getPassword ());
185180 setCredentials (AuthScope .ANY , credentials );
186181 }
187- properties .getUris ()
188- .stream ()
189- .map (this ::toUri )
190- .filter (this ::hasUserInfo )
191- .forEach (this ::addUserInfoCredentials );
182+ Stream <URI > uris = getUris (connectionDetails );
183+ uris .filter (this ::hasUserInfo ).forEach (this ::addUserInfoCredentials );
192184 }
193185
194- private URI toUri (String uri ) {
195- try {
196- return URI .create (uri );
197- }
198- catch (IllegalArgumentException ex ) {
199- return null ;
200- }
186+ private Stream <URI > getUris (ElasticsearchConnectionDetails connectionDetails ) {
187+ return connectionDetails .getNodes ().stream ().map (Node ::toUri );
201188 }
202189
203190 private boolean hasUserInfo (URI uri ) {
@@ -222,4 +209,59 @@ private Credentials createUserInfoCredentials(String userInfo) {
222209
223210 }
224211
212+ /**
213+ * Adapts {@link ElasticsearchProperties} to {@link ElasticsearchConnectionDetails}.
214+ */
215+ private static class PropertiesElasticsearchConnectionDetails implements ElasticsearchConnectionDetails {
216+
217+ private final ElasticsearchProperties properties ;
218+
219+ PropertiesElasticsearchConnectionDetails (ElasticsearchProperties properties ) {
220+ this .properties = properties ;
221+ }
222+
223+ @ Override
224+ public List <Node > getNodes () {
225+ return this .properties .getUris ().stream ().map (this ::createNode ).toList ();
226+ }
227+
228+ @ Override
229+ public String getUsername () {
230+ return this .properties .getUsername ();
231+ }
232+
233+ @ Override
234+ public String getPassword () {
235+ return this .properties .getPassword ();
236+ }
237+
238+ @ Override
239+ public String getPathPrefix () {
240+ return this .properties .getPathPrefix ();
241+ }
242+
243+ private Node createNode (String uri ) {
244+ if (!(uri .startsWith ("http://" ) || uri .startsWith ("https://" ))) {
245+ uri = "http://" + uri ;
246+ }
247+ return createNode (URI .create (uri ));
248+ }
249+
250+ private Node createNode (URI uri ) {
251+ String userInfo = uri .getUserInfo ();
252+ Protocol protocol = Protocol .forScheme (uri .getScheme ());
253+ if (!StringUtils .hasLength (userInfo )) {
254+ return new Node (uri .getHost (), uri .getPort (), protocol , null , null );
255+ }
256+ int separatorIndex = userInfo .indexOf (':' );
257+ if (separatorIndex == -1 ) {
258+ return new Node (uri .getHost (), uri .getPort (), protocol , userInfo , null );
259+ }
260+ String [] components = userInfo .split (":" );
261+ return new Node (uri .getHost (), uri .getPort (), protocol , components [0 ],
262+ (components .length > 1 ) ? components [1 ] : "" );
263+ }
264+
265+ }
266+
225267}
0 commit comments