diff --git a/src/main/java/org/springframework/data/gemfire/cache/config/EnableGemfireCaching.java b/src/main/java/org/springframework/data/gemfire/cache/config/EnableGemfireCaching.java new file mode 100644 index 00000000..6008f87a --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/cache/config/EnableGemfireCaching.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire.cache.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Import; + +/** + * The {@link EnableGemfireCaching} annotation enables Pivotal GemFire or Apache Geode as a caching provider + * in Spring's Cache Abstraction. + * + * @author John Blum + * @see java.lang.annotation.Documented + * @see java.lang.annotation.Inherited + * @see java.lang.annotation.Retention + * @see java.lang.annotation.Target + * @see org.springframework.context.annotation.Import + * @see Cache Abstraction + * @see GemFire-based Cache + * @see Support for Spring Cache Abstraction + * @since 2.0.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Import(GemfireCachingConfiguration.class) +@SuppressWarnings("unused") +public @interface EnableGemfireCaching { + +} diff --git a/src/main/java/org/springframework/data/gemfire/cache/config/GemfireCachingConfiguration.java b/src/main/java/org/springframework/data/gemfire/cache/config/GemfireCachingConfiguration.java new file mode 100644 index 00000000..b9467b81 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/cache/config/GemfireCachingConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire.cache.config; + +import org.apache.geode.cache.GemFireCache; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.gemfire.cache.GemfireCacheManager; + +/** + * The {@link GemfireCachingConfiguration} class is a Spring {@link Configuration @Configuration} class + * used to configure Pivotal GemFire or Apache Geode as the caching provider in Spring's Cache Abstraction. + * + * Additionally, this Spring {@link Configuration} class also enables the Spring Cache Abstraction + * with {@link EnableCaching}. + * + * @author John Blum + * @see org.apache.geode.cache.GemFireCache + * @see org.springframework.cache.annotation.EnableCaching + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.data.gemfire.cache.GemfireCacheManager + * @see org.springframework.data.gemfire.cache.config.EnableGemfireCaching + * @see Cache Abstraction + * @see GemFire-based Cache + * @see Support for Spring Cache Abstraction + * @since 2.0.0 + */ +@Configuration +@EnableCaching +@SuppressWarnings("unused") +public class GemfireCachingConfiguration { + + /** + * SDG's {@link GemfireCacheManager} used to position Pivotal GemFire or Apache Geode as the caching provider + * in Spring's Cache Abstraction. + * + * @return an instance of {@link GemfireCacheManager}. + * @see org.springframework.data.gemfire.cache.GemfireCacheManager + * @see org.apache.geode.cache.GemFireCache + */ + @Bean + public GemfireCacheManager cacheManager(GemFireCache gemfireCache) { + + GemfireCacheManager gemfireCacheManager = new GemfireCacheManager(); + + gemfireCacheManager.setCache(gemfireCache); + + return gemfireCacheManager; + } +} diff --git a/src/test/java/org/springframework/data/gemfire/cache/config/EnableGemfireCachingIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/cache/config/EnableGemfireCachingIntegrationTests.java new file mode 100644 index 00000000..3a90301f --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/cache/config/EnableGemfireCachingIntegrationTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 2017 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire.cache.config; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +import javax.annotation.Resource; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; +import org.apache.shiro.util.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.cache.GemfireCacheManager; +import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; +import org.springframework.stereotype.Service; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration tests for {@link EnableGemfireCaching} and {@link GemfireCachingConfiguration}. + * + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.apache.geode.cache.GemFireCache + * @see org.springframework.cache.annotation.Cacheable + * @see org.springframework.context.annotation.Bean + * @see org.springframework.data.gemfire.cache.config.EnableGemfireCaching + * @see org.springframework.data.gemfire.cache.config.GemfireCachingConfiguration + * @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 2.0.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class EnableGemfireCachingIntegrationTests { + + @Autowired + private CalculatorService calculator; + + @Autowired + @SuppressWarnings("unused") + private GemfireCacheManager gemfireCacheManager; + + @Test + public void gemfireCacheManagerIsConfigured() { + assertThat(this.gemfireCacheManager).isNotNull(); + } + + @Test + public void enableGemfireCachingIsSuccessful() { + + assertThat(calculator.isCacheMiss()).isFalse(); + assertThat(calculator.factorial(0L)).isEqualTo(1L); + assertThat(calculator.isCacheMiss()).isTrue(); + assertThat(calculator.factorial(1L)).isEqualTo(1L); + assertThat(calculator.isCacheMiss()).isTrue(); + assertThat(calculator.factorial(2L)).isEqualTo(2L); + assertThat(calculator.isCacheMiss()).isTrue(); + assertThat(calculator.factorial(0L)).isEqualTo(1L); + assertThat(calculator.isCacheMiss()).isFalse(); + assertThat(calculator.factorial(1L)).isEqualTo(1L); + assertThat(calculator.isCacheMiss()).isFalse(); + assertThat(calculator.factorial(2L)).isEqualTo(2L); + assertThat(calculator.isCacheMiss()).isFalse(); + assertThat(calculator.factorial(3L)).isEqualTo(6L); + assertThat(calculator.isCacheMiss()).isTrue(); + assertThat(calculator.factorial(4L)).isEqualTo(24L); + assertThat(calculator.isCacheMiss()).isTrue(); + assertThat(calculator.factorial(5L)).isEqualTo(120L); + assertThat(calculator.isCacheMiss()).isTrue(); + } + + @Service + static class CalculatorService { + + private volatile boolean cacheMiss; + + @Resource(name = "Factorials") + private Region factorials; + + public boolean isCacheMiss() { + boolean cacheMiss = this.cacheMiss; + this.cacheMiss = false; + return cacheMiss; + } + + @Cacheable("Factorials") + public Long factorial(Long number) { + + Assert.notNull(number, "Number to compute the factorial of must not be null"); + + Assert.isTrue(number > -1, + String.format("Number [%d] must be greater than equal to 0", number)); + + cacheMiss = true; + + if (number < 3) { + return (number > 1L ? 2L : 1L); + } + + long result = number; + + while (number-- > 1) { + result *= number; + } + + return result; + } + } + + @EnableGemfireCaching + @PeerCacheApplication(name = "EnableGemfireCachingIntegrationTests", logLevel = "warning") + @SuppressWarnings("unused") + static class TestConfiguration { + + @Bean + CalculatorService calculatorService() { + return new CalculatorService(); + } + + @Bean("Factorials") + LocalRegionFactoryBean factorialsRegion(GemFireCache gemfireCache) { + + LocalRegionFactoryBean factorials = new LocalRegionFactoryBean<>(); + + factorials.setCache(gemfireCache); + factorials.setClose(false); + factorials.setPersistent(false); + + return factorials; + } + } +}