Commit 3e243d6a authored by Phillip Webb's avatar Phillip Webb

Merge pull request #18287 from veronicavasq

* pr/18287:
  Polish 'Add @LocalRSocketServerPort support'
  Add @LocalRSocketServerPort support

Closes gh-18287
parents ec747d6b 4b0fb8ff
......@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.rsocket;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer;
import org.springframework.boot.rsocket.server.RSocketServerBootstrap;
import org.springframework.boot.rsocket.server.RSocketServerFactory;
import org.springframework.boot.rsocket.server.ServerRSocketFactoryCustomizer;
......@@ -39,6 +40,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link RSocketServerAutoConfiguration}.
*
* @author Brian Clozel
* @author Verónica Vásquez
*/
class RSocketServerAutoConfigurationTests {
......@@ -80,6 +82,17 @@ class RSocketServerAutoConfigurationTests {
.hasSingleBean(ServerRSocketFactoryCustomizer.class));
}
@Test
void shouldSetLocalServerPortWhenRSocketServerPortIsSet() {
reactiveWebContextRunner().withPropertyValues("spring.rsocket.server.port=0")
.withInitializer(new RSocketPortInfoApplicationContextInitializer()).run((context) -> {
assertThat(context).hasSingleBean(RSocketServerFactory.class)
.hasSingleBean(RSocketServerBootstrap.class)
.hasSingleBean(ServerRSocketFactoryCustomizer.class);
assertThat(context.getEnvironment().getProperty("local.rsocket.server.port")).isNotNull();
});
}
@Test
void shouldUseCustomServerBootstrap() {
contextRunner().withUserConfiguration(CustomServerBootstrapConfig.class).run((context) -> assertThat(context)
......
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.rsocket.context;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Value;
/**
* Annotation at the field or method/constructor parameter level that injects the RSocket
* port that got allocated at runtime. Provides a convenient alternative for
* <code>&#064;Value(&quot;${local.rsocket.server.port}&quot;)</code>.
*
* @author Verónica Vásquez
* @author Eddú Meléndez
* @since 2.2.0
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Value("${local.rsocket.server.port}")
public @interface LocalRSocketServerPort {
}
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.rsocket.context;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.rsocket.server.RSocketServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
/**
* {@link ApplicationContextInitializer} that sets {@link Environment} properties for the
* ports that {@link RSocketServer} servers are actually listening on. The property
* {@literal "local.rsocket.server.port"} can be injected directly into tests using
* {@link Value @Value} or obtained via the {@link Environment}.
* <p>
* Properties are automatically propagated up to any parent context.
*
* @author Verónica Vásquez
* @author Eddú Meléndez
* @since 2.2.0
*/
public class RSocketPortInfoApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(new Listener(applicationContext));
}
private static class Listener implements ApplicationListener<RSocketServerInitializedEvent> {
private static final String PROPERTY_NAME = "local.rsocket.server.port";
private ConfigurableApplicationContext applicationContext;
Listener(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void onApplicationEvent(RSocketServerInitializedEvent event) {
setPortProperty(this.applicationContext, event.getrSocketServer().address().getPort());
}
private void setPortProperty(ApplicationContext context, int port) {
if (context instanceof ConfigurableApplicationContext) {
setPortProperty(((ConfigurableApplicationContext) context).getEnvironment(), port);
}
if (context.getParent() != null) {
setPortProperty(context.getParent(), port);
}
}
private void setPortProperty(ConfigurableEnvironment environment, int port) {
MutablePropertySources sources = environment.getPropertySources();
PropertySource<?> source = sources.get("server.ports");
if (source == null) {
source = new MapPropertySource("server.ports", new HashMap<>());
sources.addFirst(source);
}
setPortProperty(port, source);
}
@SuppressWarnings("unchecked")
private void setPortProperty(int port, PropertySource<?> source) {
((Map<String, Object>) source.getSource()).put(PROPERTY_NAME, port);
}
}
}
......@@ -16,6 +16,7 @@ org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
......
......@@ -240,7 +240,7 @@ class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.web(WebApplicationType.NONE);
this.context = application.run();
assertThat(application.application().getInitializers()).hasSize(4);
assertThat(application.application().getInitializers()).hasSize(5);
}
@Test
......@@ -248,7 +248,7 @@ class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)
.child(ChildConfig.class).web(WebApplicationType.NONE);
this.context = application.run();
assertThat(application.application().getInitializers()).hasSize(5);
assertThat(application.application().getInitializers()).hasSize(6);
}
@Test
......@@ -257,7 +257,7 @@ class SpringApplicationBuilderTests {
.web(WebApplicationType.NONE).initializers((ConfigurableApplicationContext applicationContext) -> {
});
this.context = application.run();
assertThat(application.application().getInitializers()).hasSize(5);
assertThat(application.application().getInitializers()).hasSize(6);
}
@Test
......
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.rsocket.context;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link LocalRSocketServerPort @LocalRSocketServerPort}.
*
* @author Verónica Vásquez
* @author Eddú Meléndez
*/
@ExtendWith(SpringExtension.class)
@TestPropertySource(properties = "local.rsocket.server.port=8181")
class LocalRSocketServerPortTests {
@Value("${local.rsocket.server.port}")
private String fromValue;
@LocalRSocketServerPort
private String fromAnnotation;
@Test
void testLocalRSocketServerPortAnnotation() {
assertThat(this.fromAnnotation).isNotNull().isEqualTo(this.fromValue);
}
@Configuration(proxyBeanMethods = false)
static class Config {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment