Add support for configuring the working directory of the Locator created/started by the LocatorFactoryBean.

Resolves #623.
This commit is contained in:
John Blum
2022-10-05 14:59:16 -07:00
parent 49e1ba8a60
commit a1eabf8650
3 changed files with 114 additions and 2 deletions

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.gemfire;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -64,6 +65,8 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport<Locator> impl
private boolean useBeanFactoryLocator = false;
private boolean useClusterConfigurationService = false;
private File workingDirectory;
private Integer port = DEFAULT_PORT;
private final List<LocatorConfigurer> locatorConfigurers = new ArrayList<>();
@@ -120,6 +123,10 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport<Locator> impl
getLocators().ifPresent(locators -> locatorBuilder.set(LOCATORS_PROPERTY, locators));
getName().ifPresent(locatorBuilder::setMemberName);
getWorkingDirectory()
.map(File::getAbsolutePath)
.ifPresent(locatorBuilder::setWorkingDirectory);
locatorBuilder.set(LOG_LEVEL_PROPERTY, getLogLevel());
locatorBuilder.setPort(getPort());
@@ -305,4 +312,49 @@ public class LocatorFactoryBean extends AbstractFactoryBeanSupport<Locator> impl
public boolean isUseClusterConfigurationService() {
return this.useClusterConfigurationService;
}
/**
* Sets the file system {@link File directory} in which the {@link Locator} will write all files to disk.
*
* This configuration setting should not be taken to mean this is the {@link File directory} in which
* the {@link Locator} process will run, or in other words, the {@link Locator} process's actual
* {@link File working directory}. If this {@link LocatorFactoryBean} is used to create and start
* a {@link Locator}, then the {@link Locator} will run in an embedded mode, or the same JVM process
* as the Spring application that called this {@link LocatorFactoryBean} and started the {@link Locator})
* and therefore will inherit the same {@link File working directory} as the parent Spring application process.
*
* This configuration property is named after the same
* {@link LocatorLauncher.Builder#getWorkingDirectory() workingDirectory} configuration property
* on the {@link LocatorLauncher.Builder}.
*
* @param workingDirectory {@link File directory} in which the {@link Locator} will write its files to disk.
* @see org.apache.geode.distributed.LocatorLauncher.Builder#setWorkingDirectory(String)
* @see java.io.File
*/
public void setWorkingDirectory(@Nullable File workingDirectory) {
this.workingDirectory = workingDirectory;
}
/**
* Get the file system {@link File directory} in which the {@link Locator} will write all files to disk.
*
* This configuration setting should not be taken to mean this is the {@link File directory} in which
* the {@link Locator} process will run, or in other words, the {@link Locator} process's actual
* {@link File working directory}. If this {@link LocatorFactoryBean} is used to create and start
* a {@link Locator}, then the {@link Locator} will run in an embedded mode, or the same JVM process
* as the Spring application that called this {@link LocatorFactoryBean} and started the {@link Locator})
* and therefore will inherit the same {@link File working directory} as the parent Spring application process.
*
* This configuration property is named after the same
* {@link LocatorLauncher.Builder#getWorkingDirectory() workingDirectory} configuration property
* on the {@link LocatorLauncher.Builder}.
*
* @return the {@link File directory} in which the {@link Locator} will write its files to disk.
* @see org.apache.geode.distributed.LocatorLauncher.Builder#getWorkingDirectory()
* @see java.util.Optional
* @see java.io.File
*/
public Optional<File> getWorkingDirectory() {
return Optional.ofNullable(this.workingDirectory);
}
}

View File

@@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.io.File;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
@@ -132,6 +133,12 @@ public class LocatorFactoryBeanUnitTests {
@Test
public void initBuildsLocator() throws Exception {
File workingDirectory = new File(System.getProperty("java.io.tmpdir"));
assertThat(workingDirectory)
.describedAs("Working directory [%s] does not exist", workingDirectory.getAbsolutePath())
.isDirectory();
Locator mockLocator = mock(Locator.class);
LocatorLauncher mockLocatorLauncher = mock(LocatorLauncher.class);
@@ -150,6 +157,7 @@ public class LocatorFactoryBeanUnitTests {
this.locatorFactoryBean.setLocators("host1[1234],host2[6789]");
this.locatorFactoryBean.setName("TestMember");
this.locatorFactoryBean.setPort(54321);
this.locatorFactoryBean.setWorkingDirectory(workingDirectory);
this.locatorFactoryBean.init();
assertThat(this.locatorFactoryBean.getLocator()).isEqualTo(mockLocator);
@@ -161,6 +169,7 @@ public class LocatorFactoryBeanUnitTests {
verify(locatorBuilderSpy, times(1)).setHostnameForClients(eq("skullbox"));
verify(locatorBuilderSpy, times(1)).setMemberName(eq("TestMember"));
verify(locatorBuilderSpy, times(1)).setPort(eq(54321));
verify(locatorBuilderSpy, times(1)).setWorkingDirectory(eq(workingDirectory.getAbsolutePath()));
verify(this.locatorFactoryBean, times(1)).postProcess(eq(locatorBuilderSpy));
verify(this.locatorFactoryBean, times(1)).postProcess(eq(mockLocatorLauncher));
verify(mockLocatorLauncher, times(1)).start();
@@ -203,7 +212,7 @@ public class LocatorFactoryBeanUnitTests {
}
@Test
public void getObjectThrowsIllegalStateException() throws Exception {
public void getObjectThrowsIllegalStateException() {
assertThatIllegalStateException()
.isThrownBy(() -> this.locatorFactoryBean.getObject())

View File

@@ -16,8 +16,13 @@
package org.springframework.data.gemfire.config.annotation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException;
import java.io.File;
import java.util.Arrays;
import java.util.Properties;
import java.util.UUID;
import java.util.function.Function;
import org.junit.Before;
import org.junit.Test;
@@ -29,11 +34,16 @@ import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.Locator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.GemFireProperties;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.LocatorFactoryBean;
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
import org.springframework.data.gemfire.util.SpringExtensions;
import org.springframework.lang.NonNull;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.StringUtils;
/**
* Integration Tests for {@link LocatorApplication} and {@link LocatorApplicationConfiguration} asserting that
@@ -112,6 +122,47 @@ public class LocatorApplicationIntegrationTests extends IntegrationTestsSupport
bindAddress = "localhost",
port = 0
)
static class TestConfiguration { }
static class TestConfiguration {
@Bean
LocatorConfigurer workingDirectoryLocatorConfigurer() {
return (beanName, locatorFactoryBean) -> {
File workingDirectory = newWorkingDirectory(locatorFactoryBean);
Function<Throwable, Boolean> workingDirectoryCreationErrorHandler = cause -> {
throw newRuntimeException(cause, "Failed to create temporary working directory [%s]", workingDirectory);
};
SpringExtensions.ValueReturningThrowableOperation<Boolean> createWorkingDirectory = () -> {
boolean result = workingDirectory.mkdirs();
workingDirectory.deleteOnExit();
return result;
};
SpringExtensions.safeGetValue(createWorkingDirectory, workingDirectoryCreationErrorHandler);
assertThat(workingDirectory).isDirectory();
locatorFactoryBean.setWorkingDirectory(workingDirectory);
};
}
private String fromTemporaryDirectory(String... pathElements) {
StringBuilder relativePath = new StringBuilder(System.getProperty("java.io.tmpdir"));
Arrays.stream(pathElements)
.filter(StringUtils::hasText)
.forEach(pathElement -> relativePath.append(File.separator).append(pathElement));
return relativePath.toString();
}
private @NonNull File newWorkingDirectory(@NonNull LocatorFactoryBean locatorBean) {
return new File(fromTemporaryDirectory("locator",
locatorBean.getName().orElse("NO-NAME"), UUID.randomUUID().toString()));
}
}
}