From 3342f3226326f3ecf545d20d8be38a92853e5102 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 7 Dec 2020 08:54:29 -0800 Subject: [PATCH] Refactor the Async Inline Caching Sample code. Change the @EnableCachingDefinedRegions annotation, serverRegionShortcut attribute to RegionShortcut.REPLICATE. AEQs cannot be configured for 'LOCAL' Regions. Import the new AsyncInlineCachingRegionConfiguration declaring the Golfers Region and Template for the Peer Cache application configuration arrangement. Add 'spring.autoconfigure.exclude' on Spring Data Geode Repositories Auto-Configuration in application-server.properties. Add AsyncInlineCachingRegionConfiguration class explicilty declaring a 'Golfers' REPLICATE Region bean and a SD Template for the 'Golfers' Region. Remove the @Region mapping anotation declaration from the Golfer model class. Fix bug in the GolfCourse.withHole(..) builder method to 'add' to the List of holes rather than 'set' the par for hole, which leads to an IndexOutOfBoundsException. Replace the custom, private 'nullSafeMap(:Map)' and 'sort(:List)' methods with SDG's CollectionUtils class methods in the GolferService class. Change the 'Schedule' for the GolfTournamentService class, play() method to have an initialDelay of 5 seconds. --- ...deAsyncInlineCachingClientApplication.java | 5 +- .../inline/async/client/model/GolfCourse.java | 2 +- .../inline/async/client/model/Golfer.java | 3 - .../client/service/GolfTournamentService.java | 2 +- .../async/client/service/GolferService.java | 17 ++--- .../AsyncInlineCachingConfiguration.java | 2 +- ...AsyncInlineCachingRegionConfiguration.java | 66 +++++++++++++++++++ ...deAsyncInlineCachingServerApplication.java | 11 +--- .../resources/application-server.properties | 1 + ...ngUsingQueueBatchSizeIntegrationTests.java | 8 +-- ...ueueBatchTimeIntervalIntegrationTests.java | 8 +-- 11 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingRegionConfiguration.java diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java index ab5b43b6..ba4273d1 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/BootGeodeAsyncInlineCachingClientApplication.java @@ -34,6 +34,7 @@ import example.app.caching.inline.async.client.model.support.GolfCourseBuilder; import example.app.caching.inline.async.client.model.support.GolferBuilder; import example.app.caching.inline.async.client.service.GolfTournamentService; import example.app.caching.inline.async.config.AsyncInlineCachingConfiguration; +import example.app.caching.inline.async.config.AsyncInlineCachingRegionConfiguration; /** * {@link SpringBootApplication} class simulating a golf tournament management application. @@ -91,12 +92,12 @@ public class BootGeodeAsyncInlineCachingClientApplication { @Configuration @UseMemberName(APPLICATION_NAME) - @EnableCachingDefinedRegions(serverRegionShortcut = RegionShortcut.LOCAL) + @EnableCachingDefinedRegions(serverRegionShortcut = RegionShortcut.REPLICATE) static class GeodeConfiguration { } @PeerCacheApplication @Profile("peer-cache") - @Import(AsyncInlineCachingConfiguration.class) + @Import({ AsyncInlineCachingConfiguration.class, AsyncInlineCachingRegionConfiguration.class }) static class PeerCacheApplicationConfiguration { } } diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/GolfCourse.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/GolfCourse.java index e5601ab9..53b98c8a 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/GolfCourse.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/GolfCourse.java @@ -71,7 +71,7 @@ public class GolfCourse { assertValidHoleNumber(holeNumber); assertValidParForHole(par, holeNumber); - this.parForHole.set(indexForHole(holeNumber), par); + this.parForHole.add(indexForHole(holeNumber), par); return this; } diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/Golfer.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/Golfer.java index 8b78d7a7..7af7aa02 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/Golfer.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/model/Golfer.java @@ -19,7 +19,6 @@ import javax.persistence.Entity; import javax.persistence.Table; import org.springframework.data.annotation.Id; -import org.springframework.data.gemfire.mapping.annotation.Region; import org.springframework.util.Assert; import lombok.AccessLevel; @@ -41,14 +40,12 @@ import lombok.ToString; * @see javax.persistence.Entity * @see javax.persistence.Table * @see org.springframework.data.annotation.Id - * @see org.springframework.data.gemfire.mapping.annotation.Region * @since 1.4.0 */ @Entity @Getter @ToString(of = "name") @Table(name = "golfers") -@Region(name = "Golfers") @EqualsAndHashCode(of = "name") @NoArgsConstructor(access = AccessLevel.PROTECTED) @RequiredArgsConstructor(staticName = "newGolfer") diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolfTournamentService.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolfTournamentService.java index c6e324cf..f8786773 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolfTournamentService.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolfTournamentService.java @@ -85,7 +85,7 @@ public class GolfTournamentService implements Closeable { } @SuppressWarnings("unused") - @Scheduled(fixedRate = 2500L) + @Scheduled(initialDelay = 5000L, fixedDelay = 2500L) public void play() { GolfTournament golfTournament = this.golfTournament; diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolferService.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolferService.java index 210336ac..1cb8643f 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolferService.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/client/service/GolferService.java @@ -16,7 +16,6 @@ package example.app.caching.inline.async.client.service; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -26,6 +25,7 @@ import org.apache.geode.cache.Region; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cache.annotation.CachePut; import org.springframework.data.gemfire.GemfireTemplate; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.gemfire.util.RegionUtils; import org.springframework.stereotype.Service; import org.springframework.util.Assert; @@ -70,25 +70,16 @@ public class GolferService { public List getAllGolfersFromCache() { Map golferMap = - nullSafeMap(this.golfersTemplate.getAll(resolveKeys(this.golfersTemplate.getRegion()))); + CollectionUtils.nullSafeMap(this.golfersTemplate.getAll(resolveKeys(this.golfersTemplate.getRegion()))); - return sort(new ArrayList<>(golferMap.values())); + return CollectionUtils.sort(new ArrayList<>(golferMap.values())); } public List getAllGolfersFromDatabase() { - return sort(this.golferRepository.findAll()); - } - - private Map nullSafeMap(Map map) { - return map != null ? map : Collections.emptyMap(); + return CollectionUtils.sort(this.golferRepository.findAll()); } private Set resolveKeys(Region region) { return RegionUtils.isClient(region) ? region.keySetOnServer() : region.keySet(); } - - private > List sort(List list) { - Collections.sort(list); - return list; - } } diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingConfiguration.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingConfiguration.java index 117f3dc5..365a5d5d 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingConfiguration.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingConfiguration.java @@ -43,7 +43,7 @@ import example.app.caching.inline.async.client.repo.GolferRepository; @SuppressWarnings("unused") public class AsyncInlineCachingConfiguration { - private static final String GOLFERS_REGION_NAME = "Golfers"; + protected static final String GOLFERS_REGION_NAME = "Golfers"; @Bean @Profile("queue-batch-size") diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingRegionConfiguration.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingRegionConfiguration.java new file mode 100644 index 00000000..9cba85b6 --- /dev/null +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/config/AsyncInlineCachingRegionConfiguration.java @@ -0,0 +1,66 @@ +/* + * 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 example.app.caching.inline.async.config; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.data.gemfire.GemfireTemplate; +import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; +import org.springframework.geode.cache.AsyncInlineCachingRegionConfigurer; + +import example.app.caching.inline.async.client.model.Golfer; + +/** + * Spring {@link Configuration} class used to configure an Apache Geode cache {@link Region} + * + * @author John Blum + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean + * @see org.springframework.geode.cache.AsyncInlineCachingRegionConfigurer + * @since 1.4.0 + */ +@Configuration +@SuppressWarnings("unused") +public class AsyncInlineCachingRegionConfiguration { + + protected static final String GOLFERS_REGION_NAME = "Golfers"; + + @Bean(GOLFERS_REGION_NAME) + public ReplicatedRegionFactoryBean golfersRegion(GemFireCache gemfireCache, + AsyncInlineCachingRegionConfigurer asyncInlineCachingRegionConfigurer) { + + ReplicatedRegionFactoryBean golfersRegion = new ReplicatedRegionFactoryBean<>(); + + golfersRegion.setCache(gemfireCache); + golfersRegion.setPersistent(false); + golfersRegion.setRegionConfigurers(asyncInlineCachingRegionConfigurer); + + return golfersRegion; + } + + @Bean + @DependsOn(GOLFERS_REGION_NAME) + public GemfireTemplate golfersTemplate(GemFireCache gemfireCache) { + return new GemfireTemplate(gemfireCache.getRegion(GOLFERS_REGION_NAME)); + } +} diff --git a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/server/BootGeodeAsyncInlineCachingServerApplication.java b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/server/BootGeodeAsyncInlineCachingServerApplication.java index e6fc208d..e5083627 100644 --- a/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/server/BootGeodeAsyncInlineCachingServerApplication.java +++ b/spring-geode-samples/caching/inline-async/src/main/java/example/app/caching/inline/async/server/BootGeodeAsyncInlineCachingServerApplication.java @@ -15,19 +15,15 @@ */ package example.app.caching.inline.async.server; -import org.apache.geode.cache.RegionShortcut; - import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Profile; import org.springframework.data.gemfire.config.annotation.CacheServerApplication; -import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions; -import example.app.caching.inline.async.client.model.Golfer; import example.app.caching.inline.async.config.AsyncInlineCachingConfiguration; +import example.app.caching.inline.async.config.AsyncInlineCachingRegionConfiguration; /** * {@link SpringBootApplication} class implementing the server-side of the golf tournament management application. @@ -36,7 +32,6 @@ import example.app.caching.inline.async.config.AsyncInlineCachingConfiguration; * @see java.time.Duration * @see org.springframework.boot.autoconfigure.SpringBootApplication * @see org.springframework.boot.builder.SpringApplicationBuilder - * @see org.springframework.context.annotation.Configuration * @see org.springframework.context.annotation.Import * @see org.springframework.context.annotation.Profile * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication @@ -59,10 +54,8 @@ public class BootGeodeAsyncInlineCachingServerApplication { .run(args); } - @Configuration @CacheServerApplication(name = APPLICATION_NAME) - @EnableEntityDefinedRegions(basePackageClasses = Golfer.class, serverRegionShortcut = RegionShortcut.LOCAL) - @Import(AsyncInlineCachingConfiguration.class) + @Import({ AsyncInlineCachingConfiguration.class, AsyncInlineCachingRegionConfiguration.class }) @SuppressWarnings("unused") static class GeodeConfiguration { } diff --git a/spring-geode-samples/caching/inline-async/src/main/resources/application-server.properties b/spring-geode-samples/caching/inline-async/src/main/resources/application-server.properties index 1ee7d8ef..314fdf8e 100644 --- a/spring-geode-samples/caching/inline-async/src/main/resources/application-server.properties +++ b/spring-geode-samples/caching/inline-async/src/main/resources/application-server.properties @@ -1,5 +1,6 @@ # Spring Boot application.properties configuration for the golfer server application. # RBMS (Database) configuration properties. +#spring.autoconfigure.exclude=org.springframework.geode.boot.autoconfigure.RepositoriesAutoConfiguration spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=none diff --git a/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_size/AsyncInlineCachingUsingQueueBatchSizeIntegrationTests.java b/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_size/AsyncInlineCachingUsingQueueBatchSizeIntegrationTests.java index 0612d06f..5059c753 100644 --- a/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_size/AsyncInlineCachingUsingQueueBatchSizeIntegrationTests.java +++ b/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_size/AsyncInlineCachingUsingQueueBatchSizeIntegrationTests.java @@ -30,7 +30,6 @@ import org.junit.runner.RunWith; import org.apache.geode.cache.Cache; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.Region; -import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.asyncqueue.AsyncEventQueue; @@ -42,7 +41,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.data.gemfire.GemfireTemplate; -import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions; import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport; import org.springframework.data.gemfire.tests.util.ReflectionUtils; @@ -57,6 +55,7 @@ import example.app.caching.inline.async.client.model.Golfer; import example.app.caching.inline.async.client.repo.GolferRepository; import example.app.caching.inline.async.client.service.GolferService; import example.app.caching.inline.async.config.AsyncInlineCachingConfiguration; +import example.app.caching.inline.async.config.AsyncInlineCachingRegionConfiguration; /** * Integration Tests for Spring Boot configured Async Inline Caching with Apache Geode using Queue Batch Size. @@ -197,10 +196,9 @@ public class AsyncInlineCachingUsingQueueBatchSizeIntegrationTests extends Integ @PeerCacheApplication @EnableAutoConfiguration - @EnableEntityDefinedRegions(basePackageClasses = Golfer.class, serverRegionShortcut = RegionShortcut.REPLICATE) - @EnableJpaRepositories(basePackageClasses = GolferRepository.class) @EntityScan(basePackageClasses = Golfer.class) - @Import(AsyncInlineCachingConfiguration.class) + @EnableJpaRepositories(basePackageClasses = GolferRepository.class) + @Import({ AsyncInlineCachingConfiguration.class, AsyncInlineCachingRegionConfiguration.class }) static class TestConfiguration { @Bean diff --git a/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_time_interval/AsyncInlineCachingUsingQueueBatchTimeIntervalIntegrationTests.java b/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_time_interval/AsyncInlineCachingUsingQueueBatchTimeIntervalIntegrationTests.java index 25e1d3f9..cb8ae2d9 100644 --- a/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_time_interval/AsyncInlineCachingUsingQueueBatchTimeIntervalIntegrationTests.java +++ b/spring-geode-samples/caching/inline-async/src/test/java/example/app/caching/inline/async/queue_batch_time_interval/AsyncInlineCachingUsingQueueBatchTimeIntervalIntegrationTests.java @@ -30,7 +30,6 @@ import org.junit.runner.RunWith; import org.apache.geode.cache.Cache; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.Region; -import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.asyncqueue.AsyncEventQueue; @@ -42,7 +41,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.data.gemfire.GemfireTemplate; -import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions; import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport; import org.springframework.data.gemfire.tests.util.ReflectionUtils; @@ -57,6 +55,7 @@ import example.app.caching.inline.async.client.model.Golfer; import example.app.caching.inline.async.client.repo.GolferRepository; import example.app.caching.inline.async.client.service.GolferService; import example.app.caching.inline.async.config.AsyncInlineCachingConfiguration; +import example.app.caching.inline.async.config.AsyncInlineCachingRegionConfiguration; /** * Integration Tests for Spring Boot configured Async Inline Caching with Apache Geode using Queue Batch Time Interval. @@ -179,10 +178,9 @@ public class AsyncInlineCachingUsingQueueBatchTimeIntervalIntegrationTests exten @PeerCacheApplication @EnableAutoConfiguration - @EnableEntityDefinedRegions(basePackageClasses = Golfer.class, serverRegionShortcut = RegionShortcut.REPLICATE) - @EnableJpaRepositories(basePackageClasses = GolferRepository.class) @EntityScan(basePackageClasses = Golfer.class) - @Import(AsyncInlineCachingConfiguration.class) + @EnableJpaRepositories(basePackageClasses = GolferRepository.class) + @Import({ AsyncInlineCachingConfiguration.class, AsyncInlineCachingRegionConfiguration.class }) static class TestConfiguration { @Bean