diff --git a/build.gradle b/build.gradle
index 0f50a274..85e4b6d0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,6 +52,17 @@ if (project.hasProperty('platformVersion')) {
}
}
+sourceSets {
+ main {
+ output.resourcesDir = 'build/classes/main'
+ output.classesDir = 'build/classes/main'
+ }
+ test {
+ output.resourcesDir = 'build/classes/test'
+ output.classesDir = 'build/classes/test'
+ }
+}
+
[compileJava, compileTestJava]*.options*.compilerArgs = ["-Xlint:-serial"]
// Common dependencies
@@ -74,6 +85,7 @@ dependencies {
exclude group: "com.fasterxml.jackson.core", module: "jackson-annotations"
exclude group: "com.fasterxml.jackson.core", module: "jackson-core"
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
+ exclude group: "org.apache.hbase", module: "hbase"
exclude group: "org.slf4j", module: "slf4j-api"
exclude group: "org.springframework", module: "spring-aop"
exclude group: "org.springframework", module: "spring-beans"
@@ -90,6 +102,7 @@ dependencies {
optional("com.google.code.findbugs:annotations:2.0.2")
runtime("antlr:antlr:$antlrVersion")
+ optional "javax.enterprise:cdi-api:$cdiVersion"
compile "org.aspectj:aspectjweaver:$aspectjVersion"
compile "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
@@ -103,11 +116,15 @@ dependencies {
testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
testCompile "org.mockito:mockito-core:$mockitoVersion"
testCompile "edu.umd.cs.mtc:multithreadedtc:$multiThreadedtcVersion"
+ testCompile "org.apache.openwebbeans.test:cditest-owb:$openwebbeansVersion"
testCompile "javax.annotation:jsr250-api:1.0", optional
+ testRuntime "javax.el:el-api:$cdiVersion"
+ testRuntime "javax.servlet:servlet-api:$servletApiVersion"
testRuntime "log4j:log4j:$log4jVersion"
testRuntime "org.apache.derby:derbyLocale_zh_TW:10.9.1.0"
testRuntime "org.slf4j:slf4j-log4j12:$slf4jVersion"
+ testRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
sharedResources "org.springframework.data.build:spring-data-build-resources:$springDataBuildVersion@zip"
}
diff --git a/gradle.properties b/gradle.properties
index 59b18f77..b7990378 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,12 +1,15 @@
antlrVersion=2.7.7
aspectjVersion=1.8.5
-gemfireVersion=1.0.0-incubating-SNAPSHOT
+cdiVersion=1.0
+gemfireVersion=1.0.0-incubating.M2-SNAPSHOT
hamcrestVersion=1.3
jacksonVersion=2.6.0
junitVersion=4.12
log4jVersion=1.2.17
mockitoVersion=1.10.19
multiThreadedtcVersion=1.01
+openwebbeansVersion=1.2.8
+servletApiVersion=2.5
slf4jVersion=1.7.12
spring.range="[4.0.0, 5.0.0)"
springVersion=4.1.9.RELEASE
diff --git a/pom.xml b/pom.xml
index 73fd79c5..9cc2c5e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,8 @@
2.7.7
1.0.0-incubating-SNAPSHOT
1.01
- 1.11.2.RELEASE
+ 2.5
+ 1.12.0.BUILD-SNAPSHOT
@@ -61,6 +62,14 @@
${springdata.commons}
+
+ javax.enterprise
+ cdi-api
+ ${cdi}
+ provided
+ true
+
+
org.apache.geode
gemfire-core
@@ -192,6 +201,26 @@
+
+ javax.el
+ el-api
+ ${cdi}
+ test
+
+
+ javax.servlet
+ servlet-api
+ ${servlet-api.version}
+ test
+
+
+
+ org.apache.openwebbeans.test
+ cditest-owb
+ ${webbeans}
+ test
+
+
org.apache.derby
derbyLocale_zh_TW
diff --git a/src/main/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryBean.java b/src/main/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryBean.java
new file mode 100644
index 00000000..4a52f876
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryBean.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2012 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.repository.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+
+import org.springframework.data.gemfire.mapping.GemfireMappingContext;
+import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactory;
+import org.springframework.data.repository.cdi.CdiRepositoryBean;
+import org.springframework.data.repository.config.CustomRepositoryImplementationDetector;
+
+import com.gemstone.gemfire.cache.Region;
+
+/**
+ * A CDI-based bean that represents a GemFire Repository.
+ *
+ * @author John Blum
+ * @param class type of the Repository.
+ * @see javax.enterprise.context.spi.CreationalContext
+ * @see javax.enterprise.inject.spi.Bean
+ * @see javax.enterprise.inject.spi.BeanManager
+ * @see org.springframework.data.gemfire.mapping.GemfireMappingContext
+ * @see org.springframework.data.gemfire.repository.support.GemfireRepositoryFactory
+ * @see org.springframework.data.repository.cdi.CdiRepositoryBean
+ * @see org.springframework.data.repository.config.CustomRepositoryImplementationDetector
+ * @see com.gemstone.gemfire.cache.Region
+ * @since 1.8.0
+ */
+class GemfireRepositoryBean extends CdiRepositoryBean {
+
+ static final GemfireMappingContext DEFAULT_GEMFIRE_MAPPING_CONTEXT = new GemfireMappingContext();
+
+ private final Bean gemfireMappingContextBean;
+
+ private final BeanManager beanManager;
+
+ private final Set> regionBeans;
+
+ /* (non-Javadoc) */
+ @SuppressWarnings("unchecked")
+ GemfireRepositoryBean(BeanManager beanManager, Class repositoryType, Set qualifiers,
+ CustomRepositoryImplementationDetector detector, Bean gemfireMappingContextBean,
+ Set> regionBeans) {
+
+ super(qualifiers, repositoryType, beanManager, detector);
+
+ this.beanManager = beanManager;
+ this.gemfireMappingContextBean = gemfireMappingContextBean;
+ this.regionBeans = regionBeans;
+ }
+
+ /**
+ * Returns an instance of the given {@link Bean} from the container.
+ *
+ * @param the actual class type of the {@link Bean}.
+ * @param bean the {@link Bean} defining the instance to create.
+ * @param type the expected component type of the instance created from the {@link Bean}.
+ * @return an instance of the given {@link Bean}.
+ * @see javax.enterprise.inject.spi.BeanManager#getReference(Bean, Type, CreationalContext)
+ * @see javax.enterprise.inject.spi.Bean
+ * @see java.lang.reflect.Type
+ */
+ @SuppressWarnings("unchecked")
+ protected S getDependencyInstance(Bean bean, Type type) {
+ return (S) beanManager.getReference(bean, type, beanManager.createCreationalContext(bean));
+ }
+
+ /**
+ * Resolves the desired, actual component type from the {@link Bean} in which the instance is created.
+ *
+ * @param the class type of the component.
+ * @param bean the {@link Bean} from which the types are evaluated and an instance is created.
+ * @param targetType the desired class type of the component.
+ * @return a resolved component {@link Type} of the {@link Bean}instance.
+ * @throws IllegalStateException if the desired class type cannot be resolved.
+ * @see javax.enterprise.inject.spi.Bean#getTypes()
+ * @see java.lang.Class
+ */
+ @SuppressWarnings("unchecked")
+ protected Type resolveType(Bean bean, Class targetType) {
+ for (Type type : bean.getTypes()) {
+ Type assignableType = (type instanceof ParameterizedType ? ((ParameterizedType) type).getRawType() : type);
+
+ if (assignableType instanceof Class && targetType.isAssignableFrom((Class) assignableType)) {
+ return type;
+ }
+ }
+
+ throw new IllegalStateException(String.format(
+ "unable to resolve bean instance of type [%1$s] from bean definition [%2$s]",
+ targetType, bean));
+ }
+
+ /* (non-Javadoc) */
+ Iterable> resolveGemfireRegions() {
+ Set> regions = new HashSet>(regionBeans.size());
+
+ for (Bean regionBean : regionBeans) {
+ regions.add(getDependencyInstance(regionBean, resolveType(regionBean, Region.class)));
+ }
+
+ return regions;
+ }
+
+ /* (non-Javadoc) */
+ GemfireMappingContext resolveGemfireMappingContext() {
+ return (gemfireMappingContextBean != null
+ ? getDependencyInstance(gemfireMappingContextBean, GemfireMappingContext.class)
+ : DEFAULT_GEMFIRE_MAPPING_CONTEXT);
+ }
+
+ /* (non-Javadoc) */
+ GemfireRepositoryFactory newGemfireRepositoryFactory() {
+ return new GemfireRepositoryFactory(resolveGemfireRegions(), resolveGemfireMappingContext());
+ }
+
+ /**
+ * Creates an instance of the given Repository type as a bean instance in the CDI container.
+ *
+ * @param creationalContext operations used by the {@link javax.enterprise.context.spi.Contextual} implementation
+ * during creation of the bean instance.
+ * @param repositoryType the actual class type of the SD (GemFire) Repository.
+ * @param customImplementation the supporting custom Repository implementing class.
+ * @return a factory used to create instance of {@link org.springframework.data.gemfire.repository.GemfireRepository}.
+ * @see javax.enterprise.context.spi.Contextual#create(javax.enterprise.context.spi.CreationalContext)
+ * @see #newGemfireRepositoryFactory()
+ */
+ @Override
+ protected T create(CreationalContext creationalContext, Class repositoryType, Object customImplementation) {
+ return newGemfireRepositoryFactory().getRepository(repositoryType, customImplementation);
+ }
+
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryExtension.java b/src/main/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryExtension.java
new file mode 100644
index 00000000..3978ccff
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryExtension.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012 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.repository.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.ProcessBean;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.gemfire.mapping.GemfireMappingContext;
+import org.springframework.data.repository.cdi.CdiRepositoryBean;
+import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
+
+import com.gemstone.gemfire.cache.Region;
+
+/**
+ * The GemfireRepositoryExtension class...
+ *
+ * @author John Blum
+ * @see org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport
+ * @since 1.8.0
+ */
+@SuppressWarnings("unused")
+public class GemfireRepositoryExtension extends CdiRepositoryExtensionSupport {
+
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ final Map, Bean> mappingContexts =
+ new HashMap, Bean>();
+
+ final Set> regionBeans = new HashSet>();
+
+ /* (non-Javadoc) */
+ public GemfireRepositoryExtension() {
+ logger.info("Activating CDI extension for Spring Data GemFire Repositories");
+ }
+
+ /**
+ * Implementation of an observer that captures GemFire Region beans defined in the CDI container, storing them
+ * along with any defined GemfireMappingContexts for later construction of the Repository beans.
+ *
+ * @param class type of the bean instance.
+ * @param processBean annotated type as defined by CDI.
+ * @see javax.enterprise.inject.spi.ProcessBean
+ * @see javax.enterprise.event.Observes
+ */
+ @SuppressWarnings("unchecked")
+ void processBean(@Observes ProcessBean processBean) {
+ Bean bean = processBean.getBean();
+
+ for (Type type : bean.getTypes()) {
+ Type resolvedType = (type instanceof ParameterizedType ? ((ParameterizedType) type).getRawType() : type);
+
+ if (resolvedType instanceof Class>) {
+ Class> classType = (Class>) resolvedType;
+
+ if (Region.class.isAssignableFrom(classType)) {
+ logger.debug("Found Region bean with name {}", bean.getName());
+ regionBeans.add((Bean) bean);
+ }
+ else if (GemfireMappingContext.class.isAssignableFrom(classType)) {
+ logger.debug("Discovered {} bean with types {} having qualifiers {}",
+ GemfireMappingContext.class.getName(), bean.getTypes(), bean.getQualifiers());
+ mappingContexts.put(bean.getQualifiers(), (Bean) bean);
+ }
+ }
+ }
+ }
+
+ /**
+ * Implementation of an observer that registers beans in the CDI container for the detected Spring Data
+ * Repositories.
+ *
+ * Repository beans are associated to the appropriate GemfireMappingContexts based on their qualifiers.
+ *
+ * @param beanManager the BeanManager instance.
+ * @see javax.enterprise.inject.spi.AfterBeanDiscovery
+ * @see javax.enterprise.inject.spi.BeanManager
+ * @see javax.enterprise.event.Observes
+ */
+ void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
+ for (Map.Entry, Set> entry : getRepositoryTypes()) {
+ Class> repositoryType = entry.getKey();
+ Set qualifiers = entry.getValue();
+
+ // Create the bean representing the Repository.
+ CdiRepositoryBean> repositoryBean = createRepositoryBean(beanManager, repositoryType, qualifiers);
+
+ logger.info("Registering bean for '{}' with qualifiers {}.", repositoryType.getName(), qualifiers);
+
+ // Register the bean with the extension and the container.
+ registerBean(repositoryBean);
+ afterBeanDiscovery.addBean(repositoryBean);
+ }
+ }
+
+ /* (non-Javadoc) */
+ CdiRepositoryBean createRepositoryBean(BeanManager beanManager, Class repositoryType,
+ Set qualifiers) {
+
+ // Determine the GemfireMappingContext bean that matches the qualifiers of the Repository.
+ Bean gemfireMappingContextBean = mappingContexts.get(qualifiers);
+
+ // Construct and return a GemFire Repository bean.
+ return new GemfireRepositoryBean(beanManager, repositoryType, qualifiers, getCustomImplementationDetector(),
+ gemfireMappingContextBean, regionBeans);
+ }
+
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryBean.java b/src/main/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryBean.java
index e9ce648e..98634c88 100644
--- a/src/main/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryBean.java
+++ b/src/main/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryBean.java
@@ -55,6 +55,7 @@ public class GemfireRepositoryFactoryBean, S, ID ext
extends RepositoryFactoryBeanSupport implements ApplicationContextAware {
private Iterable> regions;
+
private MappingContext extends GemfirePersistentEntity>, GemfirePersistentProperty> context;
/**
@@ -67,7 +68,6 @@ public class GemfireRepositoryFactoryBean, S, ID ext
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-
Collection regions = applicationContext.getBeansOfType(Region.class).values();
this.regions = (Iterable) Collections.unmodifiableCollection(regions);
}
@@ -80,7 +80,6 @@ public class GemfireRepositoryFactoryBean, S, ID ext
* @see org.springframework.data.mapping.context.MappingContext
*/
public void setGemfireMappingContext(MappingContext extends GemfirePersistentEntity>, GemfirePersistentProperty> mappingContext) {
-
setMappingContext(mappingContext);
this.context = mappingContext;
}
diff --git a/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 00000000..32a846a9
--- /dev/null
+++ b/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1 @@
+org.springframework.data.gemfire.repository.cdi.GemfireRepositoryExtension
diff --git a/src/test/java/org/springframework/data/gemfire/repository/cdi/CdiExtensionIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/repository/cdi/CdiExtensionIntegrationTest.java
new file mode 100644
index 00000000..a8889dc9
--- /dev/null
+++ b/src/test/java/org/springframework/data/gemfire/repository/cdi/CdiExtensionIntegrationTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 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.repository.cdi;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import org.apache.webbeans.cditest.CdiTestContainer;
+import org.apache.webbeans.cditest.CdiTestContainerLoader;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.data.gemfire.repository.sample.Person;
+
+import com.gemstone.gemfire.cache.CacheClosedException;
+import com.gemstone.gemfire.cache.CacheFactory;
+
+/**
+ * The CdiExtensionIntegrationTest class...
+ *
+ * @author John Blum
+ * @see org.junit.Test
+ * @see org.springframework.data.gemfire.repository.cdi.GemfireRepositoryBean
+ * @see org.springframework.data.gemfire.repository.cdi.GemfireRepositoryExtension
+ * @see org.apache.webbeans.cditest.CdiTestContainer
+ * @see org.apache.webbeans.cditest.CdiTestContainerLoader
+ * @since 1.8.0
+ */
+public class CdiExtensionIntegrationTest {
+
+ static CdiTestContainer container;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ container = CdiTestContainerLoader.getCdiContainer();
+ container.bootContainer();
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ container.shutdownContainer();
+ closeGemfireCache();
+ }
+
+ private static void closeGemfireCache() {
+ try {
+ CacheFactory.getAnyInstance().close();
+ }
+ catch (CacheClosedException ignore) {
+ }
+ }
+
+ protected void assertIsExpectedPerson(Person actual, Person expected) {
+ assertThat(actual.getId(), is(equalTo(expected.getId())));
+ assertThat(actual.getFirstname(), is(equalTo(expected.getFirstname())));
+ assertThat(actual.getLastname(), is(equalTo(expected.getLastname())));
+ }
+
+ @Test
+ public void bootstrapsRepositoryCorrectly() {
+ RepositoryClient repositoryClient = container.getInstance(RepositoryClient.class);
+
+ assertThat(repositoryClient.getPersonRepository(), is(notNullValue()));
+
+ Person expectedJonDoe = repositoryClient.newPerson("Jon", "Doe");
+
+ assertThat(expectedJonDoe, is(notNullValue()));
+ assertThat(expectedJonDoe.getId(), is(greaterThan(0l)));
+ assertThat(expectedJonDoe.getName(), is(equalTo("Jon Doe")));
+
+ Person savedJonDoe = repositoryClient.save(expectedJonDoe);
+
+ assertIsExpectedPerson(savedJonDoe, expectedJonDoe);
+
+ Person foundJonDoe = repositoryClient.find(expectedJonDoe.getId());
+
+ assertIsExpectedPerson(foundJonDoe, expectedJonDoe);
+
+ assertThat(repositoryClient.delete(expectedJonDoe), is(true));
+ assertThat(repositoryClient.find(expectedJonDoe.getId()), is(nullValue()));
+ }
+
+ @Test
+ public void returnOneFromCustomImplementation() {
+ RepositoryClient repositoryClient = container.getInstance(RepositoryClient.class);
+
+ assertThat(repositoryClient.getPersonRepository().returnOne(), is(equalTo(1)));
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/gemfire/repository/cdi/CustomPersonRepository.java b/src/test/java/org/springframework/data/gemfire/repository/cdi/CustomPersonRepository.java
new file mode 100644
index 00000000..70b2ee32
--- /dev/null
+++ b/src/test/java/org/springframework/data/gemfire/repository/cdi/CustomPersonRepository.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 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.repository.cdi;
+
+/**
+ * The CustomPersonRepository interface is an Spring Data Repository extension type specifying additional, "custom"
+ * data access operations on people.
+ *
+ * @author John Blum
+ * @since 1.8.0
+ */
+public interface CustomPersonRepository {
+
+ int returnOne();
+
+}
diff --git a/src/test/java/org/springframework/data/gemfire/repository/cdi/GemfireCacheRegionProducer.java b/src/test/java/org/springframework/data/gemfire/repository/cdi/GemfireCacheRegionProducer.java
new file mode 100644
index 00000000..dc78e78a
--- /dev/null
+++ b/src/test/java/org/springframework/data/gemfire/repository/cdi/GemfireCacheRegionProducer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 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.repository.cdi;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import org.springframework.data.gemfire.repository.sample.Person;
+import org.springframework.util.Assert;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionFactory;
+import com.gemstone.gemfire.cache.RegionShortcut;
+
+/**
+ * The GemfireCacheRegionProducer class is an application scoped CDI context bean that is responsible
+ * for creating the GemFire Cache "People" Region used to store {@link Person} instances.
+ *
+ * @author John Blum
+ * @see javax.enterprise.context.ApplicationScoped
+ * @see javax.enterprise.inject.Produces
+ * @see com.gemstone.gemfire.cache.Cache
+ * @see com.gemstone.gemfire.cache.CacheFactory
+ * @see com.gemstone.gemfire.cache.Region
+ * @see com.gemstone.gemfire.cache.RegionFactory
+ * @since 1.8.0
+ */
+@SuppressWarnings("unused")
+public class GemfireCacheRegionProducer {
+
+ @Produces
+ @ApplicationScoped
+ public Region createPeopleRegion() {
+ Cache gemfireCache = new CacheFactory()
+ .set("name", "SpringDataGemFireCdiTest")
+ .set("mcast-port", "0")
+ .set("log-level", "warning")
+ .create();
+
+ RegionFactory peopleRegionFactory = gemfireCache.createRegionFactory(RegionShortcut.REPLICATE);
+
+ peopleRegionFactory.setKeyConstraint(Long.class);
+ peopleRegionFactory.setValueConstraint(Person.class);
+
+ Region peopleRegion = peopleRegionFactory.create("People");
+
+ Assert.notNull(peopleRegion);
+
+ return peopleRegion;
+ }
+
+}
diff --git a/src/test/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryBeanTest.java
new file mode 100644
index 00000000..fcd7b3db
--- /dev/null
+++ b/src/test/java/org/springframework/data/gemfire/repository/cdi/GemfireRepositoryBeanTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2012 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.repository.cdi;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isIn;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.data.gemfire.GemfireAccessor;
+import org.springframework.data.gemfire.TestUtils;
+import org.springframework.data.gemfire.mapping.GemfireMappingContext;
+import org.springframework.data.gemfire.repository.GemfireRepository;
+import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactory;
+import org.springframework.data.gemfire.repository.support.SimpleGemfireRepository;
+import org.springframework.data.repository.core.RepositoryInformation;
+import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionAttributes;
+
+/**
+ * The GemfireRepositoryBeanTest class is a test suite of test cases testing the contract and functionality
+ * of the GemfireRepositoryBean class.
+ *
+ * @author John Blum
+ * @see org.junit.Rule
+ * @see org.junit.Test
+ * @see org.junit.rules.ExpectedException
+ * @see org.junit.runner.RunWith
+ * @see org.mockito.Mock
+ * @see org.mockito.Mockito
+ * @see org.mockito.runners.MockitoJUnitRunner
+ * @see org.springframework.data.gemfire.repository.cdi.GemfireRepositoryBean
+ * @since 1.0.0
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("unchecked")
+public class GemfireRepositoryBeanTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Mock
+ private BeanManager mockBeanManager;
+
+ protected T[] asArray(T... array) {
+ return array;
+ }
+
+ protected Set asSet(T... array) {
+ return new HashSet(Arrays.asList(array));
+ }
+
+ protected Set asSet(Iterable collection) {
+ Set set = new HashSet();
+
+ for (T element : collection) {
+ set.add(element);
+ }
+
+ return set;
+ }
+
+ @Test
+ public void getDependencyInstanceGetsReference() {
+ Bean mockRegionBean = mock(Bean.class);
+ CreationalContext mockCreationalContext = mock(CreationalContext.class);
+ Region mockRegion = mock(Region.class);
+
+ when(mockBeanManager.createCreationalContext(eq(mockRegionBean))).thenReturn(mockCreationalContext);
+ when(mockBeanManager.getReference(eq(mockRegionBean), eq(Region.class), eq(mockCreationalContext)))
+ .thenReturn(mockRegion);
+
+ GemfireRepositoryBean repositoryBean = new GemfireRepositoryBean(
+ mockBeanManager, PersonRepository.class, Collections.emptySet(), null, null, null);
+
+ assertThat(repositoryBean.getDependencyInstance(mockRegionBean, Region.class), is(equalTo(mockRegion)));
+
+ verify(mockBeanManager, times(1)).createCreationalContext(eq(mockRegionBean));
+ verify(mockBeanManager, times(1)).getReference(eq(mockRegionBean), eq(Region.class), eq(mockCreationalContext));
+ }
+
+ @Test
+ public void resolveGemfireMappingContextUsesDefault() {
+ GemfireRepositoryBean repositoryBean = new GemfireRepositoryBean(
+ mockBeanManager, PersonRepository.class, Collections.emptySet(), null, null, null);
+
+ assertThat(repositoryBean.resolveGemfireMappingContext(),
+ is(equalTo(GemfireRepositoryBean.DEFAULT_GEMFIRE_MAPPING_CONTEXT)));
+ }
+
+ @Test
+ public void resolveGemfireMappingContextUsesQualifiedMappingContext() {
+ Bean mockMappingContextBean = mock(Bean.class);
+ CreationalContext mockCreationalContext = mock(CreationalContext.class);
+ GemfireMappingContext expectedGemfireMappingContext = new GemfireMappingContext();
+
+ when(mockBeanManager.createCreationalContext(eq(mockMappingContextBean))).thenReturn(mockCreationalContext);
+ when(mockBeanManager.getReference(eq(mockMappingContextBean), eq(GemfireMappingContext.class),
+ eq(mockCreationalContext))).thenReturn(expectedGemfireMappingContext);
+
+ GemfireRepositoryBean repositoryBean = new GemfireRepositoryBean(
+ mockBeanManager, PersonRepository.class, Collections.emptySet(), null,
+ mockMappingContextBean, null);
+
+ GemfireMappingContext actualGemfireMappingContext = repositoryBean.resolveGemfireMappingContext();
+
+ assertThat(actualGemfireMappingContext, is(equalTo(expectedGemfireMappingContext)));
+
+ verify(mockBeanManager, times(1)).createCreationalContext(eq(mockMappingContextBean));
+ verify(mockBeanManager, times(1)).getReference(eq(mockMappingContextBean), eq(GemfireMappingContext.class),
+ eq(mockCreationalContext));
+ }
+
+ @Test
+ public void resolveGemfireRegions() {
+ Region mockRegionOne = mock(Region.class);
+ Region mockRegionTwo = mock(Region.class);
+
+ CreationalContext> mockCreationalContext = mock(CreationalContext.class);
+
+ Bean mockRegionBeanOne = mock(Bean.class);
+ Bean mockRegionBeanTwo = mock(Bean.class);
+
+ when(mockRegionBeanOne.getTypes()).thenReturn(asSet((Type) Region.class));
+ when(mockRegionBeanTwo.getTypes()).thenReturn(asSet((Type) Region.class));
+ when(mockBeanManager.createCreationalContext(any(Bean.class))).thenReturn(mockCreationalContext);
+ when(mockBeanManager.getReference(eq(mockRegionBeanOne), eq(Region.class), eq(mockCreationalContext)))
+ .thenReturn(mockRegionOne);
+ when(mockBeanManager.getReference(eq(mockRegionBeanTwo), eq(Region.class), eq(mockCreationalContext)))
+ .thenReturn(mockRegionTwo);
+
+ GemfireRepositoryBean repositoryBean = new GemfireRepositoryBean(mockBeanManager,
+ PersonRepository.class, Collections.emptySet(), null, null, asSet(mockRegionBeanOne, mockRegionBeanTwo));
+
+ Iterable regions = repositoryBean.resolveGemfireRegions();
+
+ assertThat(regions, is(notNullValue()));
+ assertThat(asSet(regions).containsAll(asSet(mockRegionOne, mockRegionTwo)), is(true));
+
+ verify(mockRegionBeanOne, times(1)).getTypes();
+ verify(mockRegionBeanTwo, times(1)).getTypes();
+ verify(mockBeanManager, times(1)).createCreationalContext(eq(mockRegionBeanOne));
+ verify(mockBeanManager, times(1)).createCreationalContext(eq(mockRegionBeanTwo));
+ verify(mockBeanManager, times(1)).getReference(eq(mockRegionBeanOne), eq(Region.class),
+ eq(mockCreationalContext));
+ verify(mockBeanManager, times(1)).getReference(eq(mockRegionBeanTwo), eq(Region.class),
+ eq(mockCreationalContext));
+ }
+
+ @Test
+ public void resolveTypeFindsTargetComponentType() {
+ Bean mockBean = mock(Bean.class);
+
+ when(mockBean.getTypes()).thenReturn(
+ asSet((Type) Object.class, Map.class, ConcurrentMap.class, Region.class));
+
+ GemfireRepositoryBean repositoryBean = new GemfireRepositoryBean(
+ mockBeanManager, PersonRepository.class, Collections.emptySet(), null, null, null);
+
+ assertThat(repositoryBean.resolveType(mockBean, Region.class), is(equalTo((Type) Region.class)));
+ assertThat(repositoryBean.resolveType(mockBean, Map.class), isIn(asArray((Type) Map.class,
+ ConcurrentMap.class, Region.class)));
+
+ verify(mockBean, times(2)).getTypes();
+ }
+
+ @Test
+ public void resolveTypeWithParameterizedType() {
+ Bean