diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index f2f37442606..c06da53e273 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -38,6 +38,7 @@ import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics; +import org.springframework.boot.actuate.health.CompositeHealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.SimpleHealthIndicator; import org.springframework.boot.actuate.health.VanillaHealthIndicator; @@ -75,7 +76,7 @@ public class EndpointAutoConfiguration { private HealthIndicator healthIndicator; @Autowired(required = false) - private DataSource dataSource; + private Map dataSources; @Autowired private InfoPropertiesConfiguration properties; @@ -97,20 +98,30 @@ public class EndpointAutoConfiguration { @Bean @ConditionalOnMissingBean - public HealthEndpoint healthEndpoint() { + public HealthEndpoint healthEndpoint() { if (this.healthIndicator == null) { - if (this.dataSource == null) { - this.healthIndicator = new VanillaHealthIndicator(); - } - else { - SimpleHealthIndicator healthIndicator = new SimpleHealthIndicator(); - healthIndicator.setDataSource(this.dataSource); - this.healthIndicator = healthIndicator; - } + this.healthIndicator = createHealthIndicator(); } return new HealthEndpoint(this.healthIndicator); } + private HealthIndicator createHealthIndicator() { + if (this.dataSources == null || this.dataSources.isEmpty()) { + return new VanillaHealthIndicator(); + } + + if (this.dataSources.size() == 1) { + return new SimpleHealthIndicator(this.dataSources.values().iterator().next()); + } + + CompositeHealthIndicator composite = new CompositeHealthIndicator(); + for (Map.Entry entry : this.dataSources.entrySet()) { + composite.addHealthIndicator(entry.getKey(), + new SimpleHealthIndicator(entry.getValue())); + } + return composite; + } + @Bean @ConditionalOnMissingBean public BeansEndpoint beansEndpoint() { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java new file mode 100644 index 00000000000..d93f872227b --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2014 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 + * + * http://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.actuate.health; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * {@link HealthIndicator} that returns health indications from all registered delegates. + * + * @author Tyler J. Frederick + * @author Phillip Webb + */ +public class CompositeHealthIndicator implements HealthIndicator> { + + private final Map> indicators; + + /** + * Create a new {@link CompositeHealthIndicator}. + */ + public CompositeHealthIndicator() { + this.indicators = new LinkedHashMap>(); + } + + /** + * Create a new {@link CompositeHealthIndicator} from the specified indicators. + * @param indicators a map of {@link HealthIndicator}s with the key being used as an + * indicator name. + */ + public CompositeHealthIndicator(Map> indicators) { + this.indicators = new LinkedHashMap>(indicators); + } + + public void addHealthIndicator(String name, HealthIndicator indicator) { + this.indicators.put(name, indicator); + } + + @Override + public Map health() { + Map health = new LinkedHashMap(); + for (Map.Entry> entry : this.indicators.entrySet()) { + health.put(entry.getKey(), entry.getValue().health()); + } + return health; + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/SimpleHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/SimpleHealthIndicator.java index 61fcc73580f..4c185c4a5b1 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/SimpleHealthIndicator.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/SimpleHealthIndicator.java @@ -54,6 +54,21 @@ public class SimpleHealthIndicator implements HealthIndicator health() { LinkedHashMap health = new LinkedHashMap(); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java new file mode 100644 index 00000000000..03da219085a --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2012-2014 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 + * + * http://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.actuate.health; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; + +/** + * Tests for {@link CompositeHealthIndicator} + * + * @author Tyler J. Frederick + * @author Phillip Webb + */ +public class CompositeHealthIndicatorTests { + + @Mock + private HealthIndicator one; + + @Mock + private HealthIndicator two; + + @Mock + private HealthIndicator three; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + given(this.one.health()).willReturn("1"); + given(this.two.health()).willReturn("2"); + given(this.three.health()).willReturn("3"); + } + + @Test + public void createWithIndicators() throws Exception { + Map> indicators = new HashMap>(); + indicators.put("one", this.one); + indicators.put("two", this.two); + CompositeHealthIndicator composite = new CompositeHealthIndicator(indicators); + Map result = composite.health(); + assertThat(result.size(), equalTo(2)); + assertThat(result, hasEntry("one", (Object) "1")); + assertThat(result, hasEntry("two", (Object) "2")); + } + + @Test + public void createWithIndicatorsAndAdd() throws Exception { + Map> indicators = new HashMap>(); + indicators.put("one", this.one); + indicators.put("two", this.two); + CompositeHealthIndicator composite = new CompositeHealthIndicator(indicators); + composite.addHealthIndicator("three", this.three); + Map result = composite.health(); + assertThat(result.size(), equalTo(3)); + assertThat(result, hasEntry("one", (Object) "1")); + assertThat(result, hasEntry("two", (Object) "2")); + assertThat(result, hasEntry("three", (Object) "3")); + } + + @Test + public void createWithoutAndAdd() throws Exception { + CompositeHealthIndicator composite = new CompositeHealthIndicator(); + composite.addHealthIndicator("one", this.one); + composite.addHealthIndicator("two", this.two); + Map result = composite.health(); + assertThat(result.size(), equalTo(2)); + assertThat(result, hasEntry("one", (Object) "1")); + assertThat(result, hasEntry("two", (Object) "2")); + } + +}