SGF-469 - Add support for CDI.
This commit is contained in:
16
build.gradle
16
build.gradle
@@ -51,6 +51,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"]
|
||||
|
||||
tasks.withType(Test).all {
|
||||
@@ -80,6 +91,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-core:$jacksonVersion"
|
||||
compile "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
|
||||
@@ -94,11 +106,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"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
antlrVersion=2.7.7
|
||||
aspectjVersion=1.8.5
|
||||
cdiVersion=1.0
|
||||
gemfireVersion=8.2.0
|
||||
hamcrestVersion=1.3
|
||||
jacksonVersion=2.6.0
|
||||
@@ -7,6 +8,8 @@ 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
|
||||
|
||||
29
pom.xml
29
pom.xml
@@ -20,6 +20,7 @@
|
||||
<antlr.version>2.7.7</antlr.version>
|
||||
<gemfire.version>8.2.0</gemfire.version>
|
||||
<multithreadedtc.version>1.01</multithreadedtc.version>
|
||||
<servlet-api.version>2.5</servlet-api.version>
|
||||
<springdata.commons>1.12.0.BUILD-SNAPSHOT</springdata.commons>
|
||||
</properties>
|
||||
|
||||
@@ -41,6 +42,14 @@
|
||||
<version>${springdata.commons}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.enterprise</groupId>
|
||||
<artifactId>cdi-api</artifactId>
|
||||
<version>${cdi}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.gemstone.gemfire</groupId>
|
||||
<artifactId>gemfire</artifactId>
|
||||
@@ -90,6 +99,26 @@
|
||||
|
||||
<!-- Test -->
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.el</groupId>
|
||||
<artifactId>el-api</artifactId>
|
||||
<version>${cdi}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>${servlet-api.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.openwebbeans.test</groupId>
|
||||
<artifactId>cditest-owb</artifactId>
|
||||
<version>${webbeans}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbyLocale_zh_TW</artifactId>
|
||||
|
||||
@@ -35,14 +35,12 @@ import org.w3c.dom.Element;
|
||||
@SuppressWarnings("unused")
|
||||
class GemfireNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
protected static final List<String> GEMFIRE7_ELEMENTS = Arrays.asList("async-event-queue", "gateway-sender",
|
||||
static final List<String> GEMFIRE7_ELEMENTS = Arrays.asList("async-event-queue", "gateway-sender",
|
||||
"gateway-receiver");
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
boolean v7ElementsPresent = GEMFIRE7_ELEMENTS.contains(element.getLocalName());
|
||||
|
||||
if (v7ElementsPresent) {
|
||||
if (GEMFIRE7_ELEMENTS.contains(element.getLocalName())) {
|
||||
ParsingUtils.throwExceptionIfNotGemfireV7(element.getLocalName(), null, parserContext);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <T> 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<T> extends CdiRepositoryBean<T> {
|
||||
|
||||
static final GemfireMappingContext DEFAULT_GEMFIRE_MAPPING_CONTEXT = new GemfireMappingContext();
|
||||
|
||||
private final Bean<GemfireMappingContext> gemfireMappingContextBean;
|
||||
|
||||
private final BeanManager beanManager;
|
||||
|
||||
private final Set<Bean<Region>> regionBeans;
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
GemfireRepositoryBean(BeanManager beanManager, Class<T> repositoryType, Set<Annotation> qualifiers,
|
||||
CustomRepositoryImplementationDetector detector, Bean<GemfireMappingContext> gemfireMappingContextBean,
|
||||
Set<Bean<Region>> 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 <S> 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> S getDependencyInstance(Bean<S> 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 <S> 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 <S> Type resolveType(Bean<S> bean, Class<S> 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<Region<?, ?>> resolveGemfireRegions() {
|
||||
Set<Region<?, ?>> regions = new HashSet<Region<?, ?>>(regionBeans.size());
|
||||
|
||||
for (Bean<Region> 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<T> creationalContext, Class<T> repositoryType, Object customImplementation) {
|
||||
return newGemfireRepositoryFactory().getRepository(repositoryType, customImplementation);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Set<Annotation>, Bean<GemfireMappingContext>> mappingContexts =
|
||||
new HashMap<Set<Annotation>, Bean<GemfireMappingContext>>();
|
||||
|
||||
final Set<Bean<Region>> regionBeans = new HashSet<Bean<Region>>();
|
||||
|
||||
/* (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 <X> 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")
|
||||
<X> void processBean(@Observes ProcessBean<X> processBean) {
|
||||
Bean<X> 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<Region>) 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<GemfireMappingContext>) 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<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
|
||||
Class<?> repositoryType = entry.getKey();
|
||||
Set<Annotation> 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) */
|
||||
<T> CdiRepositoryBean<T> createRepositoryBean(BeanManager beanManager, Class<T> repositoryType,
|
||||
Set<Annotation> qualifiers) {
|
||||
|
||||
// Determine the GemfireMappingContext bean that matches the qualifiers of the Repository.
|
||||
Bean<GemfireMappingContext> gemfireMappingContextBean = mappingContexts.get(qualifiers);
|
||||
|
||||
// Construct and return a GemFire Repository bean.
|
||||
return new GemfireRepositoryBean<T>(beanManager, repositoryType, qualifiers, getCustomImplementationDetector(),
|
||||
gemfireMappingContextBean, regionBeans);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,6 +55,7 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID ext
|
||||
extends RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
|
||||
|
||||
private Iterable<Region<?, ?>> regions;
|
||||
|
||||
private MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context;
|
||||
|
||||
/**
|
||||
@@ -67,7 +68,6 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID ext
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
Collection<Region> regions = applicationContext.getBeansOfType(Region.class).values();
|
||||
this.regions = (Iterable) Collections.unmodifiableCollection(regions);
|
||||
}
|
||||
@@ -80,7 +80,6 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID ext
|
||||
* @see org.springframework.data.mapping.context.MappingContext
|
||||
*/
|
||||
public void setGemfireMappingContext(MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext) {
|
||||
|
||||
setMappingContext(mappingContext);
|
||||
this.context = mappingContext;
|
||||
}
|
||||
@@ -118,10 +117,8 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID ext
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
|
||||
Assert.state(context != null, "GemfireMappingContext must not be null!");
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.data.gemfire.repository.cdi.GemfireRepositoryExtension
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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<Long, Person> createPeopleRegion() {
|
||||
Cache gemfireCache = new CacheFactory()
|
||||
.set("name", "SpringDataGemFireCdiTest")
|
||||
.set("mcast-port", "0")
|
||||
.set("log-level", "warning")
|
||||
.create();
|
||||
|
||||
RegionFactory<Long, Person> peopleRegionFactory = gemfireCache.createRegionFactory(RegionShortcut.REPLICATE);
|
||||
|
||||
peopleRegionFactory.setKeyConstraint(Long.class);
|
||||
peopleRegionFactory.setValueConstraint(Person.class);
|
||||
|
||||
Region<Long, Person> peopleRegion = peopleRegionFactory.create("People");
|
||||
|
||||
Assert.notNull(peopleRegion);
|
||||
|
||||
return peopleRegion;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> T[] asArray(T... array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
protected <T> Set<T> asSet(T... array) {
|
||||
return new HashSet<T>(Arrays.asList(array));
|
||||
}
|
||||
|
||||
protected <T> Set<T> asSet(Iterable<T> collection) {
|
||||
Set<T> set = new HashSet<T>();
|
||||
|
||||
for (T element : collection) {
|
||||
set.add(element);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDependencyInstanceGetsReference() {
|
||||
Bean<Region> mockRegionBean = mock(Bean.class);
|
||||
CreationalContext<Region> 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<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>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<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>emptySet(), null, null, null);
|
||||
|
||||
assertThat(repositoryBean.resolveGemfireMappingContext(),
|
||||
is(equalTo(GemfireRepositoryBean.DEFAULT_GEMFIRE_MAPPING_CONTEXT)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveGemfireMappingContextUsesQualifiedMappingContext() {
|
||||
Bean<GemfireMappingContext> mockMappingContextBean = mock(Bean.class);
|
||||
CreationalContext<GemfireMappingContext> 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<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>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<Bean<Region>> mockCreationalContext = mock(CreationalContext.class);
|
||||
|
||||
Bean<Region> mockRegionBeanOne = mock(Bean.class);
|
||||
Bean<Region> 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<Region> 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<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>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<Map> mockBean = mock(Bean.class);
|
||||
Map<Long, Object> parameterizedTypeMap = Collections.emptyMap();
|
||||
ParameterizedType mockParameterizedType = mock(ParameterizedType.class);
|
||||
|
||||
assertThat(parameterizedTypeMap.getClass(), is(instanceOf(Type.class)));
|
||||
assertThat(parameterizedTypeMap.getClass().getGenericSuperclass(), is(instanceOf(ParameterizedType.class)));
|
||||
assertThat(parameterizedTypeMap.getClass().getTypeParameters().length, is(equalTo(2)));
|
||||
|
||||
when(mockBean.getTypes()).thenReturn(asSet((Type) mockParameterizedType));
|
||||
when(mockParameterizedType.getRawType()).thenReturn(parameterizedTypeMap.getClass());
|
||||
|
||||
GemfireRepositoryBean<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>emptySet(), null, null, null);
|
||||
|
||||
assertThat(repositoryBean.resolveType(mockBean, Map.class), is(equalTo((Type) mockParameterizedType)));
|
||||
|
||||
verify(mockBean, times(1)).getTypes();
|
||||
verify(mockParameterizedType, times(1)).getRawType();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTypeWithUnresolvableType() {
|
||||
Bean mockBean = mock(Bean.class);
|
||||
|
||||
when(mockBean.getTypes()).thenReturn(asSet((Type) Map.class, Object.class));
|
||||
|
||||
GemfireRepositoryBean<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>emptySet(), null, null, null);
|
||||
|
||||
try {
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage(is(equalTo(String.format(
|
||||
"unable to resolve bean instance of type [%1$s] from bean definition [%2$s]",
|
||||
Region.class, mockBean))));
|
||||
|
||||
repositoryBean.resolveType(mockBean, Region.class);
|
||||
}
|
||||
finally {
|
||||
verify(mockBean, times(1)).getTypes();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// IntegrationTest
|
||||
public void createGemfireRepositoryInstanceSuccessfully() throws Exception {
|
||||
Bean<Region> mockRegionBean = mock(Bean.class);
|
||||
|
||||
CreationalContext<Bean<Region>> mockCreationalContext = mock(CreationalContext.class);
|
||||
|
||||
final Region mockRegion = mock(Region.class);
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegion.getName()).thenReturn("Person");
|
||||
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionAttributes.getKeyConstraint()).thenReturn(Long.class);
|
||||
when(mockRegionBean.getTypes()).thenReturn(asSet((Type) Region.class));
|
||||
when(mockBeanManager.createCreationalContext(any(Bean.class))).thenReturn(mockCreationalContext);
|
||||
when(mockBeanManager.getReference(eq(mockRegionBean), eq(Region.class), eq(mockCreationalContext)))
|
||||
.thenReturn(mockRegion);
|
||||
|
||||
final AtomicBoolean repositoryProxyPostProcessed = new AtomicBoolean(false);
|
||||
|
||||
GemfireRepositoryBean<PersonRepository> repositoryBean = new GemfireRepositoryBean<PersonRepository>(
|
||||
mockBeanManager, PersonRepository.class, Collections.<Annotation>emptySet(), null, null,
|
||||
asSet(mockRegionBean))
|
||||
{
|
||||
@Override
|
||||
GemfireRepositoryFactory newGemfireRepositoryFactory() {
|
||||
GemfireRepositoryFactory gemfireRepositoryFactory = super.newGemfireRepositoryFactory();
|
||||
|
||||
gemfireRepositoryFactory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
|
||||
public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
|
||||
try {
|
||||
assertThat((Class<PersonRepository>) repositoryInformation.getRepositoryInterface(),
|
||||
is(equalTo(PersonRepository.class)));
|
||||
assertThat((Class<SimpleGemfireRepository>) repositoryInformation.getRepositoryBaseClass(),
|
||||
is(equalTo(SimpleGemfireRepository.class)));
|
||||
assertThat((Class<Person>) repositoryInformation.getDomainType(), is(equalTo(Person.class)));
|
||||
assertThat((Class<Long>) repositoryInformation.getIdType(), is(equalTo(Long.class)));
|
||||
assertThat((Class<SimpleGemfireRepository>) factory.getTargetClass(),
|
||||
is(equalTo(SimpleGemfireRepository.class)));
|
||||
|
||||
Object gemfireRepository = factory.getTargetSource().getTarget();
|
||||
|
||||
GemfireAccessor gemfireAccessor = TestUtils.readField("template", gemfireRepository);
|
||||
|
||||
assertThat(gemfireAccessor, is(notNullValue()));
|
||||
assertThat(gemfireAccessor.getRegion(), is(equalTo(mockRegion)));
|
||||
|
||||
repositoryProxyPostProcessed.set(true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return gemfireRepositoryFactory;
|
||||
}
|
||||
};
|
||||
|
||||
GemfireRepository<Person, Long> gemfireRepository = repositoryBean.create(null, PersonRepository.class, null);
|
||||
|
||||
assertThat(gemfireRepository, is(notNullValue()));
|
||||
assertThat(repositoryProxyPostProcessed.get(), is(true));
|
||||
|
||||
verify(mockBeanManager, times(1)).createCreationalContext(eq(mockRegionBean));
|
||||
verify(mockBeanManager, times(1)).getReference(eq(mockRegionBean), eq(Region.class),
|
||||
eq(mockCreationalContext));
|
||||
verify(mockRegionBean, times(1)).getTypes();
|
||||
verify(mockRegion, times(1)).getName();
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getKeyConstraint();
|
||||
}
|
||||
|
||||
class TestMap extends AbstractMap<Long, Object> {
|
||||
@Override public Set<Entry<Long, Object>> entrySet() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
class Person {}
|
||||
|
||||
interface PersonRepository extends GemfireRepository<Person, Long> {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.isA;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
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.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
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 javax.inject.Qualifier;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
|
||||
import org.springframework.data.gemfire.repository.GemfireRepository;
|
||||
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* The GemfireRepositoryExtensionTest class is a test suite of unit tests testing the contract and proper functionality
|
||||
* of the {@link GemfireRepositoryExtension} class in a Java EE CDI context.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see javax.enterprise.inject.spi.Bean
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
|
||||
* @see org.springframework.data.gemfire.repository.GemfireRepository
|
||||
* @see org.springframework.data.gemfire.repository.cdi.GemfireRepositoryExtension
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class GemfireRepositoryExtensionTest {
|
||||
|
||||
private GemfireRepositoryExtension repositoryExtension;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
repositoryExtension = new GemfireRepositoryExtension();
|
||||
}
|
||||
|
||||
protected <T> Set<T> asSet(T... array) {
|
||||
return new HashSet<T>(Arrays.asList(array));
|
||||
}
|
||||
|
||||
protected Annotation mockAnnotation(Class annotationType) {
|
||||
Annotation mockAnnotation = mock(Annotation.class);
|
||||
when(mockAnnotation.annotationType()).thenReturn(annotationType);
|
||||
return mockAnnotation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processBeanIdentifiesAndProcessesRegionBeanCorrectly() {
|
||||
ProcessBean<Region> mockProcessBean = mock(ProcessBean.class);
|
||||
Bean<Region> mockBean = mock(Bean.class);
|
||||
|
||||
when(mockProcessBean.getBean()).thenReturn(mockBean);
|
||||
when(mockBean.getTypes()).thenReturn(Collections.singleton((Type) Region.class));
|
||||
|
||||
assertThat(repositoryExtension.regionBeans.isEmpty(), is(true));
|
||||
|
||||
repositoryExtension.processBean(mockProcessBean);
|
||||
|
||||
assertThat(repositoryExtension.regionBeans.contains(mockBean), is(true));
|
||||
|
||||
verify(mockProcessBean, times(1)).getBean();
|
||||
verify(mockBean, times(1)).getTypes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processBeanIdentifiesAndProcessesGemfireMappingContextBeanCorrectly() {
|
||||
ProcessBean<GemfireMappingContext> mockProcessBean = mock(ProcessBean.class);
|
||||
Bean<GemfireMappingContext> mockBean = mock(Bean.class);
|
||||
|
||||
Set<Annotation> expectedQualifiers = asSet(mockAnnotation(SpringDataRepo.class),
|
||||
mockAnnotation(GemfireRepo.class));
|
||||
|
||||
when(mockProcessBean.getBean()).thenReturn(mockBean);
|
||||
when(mockBean.getTypes()).thenReturn(Collections.singleton((Type) GemfireMappingContext.class));
|
||||
when(mockBean.getQualifiers()).thenReturn(expectedQualifiers);
|
||||
|
||||
assertThat(repositoryExtension.mappingContexts.isEmpty(), is(true));
|
||||
|
||||
repositoryExtension.processBean(mockProcessBean);
|
||||
|
||||
assertThat(repositoryExtension.mappingContexts.containsKey(expectedQualifiers), is(true));
|
||||
assertThat(repositoryExtension.mappingContexts.get(expectedQualifiers), is(equalTo(mockBean)));
|
||||
|
||||
verify(mockProcessBean, times(1)).getBean();
|
||||
verify(mockBean, times(2)).getTypes();
|
||||
verify(mockBean, times(2)).getQualifiers();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processBeanIgnoresNonRegionNonGemfireMappingContextBeansProperly() {
|
||||
ProcessBean<Object> mockProcessBean = mock(ProcessBean.class);
|
||||
Bean<Object> mockBean = mock(Bean.class);
|
||||
|
||||
when(mockProcessBean.getBean()).thenReturn(mockBean);
|
||||
when(mockBean.getTypes()).thenReturn(Collections.singleton((Type) Object.class));
|
||||
|
||||
assertThat(repositoryExtension.mappingContexts.isEmpty(), is(true));
|
||||
assertThat(repositoryExtension.regionBeans.isEmpty(), is(true));
|
||||
|
||||
repositoryExtension.processBean(mockProcessBean);
|
||||
|
||||
assertThat(repositoryExtension.mappingContexts.isEmpty(), is(true));
|
||||
assertThat(repositoryExtension.regionBeans.isEmpty(), is(true));
|
||||
|
||||
verify(mockProcessBean, times(1)).getBean();
|
||||
verify(mockBean, times(1)).getTypes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterBeanDiscoveryRegistersRepositoryBean() {
|
||||
AfterBeanDiscovery mockAfterBeanDiscovery = mock(AfterBeanDiscovery.class);
|
||||
|
||||
final Set<Annotation> expectedQualifiers = asSet(mockAnnotation(SpringDataRepo.class),
|
||||
mockAnnotation(GemfireRepo.class));
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
public Void answer(final InvocationOnMock invocation) throws Throwable {
|
||||
GemfireRepositoryBean<?> repositoryBean = invocation.getArgumentAt(0, GemfireRepositoryBean.class);
|
||||
|
||||
assertThat(repositoryBean, is(notNullValue()));
|
||||
assertThat((Class<TestRepository>) repositoryBean.getBeanClass(), is(equalTo(TestRepository.class)));
|
||||
assertThat(repositoryBean.getQualifiers(), is(equalTo(expectedQualifiers)));
|
||||
|
||||
return null;
|
||||
}
|
||||
}).when(mockAfterBeanDiscovery).addBean(isA(GemfireRepositoryBean.class));
|
||||
|
||||
GemfireRepositoryExtension repositoryExtension = new GemfireRepositoryExtension() {
|
||||
@Override protected Iterable<Map.Entry<Class<?>, Set<Annotation>>> getRepositoryTypes() {
|
||||
return Collections.<Class<?>, Set<Annotation>>singletonMap(TestRepository.class, expectedQualifiers).entrySet();
|
||||
}
|
||||
};
|
||||
|
||||
repositoryExtension.afterBeanDiscovery(mockAfterBeanDiscovery, mock(BeanManager.class));
|
||||
|
||||
verify(mockAfterBeanDiscovery, times(1)).addBean(isA(GemfireRepositoryBean.class));
|
||||
}
|
||||
|
||||
@Qualifier
|
||||
@interface GemfireRepo {
|
||||
}
|
||||
|
||||
@Qualifier
|
||||
@interface SpringDataRepo {
|
||||
}
|
||||
|
||||
@GemfireRepo
|
||||
@SpringDataRepo
|
||||
interface TestRepository extends GemfireRepository<Object, Long> {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.util.concurrent.atomic.AtomicLong;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.springframework.data.gemfire.repository.sample.Person;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The RepositoryClient class is a user/consumer of the {@link SamplePersonRepository} bean in a CDI context.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see javax.inject.Inject
|
||||
* @see org.springframework.data.gemfire.repository.cdi.SamplePersonRepository
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public class RepositoryClient {
|
||||
|
||||
private static final AtomicLong ID_SEQUENCE = new AtomicLong(0l);
|
||||
|
||||
@Inject
|
||||
private SamplePersonRepository personRepository;
|
||||
|
||||
protected SamplePersonRepository getPersonRepository() {
|
||||
Assert.state(personRepository != null, "personRepository was not properly initialized");
|
||||
return personRepository;
|
||||
}
|
||||
|
||||
public Person newPerson(String firstName, String lastName) {
|
||||
return new Person(ID_SEQUENCE.incrementAndGet(), firstName, lastName);
|
||||
}
|
||||
|
||||
public Person find(Long id) {
|
||||
return getPersonRepository().findOne(id);
|
||||
}
|
||||
|
||||
public Person save(Person person) {
|
||||
return getPersonRepository().save(person);
|
||||
}
|
||||
|
||||
public boolean delete(Person person) {
|
||||
getPersonRepository().delete(person);
|
||||
return (find(person.getId()) == null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 org.springframework.data.gemfire.mapping.Region;
|
||||
import org.springframework.data.gemfire.repository.GemfireRepository;
|
||||
import org.springframework.data.gemfire.repository.sample.Person;
|
||||
|
||||
/**
|
||||
* The SamplePersonRepository class is a {@link GemfireRepository} implementation for performing data access (CRUD)
|
||||
* operations on instances of {@link Person}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.repository.GemfireRepository
|
||||
* @see org.springframework.data.gemfire.repository.cdi.CustomPersonRepository
|
||||
* @see org.springframework.data.gemfire.repository.cdi.SamplePersonRepositoryImpl
|
||||
* @see org.springframework.data.gemfire.repository.sample.Person
|
||||
* @since 1.8.0
|
||||
*/
|
||||
@Region("People")
|
||||
public interface SamplePersonRepository extends GemfireRepository<Person, Long>, CustomPersonRepository {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 SamplePersonRepositoryImpl class is an implementation of the {@link CustomPersonRepository} extension interface
|
||||
* supporting additional data access (CRUD) operations on people.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.repository.cdi.CustomPersonRepository
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public class SamplePersonRepositoryImpl implements CustomPersonRepository {
|
||||
|
||||
public int returnOne() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
5
src/test/resources/META-INF/beans.xml
Normal file
5
src/test/resources/META-INF/beans.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
|
||||
</beans>
|
||||
12
template.mf
12
template.mf
@@ -2,14 +2,14 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Spring Data GemFire
|
||||
Bundle-SymbolicName: org.springframework.data.gemfire
|
||||
Bundle-Vendor: Pivotal Software, Inc.
|
||||
Import-Package:
|
||||
sun.reflect;version="0";resolution:=optional
|
||||
Import-Template:
|
||||
Import-Package: sun.reflect;version="0";resolution:=optional
|
||||
Import-Template: javax.enterprise.*;version="[1.0,2.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
|
||||
org.aspectj.*;version="[1.8.2, 2.0.0)";resolution:=optional,
|
||||
com.fasterxml.jackson.*;version="[2.4.1,3.0.0)";resolution:=optional,
|
||||
com.gemstone.*;version="[8.0.0,9.0.0)",
|
||||
org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.aspectj.*;version="[1.8.2, 2.0.0)";resolution:=optional,
|
||||
org.slf4j.*;version="[1.7.0,2.0)",
|
||||
org.springframework.*;version="[4.0.6, 5.0.0)",
|
||||
org.springframework.data.*;version="[1.9.0,2.0.0)",
|
||||
org.w3c.dom.*;version="0"
|
||||
|
||||
Reference in New Issue
Block a user