diff --git a/src/main/java/org/springframework/data/gemfire/LocatorFactoryBean.java b/src/main/java/org/springframework/data/gemfire/LocatorFactoryBean.java index 6a8df23f..d4218a36 100644 --- a/src/main/java/org/springframework/data/gemfire/LocatorFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/LocatorFactoryBean.java @@ -57,6 +57,7 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport impl public static final int DEFAULT_PORT = 10334; public static final String DEFAULT_LOG_LEVEL = "config"; + private static final String LOCATORS_PROPERTY = "locators"; public static final String LOG_LEVEL_PROPERTY = "log-level"; private Integer port = DEFAULT_PORT; @@ -75,6 +76,7 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport impl private String bindAddress; private String hostnameForClients; + private String locators; private String logLevel; private String name; @@ -105,14 +107,15 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport impl getBindAddress().ifPresent(locatorBuilder::setBindAddress); getHostnameForClients().ifPresent(locatorBuilder::setHostnameForClients); + getLocators().ifPresent(locators -> locatorBuilder.set(LOCATORS_PROPERTY, locators)); getName().ifPresent(locatorBuilder::setMemberName); locatorBuilder.set(LOG_LEVEL_PROPERTY, getLogLevel()); locatorBuilder.setPort(getPort()); - locatorBuilder = postProcess(locatorBuilder); + LocatorLauncher.Builder processedLocatorBuilder = postProcess(locatorBuilder); - this.locatorLauncher = postProcess(locatorBuilder.build()); + this.locatorLauncher = postProcess(processedLocatorBuilder.build()); LocatorLauncher.LocatorState locatorState = this.locatorLauncher.start(); @@ -222,6 +225,16 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport impl Optional.ofNullable(locatorConfigurers).ifPresent(this.locatorConfigurers::addAll); } + public void setLocators(String locators) { + this.locators = locators; + } + + public Optional getLocators() { + + return Optional.ofNullable(this.locators) + .filter(StringUtils::hasText); + } + public void setLogLevel(String logLevel) { this.logLevel = logLevel; } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplication.java index b82a02d2..4914c5cd 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplication.java @@ -72,6 +72,14 @@ public @interface LocatorApplication { */ String hostnameForClients() default ""; + /** + * Configures the list of {@link Locator Locators} defining the cluster to which this Spring {@link Locator} + * application will connect. + * + * Use {@literal spring.data.gemfire.locators} property in {@literal application.properties}. + */ + String locators() default ""; + /** * Configures the log level used to output log messages at Apache Geode / Pivotal GemFire {@link Locator} runtime. * diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfiguration.java index 8817c0e2..43d4deaa 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfiguration.java @@ -88,6 +88,7 @@ public class LocatorApplicationConfiguration extends AbstractAnnotationConfigSup private String bindAddress; private String hostnameForClients; + private String locators; private String logLevel; private String name; @@ -147,6 +148,9 @@ public class LocatorApplicationConfiguration extends AbstractAnnotationConfigSup setHostnameForClients(resolveProperty(locatorProperty("hostname-for-clients"), locatorApplicationAnnotationAttributes.getString("hostnameForClients"))); + setLocators(resolveProperty(propertyName("locators"), + locatorApplicationAnnotationAttributes.getString("locators"))); + setLogLevel(resolveProperty(locatorProperty("log-level"), locatorApplicationAnnotationAttributes.getString("logLevel"))); @@ -166,6 +170,7 @@ public class LocatorApplicationConfiguration extends AbstractAnnotationConfigSup locatorFactoryBean.setBindAddress(getBindAddress()); locatorFactoryBean.setHostnameForClients(getHostnameForClients()); locatorFactoryBean.setLocatorConfigurers(resolveLocatorConfigurers()); + locatorFactoryBean.setLocators(getLocators()); locatorFactoryBean.setLogLevel(getLogLevel()); locatorFactoryBean.setName(getName()); locatorFactoryBean.setPort(getPort()); @@ -197,6 +202,14 @@ public class LocatorApplicationConfiguration extends AbstractAnnotationConfigSup return this.hostnameForClients; } + public void setLocators(String locators) { + this.locators = locators; + } + + public String getLocators() { + return this.locators; + } + public void setLogLevel(String logLevel) { this.logLevel = logLevel; } diff --git a/src/test/java/org/springframework/data/gemfire/LocatorFactoryBeanUnitTests.java b/src/test/java/org/springframework/data/gemfire/LocatorFactoryBeanUnitTests.java index 9ea94b45..281623c3 100644 --- a/src/test/java/org/springframework/data/gemfire/LocatorFactoryBeanUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/LocatorFactoryBeanUnitTests.java @@ -33,14 +33,14 @@ import java.util.Arrays; import java.util.List; import java.util.Properties; -import org.apache.geode.distributed.Locator; -import org.apache.geode.distributed.LocatorLauncher; - import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mockito; +import org.apache.geode.distributed.Locator; +import org.apache.geode.distributed.LocatorLauncher; + import org.springframework.data.gemfire.config.annotation.LocatorConfigurer; /** @@ -145,6 +145,7 @@ public class LocatorFactoryBeanUnitTests { this.locatorFactoryBean.setBeanName("TestLocatorBean"); this.locatorFactoryBean.setBindAddress(testBindAddress); this.locatorFactoryBean.setHostnameForClients("skullbox"); + this.locatorFactoryBean.setLocators("host1[1234],host2[6789]"); this.locatorFactoryBean.setName("TestMember"); this.locatorFactoryBean.setPort(54321); this.locatorFactoryBean.init(); @@ -152,6 +153,7 @@ public class LocatorFactoryBeanUnitTests { assertThat(this.locatorFactoryBean.getLocator()).isEqualTo(mockLocator); assertThat(this.locatorFactoryBean.getLocatorLauncher()).isEqualTo(mockLocatorLauncher); + verify(locatorBuilderSpy, times(1)).set(eq("locators"), eq("host1[1234],host2[6789]")); verify(locatorBuilderSpy, times(1)).set(eq("log-level"), eq("config")); verify(locatorBuilderSpy, times(1)).setBindAddress(eq(testBindAddress)); verify(locatorBuilderSpy, times(1)).setHostnameForClients(eq("skullbox")); @@ -319,6 +321,30 @@ public class LocatorFactoryBeanUnitTests { .configure(eq("TestLocator"), eq(this.locatorFactoryBean)); } + @Test + public void setAndGetLocators() { + + this.locatorFactoryBean.setLocators("skullbox[11235]"); + + assertThat(this.locatorFactoryBean.getLocators().orElse(null)).isEqualTo("skullbox[11235]"); + + this.locatorFactoryBean.setLocators(null); + + assertThat(this.locatorFactoryBean.getLocators().orElse(null)).isNull(); + + this.locatorFactoryBean.setLocators(""); + + assertThat(this.locatorFactoryBean.getLocators().orElse(null)).isNull(); + + this.locatorFactoryBean.setLocators(" "); + + assertThat(this.locatorFactoryBean.getLocators().orElse(null)).isNull(); + + this.locatorFactoryBean.setLocators("host1[1234],host2[6789]"); + + assertThat(this.locatorFactoryBean.getLocators().orElse(null)).isEqualTo("host1[1234],host2[6789]"); + } + @Test public void setAndGetLogLevel() { diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfigurationIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfigurationIntegrationTests.java new file mode 100644 index 00000000..1c5d044c --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationConfigurationIntegrationTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2020 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.data.gemfire.config.annotation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.LocatorFactoryBean; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects; +import org.springframework.lang.Nullable; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration Tests for {@link LocatorApplication} and {@link LocatorApplicationConfiguration}. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.beans.factory.config.BeanPostProcessor + * @see org.springframework.data.gemfire.LocatorFactoryBean + * @see org.springframework.data.gemfire.config.annotation.LocatorApplication + * @see org.springframework.data.gemfire.config.annotation.LocatorApplicationConfiguration + * @see org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 2.3.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class LocatorApplicationConfigurationIntegrationTests { + + @Autowired + private LocatorFactoryBean locatorFactoryBean; + + @Test + public void locatorFactoryBeanWasConfiguredFromAnnotationAttributes() { + + assertThat(this.locatorFactoryBean).isNotNull(); + assertThat(this.locatorFactoryBean.getBindAddress().orElse(null)).isEqualTo("10.101.202.8"); + assertThat(this.locatorFactoryBean.getHostnameForClients().orElse(null)).isEqualTo("cardboardBox"); + assertThat(this.locatorFactoryBean.getLocators().orElse(null)).isEqualTo("host1[1234],host2[6789]"); + assertThat(this.locatorFactoryBean.getLogLevel()).isEqualTo("WARN"); + assertThat(this.locatorFactoryBean.getName().orElse(null)).isEqualTo("MockLocator"); + assertThat(this.locatorFactoryBean.getPort()).isEqualTo(9876); + } + + @EnableGemFireMockObjects + @LocatorApplication( + bindAddress = "10.101.202.8", + hostnameForClients = "cardboardBox", + locators = "host1[1234],host2[6789]", + logLevel = "WARN", + name = "MockLocator", + port = 9876 + ) + static class TestConfiguration { + + @Bean + BeanPostProcessor locatorFactoryBeanPostProcessor() { + + return new BeanPostProcessor() { + + @Nullable @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + + if (bean instanceof LocatorFactoryBean) { + + LocatorFactoryBean locatorFactoryBean = spy((LocatorFactoryBean) bean); + + doNothing().when(locatorFactoryBean).init(); + + bean = locatorFactoryBean; + + } + + return bean; + } + }; + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationPropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationPropertiesIntegrationTests.java index 655ae12c..91cc3752 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationPropertiesIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/LocatorApplicationPropertiesIntegrationTests.java @@ -91,7 +91,8 @@ public class LocatorApplicationPropertiesIntegrationTests { .withProperty("spring.data.gemfire.locator.hostname-for-clients", "skullbox") .withProperty("spring.data.gemfire.locator.log-level", "error") .withProperty("spring.data.gemfire.locator.name", "MockLocator") - .withProperty("spring.data.gemfire.locator.port", 54321); + .withProperty("spring.data.gemfire.locator.port", 54321) + .withProperty("spring.data.gemfire.locators", "host1[1234],host2[6789]"); this.applicationContext = newApplicationContext(testPropertySource, TestConfiguration.class); @@ -100,6 +101,7 @@ public class LocatorApplicationPropertiesIntegrationTests { assertThat(locatorFactoryBean).isNotNull(); assertThat(locatorFactoryBean.getBindAddress().orElse(null)).isEqualTo("10.120.240.32"); assertThat(locatorFactoryBean.getHostnameForClients().orElse(null)).isEqualTo("skullbox"); + assertThat(locatorFactoryBean.getLocators().orElse(null)).isEqualTo("host1[1234],host2[6789]"); assertThat(locatorFactoryBean.getLogLevel()).isEqualTo("error"); assertThat(locatorFactoryBean.getName().orElse(null)).isEqualTo("MockLocator"); assertThat(locatorFactoryBean.getPort()).isEqualTo(54321);