From 0acf8c85cb349738c1d906317be0aa3925fd1b96 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 12 Aug 2019 18:12:45 -0700 Subject: [PATCH] Add Sample Code for Near Caching. --- .../spring-geode-samples-caching-near.gradle | 36 +++++ ...eodeNearCachingClientCacheApplication.java | 70 ++++++++++ .../client/config/GeodeConfiguration.java | 120 +++++++++++++++++ .../controller/YellowPagesController.java | 90 +++++++++++++ .../app/near/caching/client/model/Person.java | 53 ++++++++ .../client/service/YellowPagesService.java | 78 +++++++++++ .../support/AbstractCacheableService.java | 71 ++++++++++ .../service/support/EmailGenerator.java | 71 ++++++++++ .../service/support/PhoneNumberGenerator.java | 72 ++++++++++ ...eodeNearCachingCacheServerApplication.java | 126 ++++++++++++++++++ .../application-client-one.properties | 4 + .../application-client-two.properties | 4 + .../resources/application-client.properties | 4 + .../resources/application-server.properties | 3 + .../src/main/resources/application.properties | 3 + 15 files changed, 805 insertions(+) create mode 100644 spring-geode-samples/caching/near/spring-geode-samples-caching-near.gradle create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/BootGeodeNearCachingClientCacheApplication.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/config/GeodeConfiguration.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/controller/YellowPagesController.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/model/Person.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/YellowPagesService.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/AbstractCacheableService.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/EmailGenerator.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/PhoneNumberGenerator.java create mode 100644 spring-geode-samples/caching/near/src/main/java/example/app/near/caching/server/BootGeodeNearCachingCacheServerApplication.java create mode 100644 spring-geode-samples/caching/near/src/main/resources/application-client-one.properties create mode 100644 spring-geode-samples/caching/near/src/main/resources/application-client-two.properties create mode 100644 spring-geode-samples/caching/near/src/main/resources/application-client.properties create mode 100644 spring-geode-samples/caching/near/src/main/resources/application-server.properties create mode 100644 spring-geode-samples/caching/near/src/main/resources/application.properties diff --git a/spring-geode-samples/caching/near/spring-geode-samples-caching-near.gradle b/spring-geode-samples/caching/near/spring-geode-samples-caching-near.gradle new file mode 100644 index 00000000..2c347ba5 --- /dev/null +++ b/spring-geode-samples/caching/near/spring-geode-samples-caching-near.gradle @@ -0,0 +1,36 @@ +plugins { + id "io.freefair.lombok" version "3.2.1" +} + +apply plugin: 'io.spring.convention.spring-sample-boot' + +description = "Spring Geode Sample demonstrating Spring's Cache Abstraction using Apache Geode as the caching provider with Near Caching." + +dependencies { + + compile project(":spring-geode-starter") + + compile project(":apache-geode-extensions") + + compile ("org.springframework.boot:spring-boot-starter-web") { + exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j" + } + + compile "org.assertj:assertj-core" + compile "org.projectlombok:lombok" + + runtime "javax.cache:cache-api" + runtime "org.springframework.boot:spring-boot-starter-jetty" + runtime "org.springframework.shell:spring-shell" + + testCompile "org.springframework.boot:spring-boot-starter-test" + + testCompile("org.springframework.data:spring-data-geode-test") { + exclude group: "org.apache.logging.log4j", module: "log4j-core" + } + +} + +bootJar { + mainClassName = 'example.app.caching.near.BootGeodeNearCachingClientCacheApplication' +} diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/BootGeodeNearCachingClientCacheApplication.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/BootGeodeNearCachingClientCacheApplication.java new file mode 100644 index 00000000..ea6b0751 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/BootGeodeNearCachingClientCacheApplication.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 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.near.caching.client; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.Pool; +import org.apache.geode.cache.client.PoolManager; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +/** + * Spring Boot application demonstrating Spring's Cache Abstraction with Apache Geode as the caching provider + * for {@literal Near Caching}. + * + * @author John Blum + * @see org.springframework.boot.SpringApplication + * @see org.springframework.boot.autoconfigure.SpringBootApplication + * @since 1.1.0 + */ +// tag::class[] +@SpringBootApplication +public class BootGeodeNearCachingClientCacheApplication { + + public static void main(String[] args) { + SpringApplication.run(BootGeodeNearCachingClientCacheApplication.class, args); + } + + // tag::application-runner[] + @Bean + public ApplicationRunner runner(@Qualifier("YellowPages") Region yellowPages) { + + return args -> { + + assertThat(yellowPages).isNotNull(); + assertThat(yellowPages.getName()).isEqualTo("YellowPages"); + assertThat(yellowPages.getInterestListRegex()).containsAnyOf(".*"); + assertThat(yellowPages.getAttributes()).isNotNull(); + assertThat(yellowPages.getAttributes().getDataPolicy()).isEqualTo(DataPolicy.NORMAL); + assertThat(yellowPages.getAttributes().getPoolName()).isEqualTo("DEFAULT"); + + Pool defaultPool = PoolManager.find("DEFAULT"); + + assertThat(defaultPool).isNotNull(); + assertThat(defaultPool.getSubscriptionEnabled()).isTrue(); + + }; + } + // end::application-runner[] +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/config/GeodeConfiguration.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/config/GeodeConfiguration.java new file mode 100644 index 00000000..fc1ef60b --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/config/GeodeConfiguration.java @@ -0,0 +1,120 @@ +/* + * Copyright 2019 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.near.caching.client.config; + +import org.apache.geode.cache.CacheListener; +import org.apache.geode.cache.EntryEvent; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.InterestResultPolicy; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientRegionShortcut; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.client.Interest; +import org.springframework.data.gemfire.client.RegexInterest; +import org.springframework.data.gemfire.config.annotation.RegionConfigurer; +import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.geode.cache.AbstractCommonEventProcessingCacheListener; + +/** + * Spring {@link Configuration} class to configure Apache Geode client {@link Region Regions} + * with interest registration on all keys. + * + * @author John Blum + * @see org.apache.geode.cache.Region + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean + * @see org.springframework.data.gemfire.client.Interest + * @see org.springframework.data.gemfire.config.annotation.EnableCachingDefinedRegions + * @see org.springframework.data.gemfire.config.annotation.RegionConfigurer + * @since 1.1.0 + */ +// tag::class[] +@Configuration +//@EnableCachingDefinedRegions(clientRegionShortcut = ClientRegionShortcut.CACHING_PROXY) +public class GeodeConfiguration { + + // TODO: Replace with the SDG `@EnableCachingDefineRegions annotation declared above (and currently commented out, + // because...) once DATAGEODE-219 is resolved. :( + // tag::region[] + @Bean("YellowPages") + public ClientRegionFactoryBean yellowPagesRegion(GemFireCache gemfireCache) { + + ClientRegionFactoryBean clientRegion = new ClientRegionFactoryBean<>(); + + clientRegion.setCache(gemfireCache); + clientRegion.setClose(false); + clientRegion.setShortcut(ClientRegionShortcut.CACHING_PROXY); + + clientRegion.setRegionConfigurers( + interestRegisteringRegionConfigurer(), + subscriptionCacheListenerRegionConfigurer() + ); + + return clientRegion; + } + // end::region[] + + // tag::interest-registration[] + @Bean + RegionConfigurer interestRegisteringRegionConfigurer() { + + return new RegionConfigurer() { + + @Override + @SuppressWarnings("unchecked") + public void configure(String beanName, ClientRegionFactoryBean clientRegion) { + + Interest interest = new RegexInterest(".*", InterestResultPolicy.NONE, + false, true); + + clientRegion.setInterests(ArrayUtils.asArray(interest)); + } + }; + } + // end::interest-registration[] + + // tag::subscription-cache-listener[] + @Bean + RegionConfigurer subscriptionCacheListenerRegionConfigurer() { + + return new RegionConfigurer() { + + @Override + @SuppressWarnings("unchecked") + public void configure(String beanName, ClientRegionFactoryBean clientRegion) { + + CacheListener subscriptionCacheListener = new AbstractCommonEventProcessingCacheListener() { + + @Override + protected void processEntryEvent(EntryEvent event, EntryEventType eventType) { + + if (event.isOriginRemote()) { + System.err.printf("[%1$s] EntryEvent for [%2$s] with value [%3$s]%n", + event.getKey(), event.getOperation(), event.getNewValue()); + } + } + }; + + clientRegion.setCacheListeners(ArrayUtils.asArray(subscriptionCacheListener)); + } + }; + } + // end::subscription-cache-listener[] +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/controller/YellowPagesController.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/controller/YellowPagesController.java new file mode 100644 index 00000000..782d403c --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/controller/YellowPagesController.java @@ -0,0 +1,90 @@ +/* + * Copyright 2019 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.near.caching.client.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import example.app.near.caching.client.model.Person; +import example.app.near.caching.client.service.YellowPagesService; + +/** + * Spring {@link RestController} class for implementing the UI to the Yellow Pages application. + * + * @author John Blum + * @see org.springframework.web.bind.annotation.GetMapping + * @see org.springframework.web.bind.annotation.RestController + * @see example.app.near.caching.client.model.Person + * @see example.app.near.caching.client.service.YellowPagesService + * @since 1.1.0 + */ +// tag::class[] +@RestController +public class YellowPagesController { + + private static final String HTML = + "Yellow Pages

%s

"; + + @Autowired + private YellowPagesService yellowPages; + + @GetMapping("/") + public String home() { + return format("Near Caching Example"); + } + + @GetMapping("/ping") + public String ping() { + return format("PONG"); + } + + @GetMapping("/yellow-pages/{name}") + public String find(@PathVariable("name") String name) { + + long t0 = System.currentTimeMillis(); + + Person person = this.yellowPages.find(name); + + return format(String.format("{ person: %s, cacheMiss: %s, latency: %d ms }", + person, this.yellowPages.isCacheMiss(), (System.currentTimeMillis() - t0))); + } + + @GetMapping("/yellow-pages/{name}/update") + public String update(@PathVariable("name") String name, + @RequestParam(name = "email", required = false) String email, + @RequestParam(name = "phoneNumber", required = false) String phoneNumber) { + + Person person = this.yellowPages.save(this.yellowPages.find(name), email, phoneNumber); + + return format(String.format("{ person: %s }", person)); + } + + @GetMapping("/yellow-pages/{name}/evict") + public String evict(@PathVariable("name") String name) { + + this.yellowPages.evict(name); + + return format(String.format("Evicted %s", name)); + } + + private String format(String value) { + return String.format(HTML, value); + } +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/model/Person.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/model/Person.java new file mode 100644 index 00000000..471c95d7 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/model/Person.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019 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.near.caching.client.model; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * {@link Person} models a person (human being). + * + * @author John Blum + * @since 1.1.0 + */ +// tag::class[] +@Getter +@EqualsAndHashCode(of = "name") +@ToString(of = { "name", "email", "phoneNumber" }) +@RequiredArgsConstructor(staticName = "newPerson") +public class Person { + + @NonNull + private String name; + + private String email; + private String phoneNumber; + + public Person withEmail(String email) { + this.email = email; + return this; + } + + public Person withPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + return this; + } +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/YellowPagesService.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/YellowPagesService.java new file mode 100644 index 00000000..f5fbcc7d --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/YellowPagesService.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019 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.near.caching.client.service; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import example.app.near.caching.client.model.Person; +import example.app.near.caching.client.service.support.AbstractCacheableService; +import example.app.near.caching.client.service.support.EmailGenerator; +import example.app.near.caching.client.service.support.PhoneNumberGenerator; + +/** + * Spring {@link Service} class implementing the Yellow Pages. + * + * @author John Blum + * @see org.springframework.cache.annotation.Cacheable + * @see org.springframework.stereotype.Service + * @see example.app.near.caching.client.model.Person + * @see example.app.near.caching.client.service.support.AbstractCacheableService + * @see example.app.near.caching.client.service.support.EmailGenerator + * @see example.app.near.caching.client.service.support.PhoneNumberGenerator + * @since 1.1.0 + */ +// tag::class[] +@Service +public class YellowPagesService extends AbstractCacheableService { + + @Cacheable(cacheNames = "YellowPages", key = "#name") + public Person find(String name) { + + this.cacheMiss.set(true); + + Person person = Person.newPerson(name) + .withEmail(EmailGenerator.generate(name, null)) + .withPhoneNumber(PhoneNumberGenerator.generate(null)); + + simulateLatency(); + + return person; + } + + @CachePut(cacheNames = "YellowPages", key = "#person.name") + public Person save(Person person, String email, String phoneNumber) { + + if (StringUtils.hasText(email)) { + person.withEmail(email); + } + + if (StringUtils.hasText(phoneNumber)) { + person.withPhoneNumber(phoneNumber); + } + + return person; + } + + @CacheEvict(cacheNames = "YellowPages") + public boolean evict(String name) { + return true; + } +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/AbstractCacheableService.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/AbstractCacheableService.java new file mode 100644 index 00000000..c2b303e8 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/AbstractCacheableService.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019 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.near.caching.client.service.support; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.springframework.stereotype.Service; + +/** + * Abstract base class for implementing cacheable {@link Service services} along with additional functionality to + * ascertain whether a cacheable operation led to a cache hit or a cache miss. + * + * @author John Blum + * @since 1.1.0 + */ +@SuppressWarnings("unused") +// tag::class[] +public abstract class AbstractCacheableService { + + protected static final int BOUNDED_MULTIPLIER = 3; + + protected static final long BASE_MILLISECONDS = 2000L; + protected static final long ONE_SECOND_IN_MILLISECONDS = 1000L; + + protected final AtomicBoolean cacheMiss = new AtomicBoolean(false); + + protected final Random multiplier = new Random(System.currentTimeMillis()); + + public boolean isCacheHit() { + return !isCacheMiss(); + } + + public boolean isCacheMiss() { + return this.cacheMiss.compareAndSet(true,false); + } + + protected long delayInMilliseconds() { + return BASE_MILLISECONDS + (ONE_SECOND_IN_MILLISECONDS * this.multiplier.nextInt(BOUNDED_MULTIPLIER)); + } + + protected boolean simulateLatency() { + return simulateLatency(delayInMilliseconds()); + } + + protected boolean simulateLatency(long milliseconds) { + + try { + Thread.sleep(milliseconds); + return true; + } + catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + return false; + } + } +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/EmailGenerator.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/EmailGenerator.java new file mode 100644 index 00000000..88f4ecc9 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/EmailGenerator.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019 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.near.caching.client.service.support; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Generates {@link String email addresses} given a person's {@link String name}. + * + * @author John Blum + * @since 1.1.0 + */ +// tag::class[] +public class EmailGenerator { + + private static final String AT_APPLE_COM = "@apple.com"; + private static final String AT_COMCAST_NET = "@comcast.net"; + private static final String AT_GMAIL_COM = "@gmail.com"; + private static final String AT_HOME_ORG = "@home.org"; + private static final String AT_MICROSOFT_COM = "@microsoft.com"; + private static final String AT_NASA_GOV = "@nasa.gov"; + private static final String AT_PIVOTAL_IO = "@pivotal.io"; + private static final String AT_YAHOO_COM = "@yahoo.com"; + + private static final List AT_EMAIL_ADDRESSES = Arrays.asList( + AT_APPLE_COM, + AT_COMCAST_NET, + AT_GMAIL_COM, + AT_HOME_ORG, + AT_MICROSOFT_COM, + AT_NASA_GOV, + AT_PIVOTAL_IO, + AT_YAHOO_COM + ); + + private static final Random index = new Random(System.currentTimeMillis()); + + public static String generate(String name, String email) { + + Assert.hasText(name, "Name is required"); + + if (!StringUtils.hasText(email)) { + + name = name.toLowerCase(); + name = StringUtils.trimAllWhitespace(name); + email = String.format("%1$s%2$s", name, + AT_EMAIL_ADDRESSES.get(index.nextInt(AT_EMAIL_ADDRESSES.size()))); + } + + return email; + } +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/PhoneNumberGenerator.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/PhoneNumberGenerator.java new file mode 100644 index 00000000..42ca2925 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/client/service/support/PhoneNumberGenerator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019 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.near.caching.client.service.support; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.apache.shiro.util.StringUtils; + +/** + * Generates random phone number using a few well-defined area codes. + * + * @author John Blum + * @since 1.1.0 + */ +// tag::class[] +public class PhoneNumberGenerator { + + private static int CALIFORNIA_AREA_CODE = 707; + private static int IOWA_AREA_CODE = 319; + private static int MONTANA_AREA_CODE = 406; + private static int NEW_YORK_AREA_CODE = 914; + private static int OREGON_AREA_CODE = 503; + private static int WASHINGTON_AREA_CODE = 206; + private static int WISCONSIN_AREA_CODE = 608; + + private static final List PHONE_NUMBER_AREA_CODES = Arrays.asList( + CALIFORNIA_AREA_CODE, + IOWA_AREA_CODE, + MONTANA_AREA_CODE, + NEW_YORK_AREA_CODE, + OREGON_AREA_CODE, + WASHINGTON_AREA_CODE, + WISCONSIN_AREA_CODE + ); + + private static final Random index = new Random(System.currentTimeMillis()); + + public static String generate(String phoneNumber) { + + if (!StringUtils.hasText(phoneNumber)) { + + phoneNumber = String.valueOf(PHONE_NUMBER_AREA_CODES.get(index.nextInt(PHONE_NUMBER_AREA_CODES.size()))) + .concat("-") + .concat(String.valueOf(index.nextInt(9))) + .concat(String.valueOf(index.nextInt(9))) + .concat(String.valueOf(index.nextInt(9))) + .concat("-") + .concat(String.valueOf(index.nextInt(9))) + .concat(String.valueOf(index.nextInt(9))) + .concat(String.valueOf(index.nextInt(9))) + .concat(String.valueOf(index.nextInt(9))); + } + + return phoneNumber; + } +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/server/BootGeodeNearCachingCacheServerApplication.java b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/server/BootGeodeNearCachingCacheServerApplication.java new file mode 100644 index 00000000..ea74ae0b --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/java/example/app/near/caching/server/BootGeodeNearCachingCacheServerApplication.java @@ -0,0 +1,126 @@ +/* + * Copyright 2019 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.near.caching.server; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.cache.server.CacheServer; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.data.gemfire.RegionAttributesFactoryBean; +import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.CacheServerApplication; +import org.springframework.data.gemfire.config.annotation.EnableLocator; +import org.springframework.data.gemfire.config.annotation.EnableManager; + +import example.app.near.caching.client.model.Person; + +/** + * Spring Boot application that configures and bootstraps an Apache Geode {@link CacheServer} application. + * + * @author John Blum + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.server.CacheServer + * @see org.springframework.boot.autoconfigure.SpringBootApplication + * @see org.springframework.boot.builder.SpringApplicationBuilder + * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication + * @see org.springframework.data.gemfire.config.annotation.EnableLocator + * @see org.springframework.data.gemfire.config.annotation.EnableManager + * @since 1.1.0 + */ +// tag::class[] +@SpringBootApplication +@CacheServerApplication +@SuppressWarnings("unused") +public class BootGeodeNearCachingCacheServerApplication { + + public static void main(String[] args) { + + new SpringApplicationBuilder(BootGeodeNearCachingCacheServerApplication.class) + .web(WebApplicationType.NONE) + .build() + .run(args); + } + + // tag::application-runner[] + @Bean + ApplicationRunner runner(@Qualifier("YellowPages") Region yellowPagesRegion) { + + return args -> { + + assertThat(yellowPagesRegion).isNotNull(); + assertThat(yellowPagesRegion.getName()).isEqualTo("YellowPages"); + assertThat(yellowPagesRegion.getAttributes()).isNotNull(); + assertThat(yellowPagesRegion.getAttributes().getDataPolicy()).isEqualTo(DataPolicy.REPLICATE); + assertThat(yellowPagesRegion.getAttributes().getEnableSubscriptionConflation()).isTrue(); + + }; + } + // end::application-runner[] + + // tag::geode-configuration[] + @Configuration + static class GeodeConfiguration { + + @Bean("YellowPages") + public ReplicatedRegionFactoryBean yellowPagesRegion(GemFireCache gemfireCache, + @Qualifier("YellowPagesAttributes") RegionAttributes exampleAttributes) { + + ReplicatedRegionFactoryBean yellowPagesRegion = + new ReplicatedRegionFactoryBean<>(); + + yellowPagesRegion.setAttributes(exampleAttributes); + yellowPagesRegion.setCache(gemfireCache); + yellowPagesRegion.setClose(false); + yellowPagesRegion.setPersistent(false); + + return yellowPagesRegion; + } + + @Bean("YellowPagesAttributes") + public RegionAttributesFactoryBean exampleRegionAttributes() { + + RegionAttributesFactoryBean yellowPagesRegionAttributes = + new RegionAttributesFactoryBean<>(); + + yellowPagesRegionAttributes.setEnableSubscriptionConflation(true); + + return yellowPagesRegionAttributes; + } + } + // end::geode-configuration[] + + // tag::locator-manager[] + @Configuration + @EnableLocator + @EnableManager(start = true) + @Profile("locator-manager") + static class LocatorManagerConfiguration { } + // end::locator-manager[] + +} +// end::class[] diff --git a/spring-geode-samples/caching/near/src/main/resources/application-client-one.properties b/spring-geode-samples/caching/near/src/main/resources/application-client-one.properties new file mode 100644 index 00000000..d46768e7 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/resources/application-client-one.properties @@ -0,0 +1,4 @@ +# Spring Boot application.properties for the Apache Geode ClientCache One application. + +server.port=8181 +spring.application.name=ClientApplicationOne diff --git a/spring-geode-samples/caching/near/src/main/resources/application-client-two.properties b/spring-geode-samples/caching/near/src/main/resources/application-client-two.properties new file mode 100644 index 00000000..72454cd8 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/resources/application-client-two.properties @@ -0,0 +1,4 @@ +# Spring Boot application.properties for the Apache Geode ClientCache Two application. + +server.port=8282 +spring.application.name=ClientApplicationTwo diff --git a/spring-geode-samples/caching/near/src/main/resources/application-client.properties b/spring-geode-samples/caching/near/src/main/resources/application-client.properties new file mode 100644 index 00000000..9535cc86 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/resources/application-client.properties @@ -0,0 +1,4 @@ +# Spring Boot application.properties for the Apache Geode ClientCache application + +spring.application.name=ClientApplication +spring.data.gemfire.pool.subscription-enabled=true diff --git a/spring-geode-samples/caching/near/src/main/resources/application-server.properties b/spring-geode-samples/caching/near/src/main/resources/application-server.properties new file mode 100644 index 00000000..01c0d2ee --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/resources/application-server.properties @@ -0,0 +1,3 @@ +# Spring Boot application.properties for the Apache Geode CacheServer application. + +spring.application.name=YellowPagesServer diff --git a/spring-geode-samples/caching/near/src/main/resources/application.properties b/spring-geode-samples/caching/near/src/main/resources/application.properties new file mode 100644 index 00000000..f42117d6 --- /dev/null +++ b/spring-geode-samples/caching/near/src/main/resources/application.properties @@ -0,0 +1,3 @@ +# Spring Boot application.properties for both the Apache Geode ClientCache and CacheServer applications. + +spring.data.gemfire.cache.log-level=config