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 index b759e3c1..303d9767 100644 --- 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 @@ -23,26 +23,37 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.geode.cache.Region; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EnvironmentAware; import org.springframework.context.Lifecycle; +import org.springframework.context.ResourceLoaderAware; import org.springframework.core.env.Environment; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; import org.springframework.data.gemfire.support.SmartLifecycleSupport; +import org.springframework.geode.core.io.ResourceReader; +import org.springframework.geode.core.io.ResourceResolver; +import org.springframework.geode.core.io.ResourceWriter; import org.springframework.geode.data.CacheDataImporterExporter; +import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ExportResourceResolver; +import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver; 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. + * an existing {@link CacheDataImporterExporter} in order to {@literal decorate} the cache (i.e. {@link Region}) data + * import & export operations, making them Spring {@link ApplicationContext}, {@link Environment}, {@link Lifecycle}, + * {@link ResourceLoader} 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, + * This wrapper {@literal decorates} the Apache Geode cache {@link Region} data import operation enabling it + * to be configured {@link ImportLifecycle#EAGER eagerly}, after the {@link Region} bean as been initialized, * or {@link ImportLifecycle#LAZY lazily}, once all beans have been fully initialized and the Spring - * {@link ApplicationContext} refreshed. + * {@link ApplicationContext} is refreshed. * * @author John Blum * @see org.apache.geode.cache.Region @@ -50,15 +61,22 @@ import org.springframework.util.Assert; * @see org.springframework.context.ApplicationContextAware * @see org.springframework.context.EnvironmentAware * @see org.springframework.context.Lifecycle + * @see org.springframework.context.ResourceLoaderAware * @see org.springframework.core.env.Environment + * @see org.springframework.core.io.ResourceLoader * @see org.springframework.data.gemfire.support.SmartLifecycleSupport + * @see org.springframework.geode.core.io.ResourceReader + * @see org.springframework.geode.core.io.ResourceResolver + * @see org.springframework.geode.core.io.ResourceWriter * @see org.springframework.geode.data.CacheDataImporterExporter + * @see org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ExportResourceResolver + * @see org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver * @see Decorator Software Design Pattern * @since 1.3.0 */ @SuppressWarnings("rawtypes") -public class LifecycleAwareCacheDataImporterExporter - implements ApplicationContextAware, CacheDataImporterExporter, EnvironmentAware, SmartLifecycleSupport { +public class LifecycleAwareCacheDataImporterExporter implements CacheDataImporterExporter, + ApplicationContextAware, EnvironmentAware, InitializingBean, ResourceLoaderAware, SmartLifecycleSupport { protected static final int DEFAULT_IMPORT_PHASE = Integer.MIN_VALUE + 1000000; @@ -94,6 +112,22 @@ public class LifecycleAwareCacheDataImporterExporter this.importerExporter = importerExporter; } + /** + * Initializes the wrapped {@link CacheDataImporterExporter} if the importer/exporter + * implements {@link InitializingBean}. + * + * @throws Exception if {@link CacheDataImporterExporter} initialization fails. + */ + @Override + public void afterPropertiesSet() throws Exception { + + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof InitializingBean) { + ((InitializingBean) importerExporter).afterPropertiesSet(); + } + } + /** * Configures a reference to the Spring {@link ApplicationContext}. * @@ -101,12 +135,15 @@ public class LifecycleAwareCacheDataImporterExporter * @see org.springframework.context.ApplicationContext */ @Override - public void setApplicationContext(ApplicationContext applicationContext) { + public void setApplicationContext(@Nullable ApplicationContext applicationContext) { - CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + if (applicationContext != null) { - if (applicationContext != null && importerExporter instanceof ApplicationContextAware) { - ((ApplicationContextAware) importerExporter).setApplicationContext(applicationContext); + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof ApplicationContextAware) { + ((ApplicationContextAware) importerExporter).setApplicationContext(applicationContext); + } } } @@ -122,26 +159,29 @@ public class LifecycleAwareCacheDataImporterExporter } /** - * Configures a reference to the {@link Environment} used to access the configuration for the behavior of + * Configures a reference to the {@link Environment} used to access 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) { + public void setEnvironment(@Nullable Environment environment) { this.environment = environment; - CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + if (environment != null) { - if (environment != null && importerExporter instanceof EnvironmentAware) { - ((EnvironmentAware) importerExporter).setEnvironment(environment); + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof EnvironmentAware) { + ((EnvironmentAware) importerExporter).setEnvironment(environment); + } } } /** - * Returns an {@link Optional}, configured reference to the {@link Environment} used to access the configuration + * Returns an {@link Optional} reference to the configured {@link Environment} used to access 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()}. @@ -156,6 +196,52 @@ public class LifecycleAwareCacheDataImporterExporter return Optional.ofNullable(this.environment); } + /** + * Configures the {@link ExportResourceResolver} of the wrapped {@link CacheDataImporterExporter} + * if the {@link ExportResourceResolver} is not {@literal null} and the {@link CacheDataImporterExporter} + * is {@link Resource} capable. + * + * @param exportResourceResolver {@link ResourceResolver} used to resolve a {@link Resource} for {@literal export}. + * @see org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ExportResourceResolver + * @see #getCacheDataImporterExporter() + */ + @Autowired(required = false) + public void setExportResourceResolver(@Nullable ExportResourceResolver exportResourceResolver) { + + if (exportResourceResolver != null) { + + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof ResourceCapableCacheDataImporterExporter) { + ((ResourceCapableCacheDataImporterExporter) importerExporter) + .setExportResourceResolver(exportResourceResolver); + } + } + } + + /** + * Configures the {@link ImportResourceResolver} of the wrapped {@link CacheDataImporterExporter} + * if the {@link ImportResourceResolver} is not {@literal null} and the {@link CacheDataImporterExporter} + * is {@link Resource} capable. + * + * @param importResourceResolver {@link ResourceResolver} used to resolve a {@link Resource} for {@literal import}. + * @see org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver + * @see #getCacheDataImporterExporter() + */ + @Autowired(required = false) + public void setImportResourceResolver(@Nullable ImportResourceResolver importResourceResolver) { + + if (importResourceResolver != null) { + + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof ResourceCapableCacheDataImporterExporter) { + ((ResourceCapableCacheDataImporterExporter) importerExporter) + .setImportResourceResolver(importResourceResolver); + } + } + } + /** * @inheritDoc */ @@ -164,10 +250,100 @@ public class LifecycleAwareCacheDataImporterExporter return resolveImportPhase(); } - Set getRegionsForImport() { + /** + * Returns the {@link Set} of {@link Region Regions} to import data into. + * + * @return a {@link Set} of {@link Region Regions} to evaluate on import; never {@literal null}. + * @see org.apache.geode.cache.Region + * @see java.util.Set + */ + @NonNull Set getRegionsForImport() { return this.regionsForImport; } + /** + * @inheritDoc + */ + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + + if (resourceLoader != null) { + + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof ResourceLoaderAware) { + ((ResourceLoaderAware) importerExporter).setResourceLoader(resourceLoader); + } + } + } + + /** + * Configures the {@link ResourceReader} of the wrapped {@link CacheDataImporterExporter} + * if the {@link ResourceReader} is not {@literal null} and the {@link CacheDataImporterExporter} + * is {@link Resource} capable. + * + * @param resourceReader {@link ResourceReader} used to read data from a {@link Resource} on {@literal import}. + * @see org.springframework.geode.core.io.ResourceReader + * @see #getCacheDataImporterExporter() + */ + @Autowired(required = false) + public void setResourceReader(@Nullable ResourceReader resourceReader) { + + if (resourceReader != null) { + + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof ResourceCapableCacheDataImporterExporter) { + ((ResourceCapableCacheDataImporterExporter) importerExporter).setResourceReader(resourceReader); + } + } + } + + /** + * Configures the {@link ResourceWriter} of the wrapped {@link CacheDataImporterExporter} + * if the {@link ResourceWriter} is not {@literal null} and the {@link CacheDataImporterExporter} + * is {@link Resource} capable. + * + * @param resourceWriter {@link ResourceWriter} used to write data to a {@link Resource} on {@literal export}. + * @see org.springframework.geode.core.io.ResourceWriter + * @see #getCacheDataImporterExporter() + */ + @Autowired(required = false) + public void setResourceWriter(@Nullable ResourceWriter resourceWriter) { + + if (resourceWriter != null) { + + CacheDataImporterExporter importerExporter = getCacheDataImporterExporter(); + + if (importerExporter instanceof ResourceCapableCacheDataImporterExporter) { + ((ResourceCapableCacheDataImporterExporter) importerExporter).setResourceWriter(resourceWriter); + } + } + } + + /** + * @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; + } + } + /** * Resolves the configured {@link ImportLifecycle}. * @@ -203,31 +379,11 @@ public class LifecycleAwareCacheDataImporterExporter .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}. + * + * @see #getCacheDataImporterExporter() + * @see #getRegionsForImport() */ @Override public void start() { @@ -239,6 +395,9 @@ public class LifecycleAwareCacheDataImporterExporter } } + /** + * An {@link Enum Enumeration} defining the different modes for the cache data import lifecycle. + */ public enum ImportLifecycle { EAGER("Imports cache data during Region bean post processing, after initialization"), 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 index a0f17af5..6d54efac 100644 --- 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 @@ -34,9 +34,15 @@ 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.ResourceLoaderAware; import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.geode.core.io.ResourceReader; +import org.springframework.geode.core.io.ResourceWriter; import org.springframework.geode.data.CacheDataImporterExporter; import org.springframework.geode.data.support.LifecycleAwareCacheDataImporterExporter.ImportLifecycle; +import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ExportResourceResolver; +import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver; /** * Unit Tests for {@link LifecycleAwareCacheDataImporterExporter}. @@ -84,51 +90,463 @@ public class LifecycleAwareCacheDataImporterExporterUnitTests { } @Test - public void setApplicationContextOnWrappedCacheDataImporterExporter() { + public void setApplicationContextOnWrappedApplicationContextAwareCacheDataImporterExporter() { ApplicationContext mockApplicationContext = mock(ApplicationContext.class); - ApplicationContextAndEnvironmentAwareCacheDataImporterExporter mockImporterExporter = - mock(ApplicationContextAndEnvironmentAwareCacheDataImporterExporter.class); + ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter mockImporterExporter = + mock(ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter.class); - LifecycleAwareCacheDataImporterExporter importerExporter = + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); - assertThat(importerExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); - importerExporter.setApplicationContext(mockApplicationContext); - importerExporter.setApplicationContext(null); + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setApplicationContext(mockApplicationContext); + lifecycleImporterExporter.setApplicationContext(null); + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); verify(mockImporterExporter, times(1)).setApplicationContext(eq(mockApplicationContext)); verifyNoMoreInteractions(mockImporterExporter); } + @Test + public void setApplicationContextDoesNotConfigureWrappedNonApplicationContextAwareCacheDataImporterExporter() { + + ApplicationContext mockApplicationContext = mock(ApplicationContext.class); + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setApplicationContext(mockApplicationContext); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockApplicationContext, mockImporterExporter); + } + @Test public void setAndGetEnvironment() { - ApplicationContextAndEnvironmentAwareCacheDataImporterExporter mockImporterExporter = - mock(ApplicationContextAndEnvironmentAwareCacheDataImporterExporter.class); + ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter mockImporterExporter = + mock(ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter.class); Environment mockEnvironment = mock(Environment.class); + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + assertThat(lifecycleImporterExporter.getEnvironment().orElse(null)).isNull(); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setEnvironment(mockEnvironment); + + assertThat(lifecycleImporterExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment); + + lifecycleImporterExporter.setEnvironment(null); + + assertThat(lifecycleImporterExporter.getEnvironment().orElse(null)).isNull(); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verify(mockImporterExporter, times(1)).setEnvironment(eq(mockEnvironment)); + verifyNoMoreInteractions(mockImporterExporter); + } + + @Test + public void setEnvironmentDoesNotConfigureWrappedNonEnvironmentAwareCacheDataImporterExporter() { + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + Environment mockEnvironment = mock(Environment.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + assertThat(lifecycleImporterExporter.getEnvironment().orElse(null)).isNull(); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setEnvironment(mockEnvironment); + + assertThat(lifecycleImporterExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter); + } + + @Test + public void setExportResourceResolverConfiguresWrappedResourceCapableCacheDataImporterExporter() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + ExportResourceResolver mockExportResourceResolver = mock(ExportResourceResolver.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setExportResourceResolver(mockExportResourceResolver); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verify(mockImporterExporter, times(1)) + .setExportResourceResolver(eq(mockExportResourceResolver)); + verifyNoMoreInteractions(mockImporterExporter); + verifyNoInteractions(mockExportResourceResolver); + } + + @Test + public void setExportResourceResolverDoesNotConfigureWrappedNonResourceCapableCacheDataImporterExporter() { + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + ExportResourceResolver mockExportResourceResolver = mock(ExportResourceResolver.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setExportResourceResolver(mockExportResourceResolver); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockExportResourceResolver, mockImporterExporter); + } + + @Test + public void setExportResourceResolverWithNull() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setExportResourceResolver(null); + + verify(lifecycleImporterExporter, never()).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter); + } + + @Test + public void setImportResourceResolverConfiguresWrappedResourceCapableCacheDataImporterExporter() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + ImportResourceResolver mockImportResourceResolver = mock(ImportResourceResolver.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setImportResourceResolver(mockImportResourceResolver); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verify(mockImporterExporter, times(1)) + .setImportResourceResolver(eq(mockImportResourceResolver)); + verifyNoMoreInteractions(mockImporterExporter); + verifyNoInteractions(mockImportResourceResolver); + } + + @Test + public void setImportResourceResolverDoesNotConfigureWrappedNonResourceCapableCacheDataImporterExporter() { + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + ImportResourceResolver mockImportResourceResolver = mock(ImportResourceResolver.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setImportResourceResolver(mockImportResourceResolver); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockImportResourceResolver, mockImporterExporter); + } + + @Test + public void setImportResourceResolverWithNull() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setImportResourceResolver(null); + + verify(lifecycleImporterExporter, never()).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter); + } + + @Test + public void setResourceLoaderConfiguresWrappedResourceLoaderAwareCacheDataImporterExporter() { + + ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter mockImporterExporter = + mock(ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter.class); + + ResourceLoader mockResourceLoader = mock(ResourceLoader.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceLoader(mockResourceLoader); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verify(mockImporterExporter, times(1)).setResourceLoader(eq(mockResourceLoader)); + verifyNoMoreInteractions(mockImporterExporter); + verifyNoInteractions(mockResourceLoader); + } + + @Test + public void setResourceLoaderDoesNotConfigureWrappedNonResourceLoaderAwareCacheDataImporterExporter() { + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + ResourceLoader mockResourceLoader = mock(ResourceLoader.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceLoader(mockResourceLoader); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockResourceLoader, mockImporterExporter); + } + + @Test + public void setResourceLoaderWithNull() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceLoader(null); + + verify(lifecycleImporterExporter, never()).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter); + } + + @Test + public void setResourceReaderConfiguresWrappedResourceCapableCacheDataImporterExporter() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + ResourceReader mockResourceReader = mock(ResourceReader.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceReader(mockResourceReader); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verify(mockImporterExporter, times(1)).setResourceReader(eq(mockResourceReader)); + verifyNoMoreInteractions(mockImporterExporter); + verifyNoInteractions(mockResourceReader); + } + + @Test + public void setResourceReaderDoesNotConfigureWrappedNonResourceCapableCacheDataImporterExporter() { + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + ResourceReader mockResourceReader = mock(ResourceReader.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceReader(mockResourceReader); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter, mockResourceReader); + } + + @Test + public void setResourceReaderWithNull() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceReader(null); + + verify(lifecycleImporterExporter, never()).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter); + } + + @Test + public void setResourceWriterConfiguresWrappedResourceCapableCacheDataImporterExporter() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + ResourceWriter mockResourceWriter = mock(ResourceWriter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceWriter(mockResourceWriter); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verify(mockImporterExporter, times(1)).setResourceWriter(eq(mockResourceWriter)); + verifyNoMoreInteractions(mockImporterExporter); + verifyNoInteractions(mockResourceWriter); + } + + @Test + public void setResourceWriterDoesNotConfigureWrappedNonResourceCapableCacheDataImporterExporter() { + + CacheDataImporterExporter mockImporterExporter = mock(CacheDataImporterExporter.class); + + ResourceWriter mockResourceWriter = mock(ResourceWriter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceWriter(mockResourceWriter); + + verify(lifecycleImporterExporter, times(1)).getCacheDataImporterExporter(); + verifyNoInteractions(mockImporterExporter, mockResourceWriter); + } + + @Test + public void setResourceWriterWithNull() { + + TestResourceCapableCacheDataImporterExporter mockImporterExporter = + mock(TestResourceCapableCacheDataImporterExporter.class); + + LifecycleAwareCacheDataImporterExporter lifecycleImporterExporter = + new LifecycleAwareCacheDataImporterExporter(mockImporterExporter); + + assertThat(lifecycleImporterExporter.getCacheDataImporterExporter()).isEqualTo(mockImporterExporter); + + lifecycleImporterExporter = spy(lifecycleImporterExporter); + lifecycleImporterExporter.setResourceWriter(null); + + verify(lifecycleImporterExporter, never()).getCacheDataImporterExporter(); + 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); - assertThat(importerExporter.getEnvironment().orElse(null)).isNull(); - importerExporter.setEnvironment(mockEnvironment); + importerExporter.exportFrom(mockRegion); - assertThat(importerExporter.getEnvironment().orElse(null)).isEqualTo(mockEnvironment); - - importerExporter.setEnvironment(null); - - assertThat(importerExporter.getEnvironment().orElse(null)).isNull(); - - verify(mockImporterExporter, times(1)).setEnvironment(eq(mockEnvironment)); + 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 resolveImportLifecycleCachesResultAndReturnsEager() { @@ -233,76 +651,6 @@ public class LifecycleAwareCacheDataImporterExporterUnitTests { 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() { @@ -402,7 +750,10 @@ public class LifecycleAwareCacheDataImporterExporterUnitTests { .isEqualTo("Imports cache data during the appropriate phase on Lifecycle start"); } - interface ApplicationContextAndEnvironmentAwareCacheDataImporterExporter - extends ApplicationContextAware, CacheDataImporterExporter, EnvironmentAware { } + interface ApplicationContextEnvironmentAndResourceLoaderAwareCacheDataImporterExporter + extends ApplicationContextAware, CacheDataImporterExporter, EnvironmentAware, ResourceLoaderAware { } + + abstract static class TestResourceCapableCacheDataImporterExporter + extends ResourceCapableCacheDataImporterExporter { } }