diff --git a/build.gradle b/build.gradle
index 27e33509..03aafdc9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -47,7 +47,7 @@ allprojects {
mavenRepo name: "spring-snapshot", urls: "http://maven.springframework.org/snapshot"
mavenRepo name: "sonatype-snapshot", urls: "http://oss.sonatype.org/content/repositories/snapshots"
mavenRepo name: "ext-snapshots", urls: "http://springframework.svn.sourceforge.net/svnroot/springframework/repos/repo-ext/"
- mavenRepo name: "gemstone-com-release", urls: "http://dist.gemstone.com/maven/release"
+ mavenRepo name: "gemstone-com-release", urls: "http://repo.springsource.org/gemstone-release"
}
}
@@ -87,10 +87,15 @@ dependencies {
compile("com.gemstone.gemfire:gemfire:$gemfireVersion")
// Testing
- testCompile "junit:junit:$junitVersion"
+ testCompile "junit:junit-dep:$junitVersion"
testCompile "org.mockito:mockito-core:$mockitoVersion"
+ testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion"
+ testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
testCompile "org.springframework:spring-test:$springVersion"
testCompile("javax.annotation:jsr250-api:1.0") { optional = true }
+
+ // Spring Data
+ compile "org.springframework.data:spring-data-commons-core:${springDataCommonsVersion}"
}
javaprojects = rootProject
diff --git a/docs/src/reference/docbook/index.xml b/docs/src/reference/docbook/index.xml
index b6bc2654..48119e0b 100644
--- a/docs/src/reference/docbook/index.xml
+++ b/docs/src/reference/docbook/index.xml
@@ -13,6 +13,11 @@
LeauSpringSource, a division of VMware
+
+ Oliver
+ Gierke
+ SpringSource, a division of VMware
+
@@ -41,6 +46,11 @@
+
+
+
+
+
diff --git a/docs/src/reference/docbook/reference/mapping.xml b/docs/src/reference/docbook/reference/mapping.xml
new file mode 100644
index 00000000..03409452
--- /dev/null
+++ b/docs/src/reference/docbook/reference/mapping.xml
@@ -0,0 +1,84 @@
+
+
+ POJO mapping
+
+
+ Entity mapping
+
+ Spring Data Gemfire provides support to map entities to be stored in
+ a Gemfire grid. The mapping metadata is define by using annotations at the
+ domain classes just like this:
+
+
+ Mapping a domain class to Gemfire
+
+ @Region("myRegion")
+public class Person {
+
+ @Id Long id;
+ String firstname;
+ String lastname;
+
+ @PersistenceConstructor
+ public Person(String firstname, String lastname) {
+ // …
+ }
+
+ …
+}
+
+
+ The first thing you see here is the
+ @Region annotation that can be used to
+ customize the region instances of the Person class
+ are stored in. The @Id annotation can be
+ used to annotate the property that shall be used as cache key. The
+ @PersistenceConstructor annotation actually
+ helps disambiguing multiple potentially available constructors taking
+ parameters and explicitly marking the one annotated as the one to be used
+ to create entities. With none or only a single constructor you can omit
+ the annotation.
+
+
+
+ Mapping PDX serializer
+
+ Spring Data Gemfire provides a custom
+ PDXSerializer implementation that uses the
+ mapping information to customize entity serialization. Beyond that it
+ allows customizing the entity instantiation by using the Spring Data
+ EntityInstantiator abstraction. By default
+ the serializer uses a ReflectionEntityInstantiator
+ that will use the persistence constructor of the mapped entity (either the
+ single declared one or explicitly annoted with
+ @PersistenceConstructor). To provide values
+ for constructor parameters it will read fields with name of the
+ constructor parameters from the PDXReader
+ supplied.
+
+
+ Using @Value on entity constructor parameters
+
+ public class Person {
+
+ public Person(@Value("#root.foo") String firstname, @Value("bean") String lastname) {
+ // …
+ }
+
+ …
+}
+
+
+ The entity annotated as such will get the field foo
+ read from the PDXReader and handed as
+ constructor parameter value for firstname. The value for
+ lastname will be the Spring bean with name
+ bean.
+
+
diff --git a/docs/src/reference/docbook/reference/repositories.xml b/docs/src/reference/docbook/reference/repositories.xml
new file mode 100644
index 00000000..1e4c0cbe
--- /dev/null
+++ b/docs/src/reference/docbook/reference/repositories.xml
@@ -0,0 +1,218 @@
+
+
+ Gemfire Repositories
+
+
+ Introduction
+
+ Spring Data Gemfire provides support to use the Spring Data
+ repository abstraction to easily persist entities into Gemfire and execute
+ queries. A general introduction into the repository programmin model has
+ been provided in .
+
+
+
+ Spring configuration
+
+ To bootstrap Spring Data repositories you use the
+ <repositories /> element from the Gemfire
+ namespace:
+
+
+ Bootstrap Gemfire repositories
+
+ <beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:gf="http://www.springframework.org/schema/gemfire"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/gemfire
+ http://www.springframework.org/schema/gemfire/spring-gemfire.xsd>
+
+ <gf:repositories base-package="com.acme.repository" />
+
+</beans>
+
+
+ This configuration snippet will look for interfaces below the
+ configured base package and create repository instances for those
+ interfaces backed by a SimpleGemfireRepository.
+ Note that you have to have your domain classes correctly mapped to
+ configured regions as the bottstrap process will fail otherwise.
+
+
+
+ Executing OQL queries
+
+ The Gemfire repositories allow the definition of query methods to
+ easily execute OQL queries against the Region the managed entity is mapped
+ to.
+
+
+ Sample repository
+
+ @Region("myRegion")
+public class Person { … }
+
+ public interface PersonRepository extends CrudRepository<Person, Long> {
+
+ Person findByEmailAddress(String emailAddress);
+
+ Collection<Person> findByFirstname(String firstname);
+
+ @Query("SELECT * FROM /Person p WHERE p.firstname = $1")
+ Collection<Person> findByFirstnameAnnotated(String firstname);
+
+ @Query("SELECT * FROM /Person p WHERE p.firstname IN SET $1")
+ Collection<Person> findByFirstnamesAnnotated(Collection<String> firstnames);
+}
+
+
+ The first method listed here will cause the following query to be
+ derived: SELECT x FROM /myRegion x WHERE x.emailAddress = $1.
+ The second method works the same way except it's returning all entities
+ found whereas the first one expects a single result value. In case the
+ supported keywords are not sufficient to declare your query or the method
+ name gets to verbose you can annotate the query methods with
+ @Query as seen for methods 3 and 4.
+
+
+
+
diff --git a/gradle.properties b/gradle.properties
index cc97c3f2..db667a51 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,11 +6,13 @@ slf4jVersion = 1.6.4
# Common libraries
springVersion = 3.1.0.RELEASE
+springDataCommonsVersion = 1.3.0.M1
gemfireVersion = 6.6.1
# Testing
junitVersion = 4.8.1
mockitoVersion = 1.8.5
+hamcrestVersion = 1.2.1
# Manifest properties
diff --git a/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java b/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java
index 57eeafe6..68f52bfa 100644
--- a/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java
+++ b/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java
@@ -17,6 +17,7 @@
package org.springframework.data.gemfire.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+import org.springframework.data.gemfire.repository.config.GemfireRepositoryParser;
/**
* Namespace handler for GemFire definitions.
@@ -40,5 +41,7 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("transaction-manager", new TransactionManagerParser());
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
+
+ registerBeanDefinitionParser("repositories", new GemfireRepositoryParser());
}
}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java
new file mode 100644
index 00000000..bc5c47fb
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java
@@ -0,0 +1,50 @@
+/*
+ * 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.mapping;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+
+import org.springframework.data.mapping.context.AbstractMappingContext;
+import org.springframework.data.mapping.model.SimpleTypeHolder;
+import org.springframework.data.util.TypeInformation;
+
+/**
+ *
+ * @author Oliver Gierke
+ */
+public class GemfireMappingContext extends
+ AbstractMappingContext, GemfirePersistentProperty> {
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
+ */
+ @Override
+ protected GemfirePersistentEntity> createPersistentEntity(TypeInformation typeInformation) {
+ return new GemfirePersistentEntity(typeInformation);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
+ */
+ @Override
+ protected GemfirePersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
+ GemfirePersistentEntity> owner, SimpleTypeHolder simpleTypeHolder) {
+ return new GemfirePersistentProperty(field, descriptor, owner, simpleTypeHolder);
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java
new file mode 100644
index 00000000..9cb5878e
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java
@@ -0,0 +1,57 @@
+/*
+ * 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.mapping;
+
+import org.springframework.data.mapping.PersistentEntity;
+import org.springframework.data.mapping.model.BasicPersistentEntity;
+import org.springframework.data.util.TypeInformation;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@link PersistentEntity} implementation adding custom Gemfire related metadata, such as the region the entity is
+ * mapped to etc.
+ *
+ * @author Oliver Gierke
+ */
+public class GemfirePersistentEntity extends BasicPersistentEntity {
+
+ private final String regionName;
+
+ /**
+ * Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
+ *
+ * @param information must not be {@literal null}.
+ */
+ public GemfirePersistentEntity(TypeInformation information) {
+
+ super(information);
+
+ Class rawType = information.getType();
+ Region region = rawType.getAnnotation(Region.class);
+ String fallbackName = rawType.getSimpleName();
+
+ this.regionName = region == null || !StringUtils.hasText(region.value()) ? fallbackName : region.value();
+ }
+
+ /**
+ * Returns the name of the region the entity shall be stored in.
+ *
+ * @return
+ */
+ public String getRegionName() {
+ return this.regionName;
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java
new file mode 100644
index 00000000..ea04d880
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java
@@ -0,0 +1,52 @@
+/*
+ * 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.mapping;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+
+import org.springframework.data.mapping.Association;
+import org.springframework.data.mapping.PersistentEntity;
+import org.springframework.data.mapping.PersistentProperty;
+import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
+import org.springframework.data.mapping.model.SimpleTypeHolder;
+
+/**
+ * {@link PersistentProperty} implementation to for Gemfire related metadata.
+ *
+ * @author Oliver Gierke
+ */
+public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty {
+
+ /**
+ * @param field
+ * @param propertyDescriptor
+ * @param owner
+ * @param simpleTypeHolder
+ */
+ public GemfirePersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
+ PersistentEntity, GemfirePersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
+ super(field, propertyDescriptor, owner, simpleTypeHolder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
+ */
+ @Override
+ protected Association createAssociation() {
+ return null;
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePropertyValueProvider.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePropertyValueProvider.java
new file mode 100644
index 00000000..e674a47d
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePropertyValueProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.mapping;
+
+import org.springframework.data.mapping.model.PropertyValueProvider;
+import org.springframework.util.Assert;
+
+import com.gemstone.gemfire.pdx.PdxReader;
+
+/**
+ * {@link PropertyValueProvider} to read property values from a {@link PdxReader}.
+ *
+ * @author Oliver Gierke
+ */
+class GemfirePropertyValueProvider implements PropertyValueProvider {
+
+ private final PdxReader reader;
+
+ /**
+ * Creates a new {@link GemfirePropertyValueProvider} with the given {@link PdxReader}.
+ *
+ * @param reader must not be {@literal null}.
+ */
+ public GemfirePropertyValueProvider(PdxReader reader) {
+ Assert.notNull(reader);
+ this.reader = reader;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.convert.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getPropertyValue(GemfirePersistentProperty property) {
+ return (T) reader.readObject(property.getName());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java b/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java
new file mode 100644
index 00000000..439b92d2
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java
@@ -0,0 +1,156 @@
+/*
+ * 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.mapping;
+
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.convert.ConversionService;
+import org.springframework.data.convert.EntityInstantiator;
+import org.springframework.data.convert.EntityInstantiators;
+import org.springframework.data.mapping.PersistentEntity;
+import org.springframework.data.mapping.PropertyHandler;
+import org.springframework.data.mapping.model.BeanWrapper;
+import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
+import org.springframework.data.mapping.model.MappingException;
+import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
+import org.springframework.data.mapping.model.SpELContext;
+import org.springframework.util.Assert;
+
+import com.gemstone.gemfire.pdx.PdxReader;
+import com.gemstone.gemfire.pdx.PdxSerializer;
+import com.gemstone.gemfire.pdx.PdxWriter;
+
+/**
+ * {@link PdxSerializer} implementation that uses a {@link GemfireMappingContext} to read and write entities.
+ *
+ * @author Oliver Gierke
+ */
+public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAware {
+
+ private final GemfireMappingContext mappingContext;
+ private final ConversionService conversionService;
+
+ private EntityInstantiators instantiators;
+ private SpELContext context;
+
+ /**
+ * Creates a new {@link MappingPdxSerializer} using the given {@link GemfireMappingContext} and
+ * {@link ConversionService}.
+ *
+ * @param mappingContext must not be {@literal null}.
+ * @param conversionService must not be {@literal null}.
+ */
+ public MappingPdxSerializer(GemfireMappingContext mappingContext, ConversionService conversionService) {
+
+ Assert.notNull(mappingContext);
+ Assert.notNull(conversionService);
+
+ this.mappingContext = mappingContext;
+ this.conversionService = conversionService;
+ this.instantiators = new EntityInstantiators();
+ this.context = new SpELContext(PdxReaderPropertyAccessor.INSTANCE);
+ }
+
+ /**
+ * Configures the {@link EntityInstantiator}s to be used to create the instances to be read.
+ *
+ * @param gemfireInstantiators must not be {@literal null}.
+ */
+ public void setGemfireInstantiators(Map, EntityInstantiator> gemfireInstantiators) {
+ Assert.notNull(gemfireInstantiators);
+ this.instantiators = new EntityInstantiators(gemfireInstantiators);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
+ */
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.context = new SpELContext(context, applicationContext);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.gemstone.gemfire.pdx.PdxSerializer#fromData(java.lang.Class, com.gemstone.gemfire.pdx.PdxReader)
+ */
+ public Object fromData(Class> type, final PdxReader reader) {
+
+ final GemfirePersistentEntity> entity = mappingContext.getPersistentEntity(type);
+ EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
+ GemfirePropertyValueProvider propertyValueProvider = new GemfirePropertyValueProvider(reader);
+
+ PersistentEntityParameterValueProvider provider = new PersistentEntityParameterValueProvider(
+ entity, propertyValueProvider);
+ provider.setSpELEvaluator(new DefaultSpELExpressionEvaluator(reader, context));
+
+ Object instance = instantiator.createInstance(entity, provider);
+
+ final BeanWrapper, Object> wrapper = BeanWrapper.create(instance, conversionService);
+
+ entity.doWithProperties(new PropertyHandler() {
+ public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
+
+ if (entity.isConstructorArgument(persistentProperty)) {
+ return;
+ }
+
+ Object value = reader.readField(persistentProperty.getName());
+
+ try {
+ wrapper.setProperty(persistentProperty, value);
+ } catch (Exception e) {
+ throw new MappingException("Could not read value " + value.toString(), e);
+ }
+ }
+ });
+
+ return wrapper.getBean();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.gemstone.gemfire.pdx.PdxSerializer#toData(java.lang.Object, com.gemstone.gemfire.pdx.PdxWriter)
+ */
+ public boolean toData(Object value, final PdxWriter writer) {
+
+ GemfirePersistentEntity> entity = mappingContext.getPersistentEntity(value.getClass());
+ final BeanWrapper, Object> wrapper = BeanWrapper.create(value, conversionService);
+
+ entity.doWithProperties(new PropertyHandler() {
+ public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
+
+ try {
+ Object value = wrapper.getProperty(persistentProperty);
+ writer.writeObject(persistentProperty.getName(), value);
+ } catch (Exception e) {
+ throw new MappingException("Could not write value for property " + persistentProperty.toString(), e);
+ }
+ }
+ });
+
+ GemfirePersistentProperty idProperty = entity.getIdProperty();
+
+ if (idProperty != null) {
+ writer.markIdentityField(idProperty.getName());
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/PdxReaderPropertyAccessor.java b/src/main/java/org/springframework/data/gemfire/mapping/PdxReaderPropertyAccessor.java
new file mode 100644
index 00000000..4e52e7b9
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/PdxReaderPropertyAccessor.java
@@ -0,0 +1,78 @@
+/*
+ * 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.mapping;
+
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.PropertyAccessor;
+import org.springframework.expression.TypedValue;
+
+import com.gemstone.gemfire.pdx.PdxReader;
+
+/**
+ * {@link PropertyAccessor} to read values from a {@link PdxReader}.
+ *
+ * @author Oliver Gierke
+ */
+enum PdxReaderPropertyAccessor implements PropertyAccessor {
+
+ INSTANCE;
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.expression.PropertyAccessor#getSpecificTargetClasses()
+ */
+ @Override
+ public Class>[] getSpecificTargetClasses() {
+ return new Class>[] { PdxReader.class };
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.expression.PropertyAccessor#canRead(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
+ */
+ @Override
+ public boolean canRead(EvaluationContext context, Object target, String name) {
+ return ((PdxReader) target).hasField(name);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.expression.PropertyAccessor#read(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
+ */
+ @Override
+ public TypedValue read(EvaluationContext context, Object target, String name) {
+ Object object = ((PdxReader) target).readObject(name);
+ return object == null ? TypedValue.NULL : new TypedValue(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.expression.PropertyAccessor#canWrite(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
+ */
+ @Override
+ public boolean canWrite(EvaluationContext context, Object target, String name) {
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.expression.PropertyAccessor#write(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ @Override
+ public void write(EvaluationContext context, Object target, String name, Object newValue) {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/Region.java b/src/main/java/org/springframework/data/gemfire/mapping/Region.java
new file mode 100644
index 00000000..726c0478
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/Region.java
@@ -0,0 +1,42 @@
+/*
+ * 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.mapping;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to define the region an entity will be stored in.
+ *
+ * @author Oliver Gierke
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface Region {
+
+ /**
+ * The name of the {@link com.gemstone.gemfire.cache.Region} the entity shall be stored in.
+ *
+ * @return the name of the region the entity shall be persisted in.
+ */
+ String value() default "";
+}
diff --git a/src/main/java/org/springframework/data/gemfire/mapping/Regions.java b/src/main/java/org/springframework/data/gemfire/mapping/Regions.java
new file mode 100644
index 00000000..70c3ebb6
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/mapping/Regions.java
@@ -0,0 +1,98 @@
+/*
+ * 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.mapping;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.springframework.data.mapping.context.MappingContext;
+import org.springframework.util.Assert;
+
+import com.gemstone.bp.edu.emory.mathcs.backport.java.util.Collections;
+import com.gemstone.gemfire.cache.Region;
+
+/**
+ * Simple value object to abstract access to regions by name and mapped type.
+ *
+ * @author Oliver Gierke
+ */
+public class Regions implements Iterable> {
+
+ private final Map> regions;
+ private final MappingContext extends GemfirePersistentEntity>, ?> context;
+
+ /**
+ * Creates a new {@link Regions} wrapper for the given {@link Region}s and {@link MappingContext}.
+ *
+ * @param regions must not be {@literal null}.
+ * @param context must not be {@literal null}.
+ */
+ @SuppressWarnings("unchecked")
+ public Regions(Iterable> regions, MappingContext extends GemfirePersistentEntity>, ?> context) {
+
+ Assert.notNull(regions);
+ Assert.notNull(context);
+
+ Map> regionMap = new HashMap>();
+
+ for (Region, ?> region : regions) {
+ regionMap.put(region.getName(), region);
+ }
+
+ this.regions = Collections.unmodifiableMap(regionMap);
+ this.context = context;
+ }
+
+ /**
+ * Returns the {@link Region} the given type is mapped to. Will try to find a {@link Region} with the simple class
+ * name in case no mapping information is found.
+ *
+ * @param type must not be {@literal null}.
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public Region, T> getRegion(Class type) {
+
+ Assert.notNull(type);
+
+ GemfirePersistentEntity> entity = context.getPersistentEntity(type);
+ return (Region, T>) (entity == null ? regions.get(type.getSimpleName()) : regions.get(entity.getRegionName()));
+ }
+
+ /**
+ * Returns the region with the given name.
+ *
+ * @param name must not be {@literal null}.
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public Region getRegion(String name) {
+
+ Assert.notNull(name);
+
+ return (Region) regions.get(name);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Iterable#iterator()
+ */
+ @Override
+ public Iterator> iterator() {
+ return regions.values().iterator();
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/GemfireRepository.java b/src/main/java/org/springframework/data/gemfire/repository/GemfireRepository.java
new file mode 100644
index 00000000..ec4b935c
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/GemfireRepository.java
@@ -0,0 +1,30 @@
+/*
+ * 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 java.io.Serializable;
+
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * Gemfire-specific extension of the {@link CrudRepository} interface.
+ *
+ * @author Oliver Gierke
+ */
+public interface GemfireRepository extends CrudRepository {
+
+ T save(Wrapper wrapper);
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/Query.java b/src/main/java/org/springframework/data/gemfire/repository/Query.java
new file mode 100644
index 00000000..b6e6cfd2
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/Query.java
@@ -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;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author Oliver Gierke
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Query {
+
+ String value() default "";
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/Wrapper.java b/src/main/java/org/springframework/data/gemfire/repository/Wrapper.java
new file mode 100644
index 00000000..97a664a6
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/Wrapper.java
@@ -0,0 +1,95 @@
+/*
+ * 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 java.io.Serializable;
+
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Simple value object to hold an entity alongside an external key the entity shall be stored under.
+ *
+ * @author Oliver Gierke
+ */
+public final class Wrapper {
+
+ private final KEY key;
+ private final T entity;
+
+ /**
+ * The entity to handle as well as the key.
+ *
+ * @param entity
+ * @param key must not be {@literal null}.
+ */
+ public Wrapper(T entity, KEY key) {
+
+ Assert.notNull(key);
+
+ this.entity = entity;
+ this.key = key;
+ }
+
+ /**
+ * @return the key
+ */
+ public KEY getKey() {
+ return key;
+ }
+
+ /**
+ * @return the entity
+ */
+ public T getEntity() {
+ return entity;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object value) {
+
+ if (this == value) {
+ return true;
+ }
+
+ if (!(value instanceof Wrapper)) {
+ return false;
+ }
+
+ Wrapper, ?> that = (Wrapper, ?>) value;
+
+ return this.key.equals(that.key) && ObjectUtils.nullSafeEquals(this.entity, that.entity);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+
+ result += 31 * key.hashCode();
+ result += 31 * ObjectUtils.nullSafeHashCode(entity);
+
+ return result;
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryParser.java b/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryParser.java
new file mode 100644
index 00000000..7b6c40dd
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/config/GemfireRepositoryParser.java
@@ -0,0 +1,40 @@
+/*
+ * 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.config;
+
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.data.gemfire.repository.config.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration;
+import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean;
+import org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser;
+import org.w3c.dom.Element;
+
+/**
+ * {@link BeanDefinitionParser} to create {@link GemfireRepositoryFactoryBean}.
+ *
+ * @author Oliver Gierke
+ */
+public class GemfireRepositoryParser extends
+ AbstractRepositoryConfigDefinitionParser {
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#getGlobalRepositoryConfigInformation(org.w3c.dom.Element)
+ */
+ @Override
+ protected SimpleGemfireRepositoryConfiguration getGlobalRepositoryConfigInformation(Element element) {
+ return new SimpleGemfireRepositoryConfiguration(element);
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/config/SimpleGemfireRepositoryConfiguration.java b/src/main/java/org/springframework/data/gemfire/repository/config/SimpleGemfireRepositoryConfiguration.java
new file mode 100644
index 00000000..afa04ff7
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/config/SimpleGemfireRepositoryConfiguration.java
@@ -0,0 +1,135 @@
+/*
+ * 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.config;
+
+import org.springframework.data.gemfire.GemfireTemplate;
+import org.springframework.data.gemfire.repository.config.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration;
+import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean;
+import org.springframework.data.repository.config.AutomaticRepositoryConfigInformation;
+import org.springframework.data.repository.config.ManualRepositoryConfigInformation;
+import org.springframework.data.repository.config.RepositoryConfig;
+import org.springframework.data.repository.config.SingleRepositoryConfigInformation;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Repository configuration implementation.
+ *
+ * @author Oliver Gierke
+ */
+class SimpleGemfireRepositoryConfiguration extends
+ RepositoryConfig {
+
+ private static final String GEMFIRE_TEMPLATE_REF = "gemfire-template-ref";
+
+ /**
+ * Creates a new {@link SimpleGemfireRepositoryConfiguration} for the given {@link Element}.
+ *
+ * @param repositoriesElement must not be {@literal null}.
+ */
+ protected SimpleGemfireRepositoryConfiguration(Element repositoriesElement) {
+ super(repositoriesElement, GemfireRepositoryFactoryBean.class.getName());
+ }
+
+ /**
+ * Returns the bean name of the {@link GemfireTemplate} to be used.
+ *
+ * @return
+ */
+ String getGemfireTemplateRef() {
+
+ String attribute = getSource().getAttribute(GEMFIRE_TEMPLATE_REF);
+ return StringUtils.hasText(attribute) ? attribute : null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.config.GlobalRepositoryConfigInformation#getAutoconfigRepositoryInformation(java.lang.String)
+ */
+ @Override
+ public GemfireRepositoryConfiguration getAutoconfigRepositoryInformation(String interfaceName) {
+ return new AutomaticGemfireRepositoryConfiguration(interfaceName, this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.config.CommonRepositoryConfigInformation#getNamedQueriesLocation()
+ */
+ @Override
+ public String getNamedQueriesLocation() {
+ return "classpath*:META-INF/gemfire-named-queries.properties";
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.config.RepositoryConfig#createSingleRepositoryConfigInformationFor(org.w3c.dom.Element)
+ */
+ @Override
+ protected GemfireRepositoryConfiguration createSingleRepositoryConfigInformationFor(Element element) {
+ return new ManualGemfireRepositoryConfiguration(element, this);
+ }
+
+ public interface GemfireRepositoryConfiguration extends
+ SingleRepositoryConfigInformation {
+
+ String getGemfireTemplateRef();
+ }
+
+ static class ManualGemfireRepositoryConfiguration extends
+ ManualRepositoryConfigInformation implements GemfireRepositoryConfiguration {
+
+ /**
+ * @param element
+ * @param parent
+ */
+ public ManualGemfireRepositoryConfiguration(Element element, SimpleGemfireRepositoryConfiguration parent) {
+ super(element, parent);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.gemfire.config.GemfireRepositoryParser.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration#getGemfireTemplateRef()
+ */
+ @Override
+ public String getGemfireTemplateRef() {
+ return getAttribute(GEMFIRE_TEMPLATE_REF);
+ }
+
+ }
+
+ static class AutomaticGemfireRepositoryConfiguration extends
+ AutomaticRepositoryConfigInformation implements
+ GemfireRepositoryConfiguration {
+
+ /**
+ * @param interfaceName
+ * @param parent
+ */
+ public AutomaticGemfireRepositoryConfiguration(String interfaceName, SimpleGemfireRepositoryConfiguration parent) {
+ super(interfaceName, parent);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.gemfire.config.GemfireRepositoryParser.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration#getGemfireTemplateRef()
+ */
+ @Override
+ public String getGemfireTemplateRef() {
+
+ return getParent().getGemfireTemplateRef();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/springframework/data/gemfire/repository/package-info.java b/src/main/java/org/springframework/data/gemfire/repository/package-info.java
new file mode 100644
index 00000000..d5292d78
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Implementations of Spring Data COmmons Core repository abstraction.
+ */
+package org.springframework.data.gemfire.repository;
+
diff --git a/src/main/java/org/springframework/data/gemfire/repository/query/DefaultGemfireEntityInformation.java b/src/main/java/org/springframework/data/gemfire/repository/query/DefaultGemfireEntityInformation.java
new file mode 100644
index 00000000..944f0d9c
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/query/DefaultGemfireEntityInformation.java
@@ -0,0 +1,52 @@
+/*
+ * 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.query;
+
+import java.io.Serializable;
+
+import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
+import org.springframework.data.repository.core.support.DelegatingEntityInformation;
+import org.springframework.data.repository.core.support.ReflectionEntityInformation;
+
+/**
+ * Implementation of {@link GemfireEntityInformation} using reflection to lookup region names.
+ *
+ * @author Oliver Gierke
+ */
+public class DefaultGemfireEntityInformation extends DelegatingEntityInformation
+ implements GemfireEntityInformation {
+
+ private final GemfirePersistentEntity entity;
+
+ /**
+ * Creates a new {@link DefaultGemfireEntityInformation}.
+ *
+ * @param domainClass must not be {@literal null}.
+ */
+ public DefaultGemfireEntityInformation(GemfirePersistentEntity entity) {
+ super(new ReflectionEntityInformation(entity.getType()));
+ this.entity = entity;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.gemfire.repository.query.GemfireEntityInformation#getRegionName()
+ */
+ @Override
+ public String getRegionName() {
+ return entity.getRegionName();
+ }
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/query/GemfireEntityInformation.java b/src/main/java/org/springframework/data/gemfire/repository/query/GemfireEntityInformation.java
new file mode 100644
index 00000000..1b44fde7
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/query/GemfireEntityInformation.java
@@ -0,0 +1,37 @@
+/*
+ * 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.query;
+
+import java.io.Serializable;
+
+import org.springframework.data.repository.core.EntityInformation;
+
+import com.gemstone.gemfire.cache.Region;
+
+/**
+ * {@link EntityInformation} to capture Gemfire specific information.
+ *
+ * @author Oliver Gierke
+ */
+public interface GemfireEntityInformation extends EntityInformation {
+
+ /**
+ * Returns the name of the {@link Region} the entity is held in.
+ *
+ * @return
+ */
+ String getRegionName();
+}
diff --git a/src/main/java/org/springframework/data/gemfire/repository/query/GemfireQueryCreator.java b/src/main/java/org/springframework/data/gemfire/repository/query/GemfireQueryCreator.java
new file mode 100644
index 00000000..0d28e039
--- /dev/null
+++ b/src/main/java/org/springframework/data/gemfire/repository/query/GemfireQueryCreator.java
@@ -0,0 +1,143 @@
+/*
+ * 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.query;
+
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
+import org.springframework.data.repository.query.parser.AbstractQueryCreator;
+import org.springframework.data.repository.query.parser.Part;
+import org.springframework.data.repository.query.parser.PartTree;
+
+/**
+ * Query creator to create {@link QueryString} instances.
+ *
+ * @author Oliver Gierke
+ */
+class GemfireQueryCreator extends AbstractQueryCreator {
+
+ private static final Log LOG = LogFactory.getLog(GemfireQueryCreator.class);
+
+ private final QueryBuilder query;
+ private Iterator indexes;
+
+ /**
+ * Creates a new {@link GemfireQueryCreator} using the given {@link PartTree} and domain class.
+ *
+ * @param tree must not be {@literal null}.
+ * @param entity must not be {@literal null}.
+ */
+ public GemfireQueryCreator(PartTree tree, GemfirePersistentEntity> entity) {
+
+ super(tree);
+
+ this.query = new QueryBuilder(entity);
+ this.indexes = new IndexProvider();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#createQuery(org.springframework.data.domain.Sort)
+ */
+ @Override
+ public QueryString createQuery(Sort dynamicSort) {
+
+ this.indexes = new IndexProvider();
+ return super.createQuery(dynamicSort);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator)
+ */
+ @Override
+ protected Predicates create(Part part, Iterator