Browse Source
* pr/25377: Polish "Expose Spring Integration global properties" Expose Spring Integration global properties Closes gh-25377pull/25815/head
8 changed files with 505 additions and 2 deletions
@ -0,0 +1,113 @@
@@ -0,0 +1,113 @@
|
||||
/* |
||||
* Copyright 2012-2021 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.autoconfigure.integration; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.env.EnvironmentPostProcessor; |
||||
import org.springframework.boot.env.OriginTrackedMapPropertySource; |
||||
import org.springframework.boot.env.PropertiesPropertySourceLoader; |
||||
import org.springframework.boot.origin.Origin; |
||||
import org.springframework.boot.origin.OriginLookup; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.core.env.ConfigurableEnvironment; |
||||
import org.springframework.core.env.PropertySource; |
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.integration.context.IntegrationProperties; |
||||
|
||||
/** |
||||
* An {@link EnvironmentPostProcessor} that maps the configuration of |
||||
* {@code META-INF/spring.integration.properties} in the environment. |
||||
* |
||||
* @author Artem Bilan |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class IntegrationPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return Ordered.LOWEST_PRECEDENCE; |
||||
} |
||||
|
||||
@Override |
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { |
||||
Resource resource = new ClassPathResource("META-INF/spring.integration.properties"); |
||||
if (resource.exists()) { |
||||
registerIntegrationPropertiesPropertySource(environment, resource); |
||||
} |
||||
} |
||||
|
||||
protected void registerIntegrationPropertiesPropertySource(ConfigurableEnvironment environment, Resource resource) { |
||||
PropertiesPropertySourceLoader loader = new PropertiesPropertySourceLoader(); |
||||
try { |
||||
OriginTrackedMapPropertySource propertyFileSource = (OriginTrackedMapPropertySource) loader |
||||
.load("META-INF/spring.integration.properties", resource).get(0); |
||||
environment.getPropertySources().addLast(new IntegrationPropertiesPropertySource(propertyFileSource)); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new IllegalStateException("Failed to load integration properties from " + resource, ex); |
||||
} |
||||
} |
||||
|
||||
private static final class IntegrationPropertiesPropertySource extends PropertySource<Map<String, Object>> |
||||
implements OriginLookup<String> { |
||||
|
||||
private static final String PREFIX = "spring.integration."; |
||||
|
||||
private static final Map<String, String> KEYS_MAPPING; |
||||
|
||||
static { |
||||
Map<String, String> mappings = new HashMap<>(); |
||||
mappings.put(PREFIX + "channel.auto-create", IntegrationProperties.CHANNELS_AUTOCREATE); |
||||
mappings.put(PREFIX + "channel.max-unicast-subscribers", |
||||
IntegrationProperties.CHANNELS_MAX_UNICAST_SUBSCRIBERS); |
||||
mappings.put(PREFIX + "channel.max-broadcast-subscribers", |
||||
IntegrationProperties.CHANNELS_MAX_BROADCAST_SUBSCRIBERS); |
||||
mappings.put(PREFIX + "error.require-subscribers", IntegrationProperties.ERROR_CHANNEL_REQUIRE_SUBSCRIBERS); |
||||
mappings.put(PREFIX + "error.ignore-failures", IntegrationProperties.ERROR_CHANNEL_IGNORE_FAILURES); |
||||
mappings.put(PREFIX + "endpoint.throw-exception-on-late-reply", |
||||
IntegrationProperties.THROW_EXCEPTION_ON_LATE_REPLY); |
||||
mappings.put(PREFIX + "endpoint.read-only-headers", IntegrationProperties.READ_ONLY_HEADERS); |
||||
mappings.put(PREFIX + "endpoint.no-auto-startup", IntegrationProperties.ENDPOINTS_NO_AUTO_STARTUP); |
||||
KEYS_MAPPING = Collections.unmodifiableMap(mappings); |
||||
} |
||||
|
||||
private final OriginTrackedMapPropertySource delegate; |
||||
|
||||
IntegrationPropertiesPropertySource(OriginTrackedMapPropertySource delegate) { |
||||
super("META-INF/spring.integration.properties", delegate.getSource()); |
||||
this.delegate = delegate; |
||||
} |
||||
|
||||
@Override |
||||
public Object getProperty(String name) { |
||||
return this.delegate.getProperty(KEYS_MAPPING.get(name)); |
||||
} |
||||
|
||||
@Override |
||||
public Origin getOrigin(String key) { |
||||
return this.delegate.getOrigin(KEYS_MAPPING.get(key)); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
/* |
||||
* Copyright 2012-2021 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.autoconfigure.integration; |
||||
|
||||
import java.io.FileNotFoundException; |
||||
import java.util.Collections; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.origin.Origin; |
||||
import org.springframework.boot.origin.OriginLookup; |
||||
import org.springframework.boot.origin.TextResourceOrigin; |
||||
import org.springframework.core.env.ConfigurableEnvironment; |
||||
import org.springframework.core.env.MapPropertySource; |
||||
import org.springframework.core.env.PropertySource; |
||||
import org.springframework.core.env.StandardEnvironment; |
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.core.io.Resource; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link IntegrationPropertiesEnvironmentPostProcessor}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class IntegrationPropertiesEnvironmentPostProcessorTests { |
||||
|
||||
@Test |
||||
void postProcessEnvironmentAddPropertySource() { |
||||
ConfigurableEnvironment environment = new StandardEnvironment(); |
||||
new IntegrationPropertiesEnvironmentPostProcessor().postProcessEnvironment(environment, |
||||
mock(SpringApplication.class)); |
||||
assertThat(environment.getPropertySources().contains("META-INF/spring.integration.properties")).isTrue(); |
||||
assertThat(environment.getProperty("spring.integration.endpoint.no-auto-startup")).isEqualTo("testService*"); |
||||
} |
||||
|
||||
@Test |
||||
void postProcessEnvironmentAddPropertySourceLast() { |
||||
ConfigurableEnvironment environment = new StandardEnvironment(); |
||||
environment.getPropertySources().addLast(new MapPropertySource("test", |
||||
Collections.singletonMap("spring.integration.endpoint.no-auto-startup", "another*"))); |
||||
new IntegrationPropertiesEnvironmentPostProcessor().postProcessEnvironment(environment, |
||||
mock(SpringApplication.class)); |
||||
assertThat(environment.getPropertySources().contains("META-INF/spring.integration.properties")).isTrue(); |
||||
assertThat(environment.getProperty("spring.integration.endpoint.no-auto-startup")).isEqualTo("another*"); |
||||
} |
||||
|
||||
@Test |
||||
void registerIntegrationPropertiesPropertySourceWithUnknownResourceThrowsException() { |
||||
ConfigurableEnvironment environment = new StandardEnvironment(); |
||||
ClassPathResource unknown = new ClassPathResource("does-not-exist.properties", getClass()); |
||||
assertThatThrownBy(() -> new IntegrationPropertiesEnvironmentPostProcessor() |
||||
.registerIntegrationPropertiesPropertySource(environment, unknown)) |
||||
.isInstanceOf(IllegalStateException.class).hasCauseInstanceOf(FileNotFoundException.class) |
||||
.hasMessageContaining(unknown.toString()); |
||||
} |
||||
|
||||
@Test |
||||
void registerIntegrationPropertiesPropertySourceWithResourceAddPropertySource() { |
||||
ConfigurableEnvironment environment = new StandardEnvironment(); |
||||
new IntegrationPropertiesEnvironmentPostProcessor().registerIntegrationPropertiesPropertySource(environment, |
||||
new ClassPathResource("spring.integration.properties", getClass())); |
||||
assertThat(environment.getProperty("spring.integration.channel.auto-create", Boolean.class)).isFalse(); |
||||
assertThat(environment.getProperty("spring.integration.channel.max-unicast-subscribers", Integer.class)) |
||||
.isEqualTo(4); |
||||
assertThat(environment.getProperty("spring.integration.channel.max-broadcast-subscribers", Integer.class)) |
||||
.isEqualTo(6); |
||||
assertThat(environment.getProperty("spring.integration.error.require-subscribers", Boolean.class)).isFalse(); |
||||
assertThat(environment.getProperty("spring.integration.error.ignore-failures", Boolean.class)).isFalse(); |
||||
assertThat(environment.getProperty("spring.integration.endpoint.throw-exception-on-late-reply", Boolean.class)) |
||||
.isTrue(); |
||||
assertThat(environment.getProperty("spring.integration.endpoint.read-only-headers", String.class)) |
||||
.isEqualTo("header1,header2"); |
||||
assertThat(environment.getProperty("spring.integration.endpoint.no-auto-startup", String.class)) |
||||
.isEqualTo("testService,anotherService"); |
||||
} |
||||
|
||||
@Test |
||||
@SuppressWarnings("unchecked") |
||||
void registerIntegrationPropertiesPropertySourceWithResourceCanRetrieveOrigin() { |
||||
ConfigurableEnvironment environment = new StandardEnvironment(); |
||||
ClassPathResource resource = new ClassPathResource("spring.integration.properties", getClass()); |
||||
new IntegrationPropertiesEnvironmentPostProcessor().registerIntegrationPropertiesPropertySource(environment, |
||||
resource); |
||||
PropertySource<?> ps = environment.getPropertySources().get("META-INF/spring.integration.properties"); |
||||
assertThat(ps).isNotNull().isInstanceOf(OriginLookup.class); |
||||
OriginLookup<String> originLookup = (OriginLookup<String>) ps; |
||||
assertThat(originLookup.getOrigin("spring.integration.channel.auto-create")) |
||||
.satisfies(textOrigin(resource, 0, 39)); |
||||
assertThat(originLookup.getOrigin("spring.integration.channel.max-unicast-subscribers")) |
||||
.satisfies(textOrigin(resource, 1, 50)); |
||||
assertThat(originLookup.getOrigin("spring.integration.channel.max-broadcast-subscribers")) |
||||
.satisfies(textOrigin(resource, 2, 52)); |
||||
} |
||||
|
||||
private Consumer<Origin> textOrigin(Resource resource, int line, int column) { |
||||
return (origin) -> { |
||||
assertThat(origin).isInstanceOf(TextResourceOrigin.class); |
||||
TextResourceOrigin textOrigin = (TextResourceOrigin) origin; |
||||
assertThat(textOrigin.getResource()).isEqualTo(resource); |
||||
assertThat(textOrigin.getLocation().getLine()).isEqualTo(line); |
||||
assertThat(textOrigin.getLocation().getColumn()).isEqualTo(column); |
||||
}; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
spring.integration.endpoints.noAutoStartup=testService* |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
spring.integration.channels.autoCreate=false |
||||
spring.integration.channels.maxUnicastSubscribers=4 |
||||
spring.integration.channels.maxBroadcastSubscribers=6 |
||||
spring.integration.channels.error.requireSubscribers=false |
||||
spring.integration.channels.error.ignoreFailures=false |
||||
spring.integration.messagingTemplate.throwExceptionOnLateReply=true |
||||
spring.integration.readOnly.headers=header1,header2 |
||||
spring.integration.endpoints.noAutoStartup=testService,anotherService |
||||
Loading…
Reference in new issue