diff --git a/src/main/java/org/springframework/data/gemfire/repository/config/EnableGemfireRepositories.java b/src/main/java/org/springframework/data/gemfire/repository/config/EnableGemfireRepositories.java index b520660c..da259906 100644 --- a/src/main/java/org/springframework/data/gemfire/repository/config/EnableGemfireRepositories.java +++ b/src/main/java/org/springframework/data/gemfire/repository/config/EnableGemfireRepositories.java @@ -27,14 +27,15 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Import; import org.springframework.data.gemfire.mapping.GemfireMappingContext; import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean; -import org.springframework.data.repository.config.DefaultRepositoryBaseClass; +import org.springframework.data.gemfire.repository.support.SimpleGemfireRepository; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; /** * Annotation to enable Gemfire repositories. - * + * * @author Oliver Gierke + * @author John Blum */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -90,7 +91,7 @@ public @interface EnableGemfireRepositories { * Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So * for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning * for {@code PersonRepositoryImpl}. - * + * * @return a String indicating the postfix to append to the Repository interface name when looking up the custom * Repository implementing class. */ @@ -99,7 +100,7 @@ public @interface EnableGemfireRepositories { /** * Configures the location of where to find the Spring Data named queries properties file. Will default to * {@code META-INFO/jpa-named-queries.properties}. - * + * * @return a String indicating the location of the name queries properties file. */ String namedQueriesLocation() default ""; @@ -107,7 +108,7 @@ public @interface EnableGemfireRepositories { /** * Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to * {@link Key#CREATE_IF_NOT_FOUND}. - * + * * @return the Key used to determine the Query lookup and creation strategy. */ Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND; @@ -115,7 +116,7 @@ public @interface EnableGemfireRepositories { /** * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to * {@link GemfireRepositoryFactoryBean}. - * + * * @return the {@link FactoryBean} class type used for each Repository interface. */ Class repositoryFactoryBeanClass() default GemfireRepositoryFactoryBean.class; @@ -125,12 +126,12 @@ public @interface EnableGemfireRepositories { * * @since 1.7 */ - Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; + Class repositoryBaseClass() default SimpleGemfireRepository.class; /** * Configures the name of the {@link GemfireMappingContext} bean definition to be used to create repositories * discovered through this annotation. If not configured a default one will be created. - * + * * @return the bean name of the {@link org.springframework.data.mapping.context.MappingContext} used by the * Repository to map entities to the underlying data store. */ diff --git a/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtension.java b/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtension.java index 44956394..1583c2a8 100644 --- a/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtension.java +++ b/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtension.java @@ -46,8 +46,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura private static final String GEMFIRE_MODULE_PREFIX = "gemfire"; private static final String MAPPING_CONTEXT_PROPERTY_NAME = "gemfireMappingContext"; - private static final String MAPPING_CONTEXT_REF_ANNOTATION_ATTRIBUTE = "mappingContextRef"; - private static final String MAPPING_CONTEXT_REF_XML_ATTRIBUTE = "mapping-context-ref"; + private static final String MAPPING_CONTEXT_REF_ATTRIBUTE_NAME = "mappingContextRef"; static final String DEFAULT_MAPPING_CONTEXT_BEAN_NAME = String.format("%1$s.%2$s", GemfireMappingContext.class.getName(), "DEFAULT"); @@ -95,7 +94,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura @Override public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource configurationSource) { builder.addPropertyReference(MAPPING_CONTEXT_PROPERTY_NAME, resolveMappingContextBeanName( - configurationSource.getAttribute(MAPPING_CONTEXT_REF_ANNOTATION_ATTRIBUTE))); + configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME))); } /* @@ -105,7 +104,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura @Override public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource configurationSource) { builder.addPropertyReference(MAPPING_CONTEXT_PROPERTY_NAME, resolveMappingContextBeanName( - configurationSource.getElement().getAttribute(MAPPING_CONTEXT_REF_XML_ATTRIBUTE))); + configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME))); } /* (non-Javadoc) */ @@ -122,7 +121,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura super.registerBeansForRoot(registry, configurationSource); - if (!StringUtils.hasText(configurationSource.getAttribute(MAPPING_CONTEXT_REF_ANNOTATION_ATTRIBUTE))) { + if (!StringUtils.hasText(configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME))) { registry.registerBeanDefinition(DEFAULT_MAPPING_CONTEXT_BEAN_NAME, new RootBeanDefinition(GemfireMappingContext.class)); } diff --git a/src/test/java/org/springframework/data/gemfire/repository/GemFireRepositoryFactoryInformationIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/repository/GemFireRepositoryFactoryInformationIntegrationTests.java new file mode 100644 index 00000000..5d5f80f8 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/repository/GemFireRepositoryFactoryInformationIntegrationTests.java @@ -0,0 +1,137 @@ +/* + * 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; + +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; +import java.util.Map; +import java.util.Properties; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.RegionAttributesFactoryBean; +import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories; +import org.springframework.data.gemfire.repository.sample.Person; +import org.springframework.data.gemfire.repository.sample.PersonRepository; +import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean; +import org.springframework.data.repository.core.support.RepositoryFactoryInformation; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.RegionAttributes; + +/** + * Test suite of test cases testing that the GemFire-based {@link org.springframework.data.repository.Repository} + * factories, implementing the {@link RepositoryFactoryInformation} interface, can in fact be looked up in the + * Spring {@link ApplicationContext}. + * + * @author John Blum + * @since 1.9.0 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class GemFireRepositoryFactoryInformationIntegrationTests { + + @Autowired + private ApplicationContext applicationContext; + + @Test + public void canAccessRepositoryFactoryInformationFactoryBeans() { + Map repositoryFactories = + applicationContext.getBeansOfType(RepositoryFactoryInformation.class); + + assertThat(repositoryFactories, is(notNullValue(Map.class))); + assertThat(repositoryFactories.size(), is(greaterThan(0))); + assertThat(repositoryFactories.keySet(), hasItem("&personRepository")); + assertThat(repositoryFactories.get("&personRepository"), is(instanceOf(GemfireRepositoryFactoryBean.class))); + assertThat(Arrays.asList(applicationContext.getBeanNamesForType(PersonRepository.class)), + hasItem("personRepository")); + } + + @Configuration + @EnableGemfireRepositories(basePackageClasses = { Person.class }, + includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, + value = org.springframework.data.gemfire.repository.sample.PersonRepository.class)) + static class GemFireConfiguration { + + String applicationName() { + return GemFireRepositoryFactoryInformationIntegrationTests.class.getSimpleName(); + } + + Properties gemfireProperties() { + Properties gemfireProperties = new Properties(); + + gemfireProperties.setProperty("name", applicationName()); + gemfireProperties.setProperty("mcast-port", "0"); + gemfireProperties.setProperty("log-level", "warning"); + + return gemfireProperties; + } + + @Bean + CacheFactoryBean gemfireCache() { + CacheFactoryBean gemfireCache = new CacheFactoryBean(); + + gemfireCache.setClose(true); + gemfireCache.setProperties(gemfireProperties()); + + return gemfireCache; + } + + @Bean(name = "simple") + LocalRegionFactoryBean simpleRegion(Cache gemfireCache, + RegionAttributes simpleRegionAttributes) { + + LocalRegionFactoryBean simpleRegion = new LocalRegionFactoryBean(); + + simpleRegion.setAttributes(simpleRegionAttributes); + simpleRegion.setCache(gemfireCache); + simpleRegion.setClose(false); + simpleRegion.setPersistent(false); + + return simpleRegion; + } + + @Bean + @SuppressWarnings("unchecked") + RegionAttributesFactoryBean simpleRegionAttributes() { + RegionAttributesFactoryBean simpleRegionAttributes = new RegionAttributesFactoryBean(); + + simpleRegionAttributes.setKeyConstraint(Long.class); + simpleRegionAttributes.setValueConstraint(Person.class); + + return simpleRegionAttributes; + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtensionTest.java b/src/test/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtensionTest.java index 0ff8a045..245126c9 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtensionTest.java +++ b/src/test/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryConfigurationExtensionTest.java @@ -30,17 +30,25 @@ import static org.mockito.Mockito.when; import java.lang.annotation.Annotation; import java.util.Collection; -import org.junit.Before; import org.junit.Test; import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.PassThroughSourceExtractor; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.factory.xml.XmlReaderContext; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; import org.springframework.data.gemfire.mapping.Region; import org.springframework.data.gemfire.repository.GemfireRepository; import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean; import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; import org.springframework.data.repository.config.XmlRepositoryConfigurationSource; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; /** * Test suite of test cases testing the contract and functionality of the @@ -54,14 +62,52 @@ import org.w3c.dom.Element; */ public class GemfireRepositoryConfigurationExtensionTest { - private GemfireRepositoryConfigurationExtension repositoryConfigurationExtension; + private GemfireRepositoryConfigurationExtension repositoryConfigurationExtension = + new GemfireRepositoryConfigurationExtension(); - private RuntimeBeanReference defaultMappingContextReference = new RuntimeBeanReference( - GemfireRepositoryConfigurationExtension.DEFAULT_MAPPING_CONTEXT_BEAN_NAME); + protected Object getPropertyValue(BeanDefinitionBuilder builder, String propertyName) { + return getPropertyValue(builder.getRawBeanDefinition(), propertyName); + } - @Before - public void setup() { - repositoryConfigurationExtension = new GemfireRepositoryConfigurationExtension(); + protected Object getPropertyValue(BeanDefinition beanDefinition, String propertyName) { + PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue(propertyName); + + return (propertyValue != null ? propertyValue.getValue() : null); + } + + protected Element mockElement() { + Element mockElement = mock(Element.class); + NodeList mockNodeList = mock(NodeList.class); + + when(mockNodeList.getLength()).thenReturn(0); + when(mockElement.getChildNodes()).thenReturn(mockNodeList); + + return mockElement; + } + + protected Environment mockEnvironment() { + return mock(Environment.class); + } + + protected ParserContext mockParserContext() { + XmlReaderContext xmlReaderContext = mockXmlReaderContext(); + + return new ParserContext(xmlReaderContext, newBeanDefinitionParserDelegate(xmlReaderContext)); + } + + protected XmlReaderContext mockXmlReaderContext() { + ResourceLoader mockResourceLoader = mock(ResourceLoader.class); + XmlBeanDefinitionReader mockXmlBeanDefinitionReader = mock(XmlBeanDefinitionReader.class); + + when(mockResourceLoader.getClassLoader()).thenReturn(Thread.currentThread().getContextClassLoader()); + when(mockXmlBeanDefinitionReader.getResourceLoader()).thenReturn(mockResourceLoader); + + return new XmlReaderContext(null, null, null, new PassThroughSourceExtractor(), + mockXmlBeanDefinitionReader, null); + } + + protected BeanDefinitionParserDelegate newBeanDefinitionParserDelegate(XmlReaderContext readerContext) { + return new BeanDefinitionParserDelegate(readerContext); } @Test @@ -103,8 +149,7 @@ public class GemfireRepositoryConfigurationExtensionTest { repositoryConfigurationExtension.postProcess(beanDefinitionBuilder, mockRepositoryConfigurationSource); - Object mappingContextRef = beanDefinitionBuilder.getRawBeanDefinition().getPropertyValues() - .getPropertyValue("gemfireMappingContext").getValue(); + Object mappingContextRef = getPropertyValue(beanDefinitionBuilder, "gemfireMappingContext"); assertThat(mappingContextRef, is(instanceOf(RuntimeBeanReference.class))); assertThat(((RuntimeBeanReference) mappingContextRef).getBeanName(), is(equalTo("testMappingContext"))); @@ -123,58 +168,55 @@ public class GemfireRepositoryConfigurationExtensionTest { repositoryConfigurationExtension.postProcess(beanDefinitionBuilder, mockRepositoryConfigurationSource); - PropertyValue mappingContextRef = beanDefinitionBuilder.getRawBeanDefinition().getPropertyValues() - .getPropertyValue("gemfireMappingContext"); + Object mappingContextRef = getPropertyValue(beanDefinitionBuilder, "gemfireMappingContext"); - assertThat(mappingContextRef.getValue(), is(equalTo((Object) defaultMappingContextReference))); + assertThat(mappingContextRef, is(instanceOf(RuntimeBeanReference.class))); + assertThat(((RuntimeBeanReference) mappingContextRef).getBeanName(), + is(equalTo(GemfireRepositoryConfigurationExtension.DEFAULT_MAPPING_CONTEXT_BEAN_NAME))); verify(mockRepositoryConfigurationSource, times(1)).getAttribute(eq("mappingContextRef")); } @Test public void postProcessWithXmlRepositoryConfigurationSource() { - Element mockElement = mock(Element.class); + Element mockElement = mockElement(); - XmlRepositoryConfigurationSource mockRepositoryConfigurationSource = - mock(XmlRepositoryConfigurationSource.class); - - when(mockRepositoryConfigurationSource.getElement()).thenReturn(mockElement); when(mockElement.getAttribute(eq("mapping-context-ref"))).thenReturn("testMappingContext"); + XmlRepositoryConfigurationSource repositoryConfigurationSource = new XmlRepositoryConfigurationSource( + mockElement, mockParserContext(), mockEnvironment()); + BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(); - repositoryConfigurationExtension.postProcess(beanDefinitionBuilder, mockRepositoryConfigurationSource); + repositoryConfigurationExtension.postProcess(beanDefinitionBuilder, repositoryConfigurationSource); - Object mappingContextRef = beanDefinitionBuilder.getRawBeanDefinition().getPropertyValues() - .getPropertyValue("gemfireMappingContext").getValue(); + Object mappingContextRef = getPropertyValue(beanDefinitionBuilder, "gemfireMappingContext"); assertThat(mappingContextRef, is(instanceOf(RuntimeBeanReference.class))); assertThat(((RuntimeBeanReference) mappingContextRef).getBeanName(), is(equalTo("testMappingContext"))); - verify(mockRepositoryConfigurationSource, times(1)).getElement(); verify(mockElement, times(1)).getAttribute(eq("mapping-context-ref")); } @Test public void postProcessWithXmlRepositoryConfigurationSourceHavingNoMappingContextRefAttribute() { - Element mockElement = mock(Element.class); + Element mockElement = mockElement(); - XmlRepositoryConfigurationSource mockRepositoryConfigurationSource = - mock(XmlRepositoryConfigurationSource.class); - - when(mockRepositoryConfigurationSource.getElement()).thenReturn(mockElement); when(mockElement.getAttribute(eq("mapping-context-ref"))).thenReturn(null); + XmlRepositoryConfigurationSource repositoryConfigurationSource = new XmlRepositoryConfigurationSource( + mockElement, mockParserContext(), mockEnvironment()); + BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(); - repositoryConfigurationExtension.postProcess(beanDefinitionBuilder, mockRepositoryConfigurationSource); + repositoryConfigurationExtension.postProcess(beanDefinitionBuilder, repositoryConfigurationSource); - PropertyValue mappingContextRef = beanDefinitionBuilder.getRawBeanDefinition().getPropertyValues() - .getPropertyValue("gemfireMappingContext"); + Object mappingContextRef = getPropertyValue(beanDefinitionBuilder, "gemfireMappingContext"); - assertThat(mappingContextRef.getValue(), is(equalTo((Object) defaultMappingContextReference))); + assertThat(mappingContextRef, is(instanceOf(RuntimeBeanReference.class))); + assertThat(((RuntimeBeanReference) mappingContextRef).getBeanName(), + is(equalTo(GemfireRepositoryConfigurationExtension.DEFAULT_MAPPING_CONTEXT_BEAN_NAME))); - verify(mockRepositoryConfigurationSource, times(1)).getElement(); verify(mockElement, times(1)).getAttribute(eq("mapping-context-ref")); } }