diff --git a/spring-geode/src/main/java/org/springframework/geode/data/support/LifecycleAwareCacheDataImporterExporter.java b/spring-geode/src/main/java/org/springframework/geode/data/support/LifecycleAwareCacheDataImporterExporter.java
new file mode 100644
index 00000000..b759e3c1
--- /dev/null
+++ b/spring-geode/src/main/java/org/springframework/geode/data/support/LifecycleAwareCacheDataImporterExporter.java
@@ -0,0 +1,284 @@
+/*
+ * 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.geode.data.support;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.geode.cache.Region;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.Lifecycle;
+import org.springframework.core.env.Environment;
+import org.springframework.data.gemfire.support.SmartLifecycleSupport;
+import org.springframework.geode.data.CacheDataImporterExporter;
+import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * A {@link CacheDataImporterExporter} implementation using the {@literal Decorator Software Design Pattern} to wrap
+ * an existing {@link CacheDataImporterExporter} in order to {@literal decorate} the cache ({@link Region}) data
+ * import & export operations, making them Spring {@link ApplicationContext}, {@link Lifecycle} aware and capable.
+ *
+ * This wrapper {@literal decorates} the Apache Geode cache {@link Region Region} data import operation enabling it
+ * to be configured {@link ImportLifecycle#EAGER eagerly}, after the Region bean as been initialized,
+ * or {@link ImportLifecycle#LAZY lazily}, once all beans have been fully initialized and the Spring
+ * {@link ApplicationContext} refreshed.
+ *
+ * @author John Blum
+ * @see org.apache.geode.cache.Region
+ * @see org.springframework.context.ApplicationContext
+ * @see org.springframework.context.ApplicationContextAware
+ * @see org.springframework.context.EnvironmentAware
+ * @see org.springframework.context.Lifecycle
+ * @see org.springframework.core.env.Environment
+ * @see org.springframework.data.gemfire.support.SmartLifecycleSupport
+ * @see org.springframework.geode.data.CacheDataImporterExporter
+ * @see Decorator Software Design Pattern
+ * @since 1.3.0
+ */
+@SuppressWarnings("rawtypes")
+public class LifecycleAwareCacheDataImporterExporter
+ implements ApplicationContextAware, CacheDataImporterExporter, EnvironmentAware, SmartLifecycleSupport {
+
+ protected static final int DEFAULT_IMPORT_PHASE = Integer.MIN_VALUE + 1000000;
+
+ protected static final String CACHE_DATA_IMPORT_LIFECYCLE_PROPERTY_NAME =
+ "spring.boot.data.gemfire.cache.data.import.lifecycle";
+
+ protected static final String CACHE_DATA_IMPORT_PHASE_PROPERTY_NAME =
+ "spring.boot.data.gemfire.cache.data.import.phase";
+
+ private final AtomicReference resolvedImportLifecycle = new AtomicReference<>(null);
+ private final AtomicReference resolvedImportPhase = new AtomicReference<>(null);
+
+ private final CacheDataImporterExporter importerExporter;
+
+ private Environment environment;
+
+ private final Set regionsForImport = Collections.synchronizedSet(new HashSet<>());
+
+ /**
+ * Constructs a new instance of the {@link LifecycleAwareCacheDataImporterExporter} initialized with the given,
+ * target {@link CacheDataImporterExporter} that is wrapped by this implementation to decorate all cache import
+ * & export data operations in order to make them {@link Lifecycle} aware and capable.
+ *
+ * @param importerExporter {@link CacheDataImporterExporter} wrapped by this implementation to {@literal decorate}
+ * the cache data import/export operations to be {@link Lifecycle} aware and capable; must not be {@literal null}.
+ * @throws IllegalArgumentException if {@link CacheDataImporterExporter} is {@literal null}.
+ * @see org.springframework.geode.data.CacheDataImporterExporter
+ */
+ public LifecycleAwareCacheDataImporterExporter(@NonNull CacheDataImporterExporter importerExporter) {
+
+ Assert.notNull(importerExporter, "The CacheDataImporterExporter to decorate must not be null");
+
+ this.importerExporter = importerExporter;
+ }
+
+ /**
+ * Configures a reference to the Spring {@link ApplicationContext}.
+ *
+ * @param applicationContext Spring {@link ApplicationContext} in which this component operates.
+ * @see org.springframework.context.ApplicationContext
+ */
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) {
+
+ CacheDataImporterExporter importerExporter = getCacheDataImporterExporter();
+
+ if (applicationContext != null && importerExporter instanceof ApplicationContextAware) {
+ ((ApplicationContextAware) importerExporter).setApplicationContext(applicationContext);
+ }
+ }
+
+ /**
+ * Returns a reference to the configured {@link CacheDataImporterExporter} wrapped by this {@link Lifecycle} aware
+ * and capable {@link CacheDataImporterExporter}.
+ *
+ * @return the {@link CacheDataImporterExporter} enhanced and used as the delegate for this {@link Lifecycle} aware
+ * and capable {@link CacheDataImporterExporter}; never {@literal null}.
+ */
+ protected @NonNull CacheDataImporterExporter getCacheDataImporterExporter() {
+ return this.importerExporter;
+ }
+
+ /**
+ * Configures a reference to the {@link Environment} used to access the configuration for the behavior of
+ * the cache data import.
+ *
+ * @param environment {@link Environment} used to access context specific configuration for the cache data import.
+ * @see org.springframework.core.env.Environment
+ */
+ @Override
+ public void setEnvironment(Environment environment) {
+
+ this.environment = environment;
+
+ CacheDataImporterExporter importerExporter = getCacheDataImporterExporter();
+
+ if (environment != null && importerExporter instanceof EnvironmentAware) {
+ ((EnvironmentAware) importerExporter).setEnvironment(environment);
+ }
+ }
+
+ /**
+ * Returns an {@link Optional}, configured reference to the {@link Environment} used to access the configuration
+ * for the behavior of the cache data import.
+ *
+ * If a reference to {@link Environment} was not configured, then this method will return {@link Optional#empty()}.
+ *
+ * @return an {@link Optional} reference to the configured {@link Environment}, or {@link Optional#empty()} if no
+ * {@link Environment} was configured.
+ * @see org.springframework.core.env.Environment
+ * @see #setEnvironment(Environment)
+ * @see java.util.Optional
+ */
+ protected Optional getEnvironment() {
+ return Optional.ofNullable(this.environment);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public int getPhase() {
+ return resolveImportPhase();
+ }
+
+ Set getRegionsForImport() {
+ return this.regionsForImport;
+ }
+
+ /**
+ * Resolves the configured {@link ImportLifecycle}.
+ *
+ * The cache data import lifecycle is configured with the
+ * {@literal spring.boot.data.gemfire.cache.data.import.lifecycle} property
+ * in Spring Boot {@literal application.properties}.
+ *
+ * @return the configured {@link ImportLifecycle}.
+ * @see LifecycleAwareCacheDataImporterExporter.ImportLifecycle
+ */
+ protected ImportLifecycle resolveImportLifecycle() {
+
+ return resolvedImportLifecycle.updateAndGet(currentValue -> currentValue != null ? currentValue
+ : getEnvironment()
+ .map(env -> env.getProperty(CACHE_DATA_IMPORT_LIFECYCLE_PROPERTY_NAME, String.class,
+ ImportLifecycle.getDefault().name()))
+ .map(ImportLifecycle::from)
+ .orElseGet(ImportLifecycle::getDefault));
+ }
+
+ /**
+ * Resolves the configured {@link SmartLifecycleSupport#getPhase() SmartLifecycle Phase} in which the cache data
+ * import will be performed.
+ *
+ * @return the configured {@link SmartLifecycleSupport#getPhase() SmartLifecycle Phase}.
+ * @see #getPhase()
+ */
+ protected int resolveImportPhase() {
+
+ return resolvedImportPhase.updateAndGet(currentValue -> currentValue != null ? currentValue
+ : getEnvironment()
+ .map(env -> env.getProperty(CACHE_DATA_IMPORT_PHASE_PROPERTY_NAME, Integer.class, DEFAULT_IMPORT_PHASE))
+ .orElse(DEFAULT_IMPORT_PHASE));
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @NonNull @Override
+ public Region exportFrom(@NonNull Region region) {
+ return getCacheDataImporterExporter().exportFrom(region);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @NonNull @Override
+ public Region importInto(@NonNull Region region) {
+
+ if (resolveImportLifecycle().isEager()) {
+ return getCacheDataImporterExporter().importInto(region);
+ }
+ else {
+ getRegionsForImport().add(region);
+ return region;
+ }
+ }
+
+ /**
+ * Performs the cache data import for each of the targeted {@link Region Regions}.
+ */
+ @Override
+ public void start() {
+
+ // Technically, the resolveImportLifecycle().isLazy() check is not strictly required since if the cache data
+ // import is "eager", then the regionsForImport Set will be empty anyway.
+ if (resolveImportLifecycle().isLazy()) {
+ getRegionsForImport().forEach(getCacheDataImporterExporter()::importInto);
+ }
+ }
+
+ public enum ImportLifecycle {
+
+ EAGER("Imports cache data during Region bean post processing, after initialization"),
+ LAZY("Imports cache data during the appropriate phase on Lifecycle start");
+
+ private final String description;
+
+ ImportLifecycle(@NonNull String description) {
+
+ Assert.hasText(description, "The enumerated value must have a description");
+
+ this.description = description;
+ }
+
+ public static @NonNull ImportLifecycle getDefault() {
+ return LAZY;
+ }
+
+ public static @Nullable ImportLifecycle from(String name) {
+
+ for (ImportLifecycle importCycle : values()) {
+ if (importCycle.name().equalsIgnoreCase(name)) {
+ return importCycle;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean isEager() {
+ return EAGER.equals(this);
+ }
+
+ public boolean isLazy() {
+ return LAZY.equals(this);
+ }
+
+ @Override
+ public String toString() {
+ return this.description;
+ }
+ }
+}
diff --git a/spring-geode/src/test/java/org/springframework/geode/data/support/LifecycleAwareCacheDataImporterExporterUnitTests.java b/spring-geode/src/test/java/org/springframework/geode/data/support/LifecycleAwareCacheDataImporterExporterUnitTests.java
new file mode 100644
index 00000000..a0f17af5
--- /dev/null
+++ b/spring-geode/src/test/java/org/springframework/geode/data/support/LifecycleAwareCacheDataImporterExporterUnitTests.java
@@ -0,0 +1,408 @@
+/*
+ * 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.geode.data.support;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.junit.Test;
+
+import org.apache.geode.cache.Region;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.env.Environment;
+import org.springframework.geode.data.CacheDataImporterExporter;
+import org.springframework.geode.data.support.LifecycleAwareCacheDataImporterExporter.ImportLifecycle;
+
+/**
+ * Unit Tests for {@link LifecycleAwareCacheDataImporterExporter}.
+ *
+ * @author John Blum
+ * @see org.junit.Test
+ * @see org.mockito.Mockito
+ * @see org.apache.geode.cache.Region
+ * @see org.springframework.context.ApplicationContext
+ * @see org.springframework.core.env.Environment
+ * @see org.springframework.geode.data.CacheDataImporterExporter
+ * @see org.springframework.geode.data.support.LifecycleAwareCacheDataImporterExporter
+ * @since 1.3.0
+ */
+public class LifecycleAwareCacheDataImporterExporterUnitTests {
+
+ @Test
+ public void constructLifecycleAwareCacheDataImporterExporter() {
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ assertThat(importerExporter).isNotNull();
+ assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter);
+ assertThat(importerExporter.getEnvironment().orElse(null)).isNull();
+
+ verifyNoInteractions(mockImporterExporter);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void constructLifecycleAwareCacheDataImporterExporterWithNull() {
+
+ try {
+ new LifecycleAwareCacheDataImporterExporter(null);
+ }
+ catch (IllegalArgumentException expected) {
+
+ assertThat(expected).hasMessage("The CacheDataImporterExporter to decorate must not be null");
+ assertThat(expected).hasNoCause();
+
+ throw expected;
+ }
+ }
+
+ @Test
+ public void setApplicationContextOnWrappedCacheDataImporterExporter() {
+
+ ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
+
+ ApplicationContextAndEnvironmentAwareCacheDataImporterExporter mockImporterExporter =
+ mock(ApplicationContextAndEnvironmentAwareCacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter);
+
+ importerExporter.setApplicationContext(mockApplicationContext);
+ importerExporter.setApplicationContext(null);
+
+ verify(mockImporterExporter, times(1)).setApplicationContext(eq(mockApplicationContext));
+ verifyNoMoreInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void setAndGetEnvironment() {
+
+ ApplicationContextAndEnvironmentAwareCacheDataImporterExporter mockImporterExporter =
+ mock(ApplicationContextAndEnvironmentAwareCacheDataImporterExporter.class);
+
+ Environment mockEnvironment = mock(Environment.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter);
+ assertThat(importerExporter.getEnvironment().orElse(null)).isNull();
+
+ importerExporter.setEnvironment(mockEnvironment);
+
+ assertThat(importerExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment);
+
+ importerExporter.setEnvironment(null);
+
+ assertThat(importerExporter.getEnvironment().orElse(null)).isNull();
+
+ verify(mockImporterExporter, times(1)).setEnvironment(eq(mockEnvironment));
+ verifyNoMoreInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void resolveImportLifecycleCachesResultAndReturnsEager() {
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ Environment mockEnvironment = mock(Environment.class);
+
+ doReturn(ImportLifecycle.EAGER.name()).when(mockEnvironment)
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_LIFECYCLE_PROPERTY_NAME),
+ eq(String.class), eq(ImportLifecycle.getDefault().name()));
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ importerExporter.setEnvironment(mockEnvironment);
+
+ assertThat(importerExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment);
+ assertThat(importerExporter.resolveImportLifecycle()).isEqualTo(ImportLifecycle.EAGER);
+ assertThat(importerExporter.resolveImportLifecycle()).isEqualTo(ImportLifecycle.EAGER);
+
+ verify(mockEnvironment, times(1))
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_LIFECYCLE_PROPERTY_NAME),
+ eq(String.class), eq(ImportLifecycle.getDefault().name()));
+ verifyNoInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void resolveImportLifecycleCachesResultAndReturnsLazy() {
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ Environment mockEnvironment = mock(Environment.class);
+
+ doReturn("INVALID").when(mockEnvironment)
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_LIFECYCLE_PROPERTY_NAME),
+ eq(String.class), eq(ImportLifecycle.getDefault().name()));
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ importerExporter.setEnvironment(mockEnvironment);
+
+ assertThat(importerExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment);
+ assertThat(importerExporter.resolveImportLifecycle()).isEqualTo(ImportLifecycle.LAZY);
+ assertThat(importerExporter.resolveImportLifecycle()).isEqualTo(ImportLifecycle.LAZY);
+
+ verify(mockEnvironment, times(1))
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_LIFECYCLE_PROPERTY_NAME),
+ eq(String.class), eq(ImportLifecycle.getDefault().name()));
+ verifyNoInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void resolveImportPhaseCachesResultAndReturnsIntegerMinValuePlusOneMillion() {
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ Environment mockEnvironment = mock(Environment.class);
+
+ doReturn(42).when(mockEnvironment)
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_PHASE_PROPERTY_NAME),
+ eq(Integer.class), eq(LifecycleAwareCacheDataImporterExporter.DEFAULT_IMPORT_PHASE));
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ importerExporter.setEnvironment(mockEnvironment);
+
+ assertThat(importerExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment);
+ assertThat(importerExporter.resolveImportPhase()).isEqualTo(42);
+ assertThat(importerExporter.resolveImportPhase()).isEqualTo(42);
+
+ verify(mockEnvironment, times(1))
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_PHASE_PROPERTY_NAME),
+ eq(Integer.class), eq(LifecycleAwareCacheDataImporterExporter.DEFAULT_IMPORT_PHASE));
+ verifyNoInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void resolveImportPhaseCachesResultAndReturnsDefaultImportPhase() {
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ Environment mockEnvironment = mock(Environment.class);
+
+ doReturn(null).when(mockEnvironment)
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_PHASE_PROPERTY_NAME),
+ eq(Integer.class), eq(LifecycleAwareCacheDataImporterExporter.DEFAULT_IMPORT_PHASE));
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ importerExporter.setEnvironment(mockEnvironment);
+
+ assertThat(importerExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment);
+ assertThat(importerExporter.resolveImportPhase()).isEqualTo(LifecycleAwareCacheDataImporterExporter.DEFAULT_IMPORT_PHASE);
+ assertThat(importerExporter.resolveImportPhase()).isEqualTo(LifecycleAwareCacheDataImporterExporter.DEFAULT_IMPORT_PHASE);
+
+ verify(mockEnvironment, times(1))
+ .getProperty(eq(LifecycleAwareCacheDataImporterExporter.CACHE_DATA_IMPORT_PHASE_PROPERTY_NAME),
+ eq(Integer.class), eq(LifecycleAwareCacheDataImporterExporter.DEFAULT_IMPORT_PHASE));
+ verifyNoInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void exportFromRegionCallsWrappedCacheDataImporterExporterExportFrom() {
+
+ Region, ?> mockRegion = mock(Region.class);
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ new LifecycleAwareCacheDataImporterExporter(mockImporterExporter);
+
+ assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter);
+
+ importerExporter.exportFrom(mockRegion);
+
+ verify(mockImporterExporter, times(1)).exportFrom(eq(mockRegion));
+ verifyNoMoreInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void importIntoRegionCallsWrappedCacheDataImporterExporterImmediatelyWhenImportLifecycleIsEager() {
+
+ Region, ?> mockRegionOne = mock(Region.class);
+ Region, ?> mockRegionTwo = mock(Region.class);
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ spy(new LifecycleAwareCacheDataImporterExporter(mockImporterExporter));
+
+ doReturn(ImportLifecycle.EAGER).when(importerExporter).resolveImportLifecycle();
+
+ assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter);
+ assertThat(importerExporter.getRegionsForImport()).isEmpty();
+
+ importerExporter.importInto(mockRegionOne);
+ importerExporter.importInto(mockRegionTwo);
+
+ assertThat(importerExporter.getRegionsForImport()).isEmpty();
+
+ verify(mockImporterExporter, times(1)).importInto(eq(mockRegionOne));
+ verify(mockImporterExporter, times(1)).importInto(eq(mockRegionTwo));
+ verifyNoMoreInteractions(mockImporterExporter);
+ }
+
+ @Test
+ public void importIntoRegionStoresRegionReferenceWhenImportLifecycleIsLazy() {
+
+ Region, ?> mockRegionOne = mock(Region.class);
+ Region, ?> mockRegionTwo = mock(Region.class);
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ spy(new LifecycleAwareCacheDataImporterExporter(mockImporterExporter));
+
+ doReturn(ImportLifecycle.LAZY).when(importerExporter).resolveImportLifecycle();
+
+ assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter);
+ assertThat(importerExporter.getRegionsForImport()).isEmpty();
+
+ importerExporter.importInto(mockRegionOne);
+ importerExporter.importInto(mockRegionTwo);
+
+ assertThat(importerExporter.getRegionsForImport()).containsExactlyInAnyOrder(mockRegionOne, mockRegionTwo);
+
+ verify(mockImporterExporter, never()).importInto(any());
+ verifyNoMoreInteractions(mockImporterExporter);
+ verifyNoInteractions(mockRegionOne, mockRegionTwo);
+ }
+
+ @Test
+ public void startImportsIntoRegionsWhenImportLifecycleIsLazy() {
+
+ Region, ?> mockRegionOne = mock(Region.class);
+ Region, ?> mockRegionTwo = mock(Region.class);
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ spy(new LifecycleAwareCacheDataImporterExporter(mockImporterExporter));
+
+ doReturn(ImportLifecycle.LAZY).when(importerExporter).resolveImportLifecycle();
+
+ importerExporter.getRegionsForImport().add(mockRegionOne);
+ importerExporter.getRegionsForImport().add(mockRegionTwo);
+
+ assertThat(importerExporter.getRegionsForImport()).containsExactlyInAnyOrder(mockRegionOne, mockRegionTwo);
+
+ importerExporter.start();
+
+ verify(mockImporterExporter, times(1)).importInto(eq(mockRegionOne));
+ verify(mockImporterExporter, times(1)).importInto(eq(mockRegionTwo));
+ verifyNoMoreInteractions(mockImporterExporter);
+ verifyNoInteractions(mockRegionOne, mockRegionTwo);
+ }
+
+ @Test
+ public void startDoesNothingWhenImportLifecycleIsEager() {
+
+ Region, ?> mockRegionOne = mock(Region.class);
+ Region, ?> mockRegionTwo = mock(Region.class);
+
+ CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class);
+
+ LifecycleAwareCacheDataImporterExporter importerExporter =
+ spy(new LifecycleAwareCacheDataImporterExporter(mockImporterExporter));
+
+ doReturn(ImportLifecycle.EAGER).when(importerExporter).resolveImportLifecycle();
+
+ importerExporter.getRegionsForImport().add(mockRegionOne);
+ importerExporter.getRegionsForImport().add(mockRegionTwo);
+
+ assertThat(importerExporter.getRegionsForImport()).containsExactlyInAnyOrder(mockRegionOne, mockRegionTwo);
+
+ importerExporter.start();
+
+ assertThat(importerExporter.getRegionsForImport()).containsExactlyInAnyOrder(mockRegionOne, mockRegionTwo);
+
+ verify(mockImporterExporter, never()).importInto(any());
+ verifyNoInteractions(mockRegionOne, mockRegionTwo);
+ }
+
+ @Test
+ public void importLifecycleDefaultIsLazy() {
+ assertThat(ImportLifecycle.getDefault()).isEqualTo(ImportLifecycle.LAZY);
+ }
+
+ @Test
+ public void importLifecycleFromIsCaseInsensitive() {
+
+ assertThat(ImportLifecycle.from("Eager")).isEqualTo(ImportLifecycle.EAGER);
+ assertThat(ImportLifecycle.from("lazy")).isEqualTo(ImportLifecycle.LAZY);
+ }
+
+ @Test
+ public void importLifecycleFromReturnsEnum() {
+
+ for (ImportLifecycle enumeratedValue : ImportLifecycle.values()) {
+ assertThat(ImportLifecycle.from(enumeratedValue.name())).isEqualTo(enumeratedValue);
+ }
+ }
+
+ @Test
+ public void importLifecycleFromUnknownReturnsNull() {
+ assertThat(ImportLifecycle.from("UNKNOWN")).isNull();
+ }
+
+ @Test
+ public void importLifecycleIsEager() {
+ assertThat(ImportLifecycle.EAGER.isEager()).isTrue();
+ assertThat(ImportLifecycle.LAZY.isEager()).isFalse();
+ }
+
+ @Test
+ public void importLifecycleIsLazy() {
+ assertThat(ImportLifecycle.EAGER.isLazy()).isFalse();
+ assertThat(ImportLifecycle.LAZY.isLazy()).isTrue();
+ }
+
+ @Test
+ public void importLifecycleToStringIsDescriptive() {
+
+ assertThat(ImportLifecycle.EAGER.toString())
+ .isEqualTo("Imports cache data during Region bean post processing, after initialization");
+
+ assertThat(ImportLifecycle.LAZY.toString())
+ .isEqualTo("Imports cache data during the appropriate phase on Lifecycle start");
+ }
+
+ interface ApplicationContextAndEnvironmentAwareCacheDataImporterExporter
+ extends ApplicationContextAware, CacheDataImporterExporter, EnvironmentAware { }
+
+}