Merge branch 'master' of github.com:SpringSource/spring-gemfire

Conflicts:
	samples/hello-world/gradle.properties
This commit is contained in:
David Turanski
2012-05-09 12:35:27 -04:00
67 changed files with 4999 additions and 45 deletions

View File

@@ -58,8 +58,9 @@ dependencies {
}
~~~~~
Latest GA release is _1.1.0.RELEASE_
Latest nightly build is _1.1.1.BUILD-SNAPSHOT_
Latest GA release is _1.1.1.RELEASE_
Latest milestone release is _1.2.0.M1_
Latest nightly build is _1.2.0.BUILD-SNAPSHOT_
* Configure a GemFire cache and Region (replicated, partitioned, client and so on):

View File

@@ -48,6 +48,7 @@ allprojects {
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 +88,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

View File

@@ -2,11 +2,29 @@ SPRING DATA GEMFIRE CHANGELOG
=============================
http://www.springsource.org/spring-gemfire
Changes in version 1.1.0.RELEASE (2011-12-14)
Changes in version 1.2.0.M1 (2012-03-20)
----------------------------------------
General
* Introduced support for annotation-based entity mapping (@Id, @PersistenceConstructor, @Id)
* Introduced support for Spring Data Repositories (query exception & derivation)
Changes in version 1.1.1.RELEASE (2012-03-20)
---------------------------------------------
General
* Upgraded to GemFire 6.6.2
* Upgraded to Spring Framework 3.1.1 GA
Package org.springframework.data.gemfire
* Fixed incorrect parsing of pdx-serializer (from value to reference)
* Fixed incorrect parsing of use-bean-factory-locator
* Fixed GemfireTransactionCommitException class hierarchy
* Improved handling of GemFire 6.5+ transaction exceptions
Package org.springframework.data.gemfire.client
* Fixed bug that caused client namespace to create only local regions
Changes in version 1.1.0.RELEASE (2011-12-14)

View File

@@ -13,6 +13,11 @@
<surname>Leau</surname>
<affiliation>SpringSource, a division of VMware</affiliation>
</author>
<author>
<firstname>Oliver</firstname>
<surname>Gierke</surname>
<affiliation>SpringSource, a division of VMware</affiliation>
</author>
</authorgroup>
@@ -41,6 +46,11 @@
<xi:include href="reference/bootstrap.xml"/>
<xi:include href="reference/data.xml"/>
<xi:include href="reference/serialization.xml"/>
<xi:include href="reference/mapping.xml"/>
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/master/src/docbkx/repositories.xml">
<xi:fallback href="../../../../../../spring-data-commons/src/docbkx/repositories.xml" />
</xi:include>
<xi:include href="reference/repositories.xml"/>
<xi:include href="reference/samples.xml"/>
</part>

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0" xml:id="mapping" xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ns5="http://www.w3.org/1999/xhtml"
xmlns:ns4="http://www.w3.org/2000/svg"
xmlns:ns3="http://www.w3.org/1998/Math/MathML"
xmlns:ns="http://docbook.org/ns/docbook">
<title>POJO mapping</title>
<section xml:id="mapping.entities">
<title>Entity mapping</title>
<para>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: </para>
<example>
<title>Mapping a domain class to Gemfire</title>
<programlisting language="java">@Region("myRegion")
public class Person {
@Id Long id;
String firstname;
String lastname;
@PersistenceConstructor
public Person(String firstname, String lastname) {
// …
}
} </programlisting>
</example>
<para>The first thing you see here is the
<interfacename>@Region</interfacename> annotation that can be used to
customize the region instances of the <classname>Person</classname> class
are stored in. The <interfacename>@Id</interfacename> annotation can be
used to annotate the property that shall be used as cache key. The
<interfacename>@PersistenceConstructor</interfacename> 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.</para>
</section>
<section xml:id="mapping.pdx-serializer">
<title>Mapping PDX serializer</title>
<para>Spring Data Gemfire provides a custom
<interfacename>PDXSerializer</interfacename> implementation that uses the
mapping information to customize entity serialization. Beyond that it
allows customizing the entity instantiation by using the Spring Data
<interfacename>EntityInstantiator</interfacename> abstraction. By default
the serializer uses a <classname>ReflectionEntityInstantiator</classname>
that will use the persistence constructor of the mapped entity (either the
single declared one or explicitly annoted with
<interfacename>@PersistenceConstructor</interfacename>). To provide values
for constructor parameters it will read fields with name of the
constructor parameters from the <interfacename>PDXReader</interfacename>
supplied.</para>
<example>
<title>Using @Value on entity constructor parameters</title>
<programlisting language="java">public class Person {
public Person(@Value("#root.foo") String firstname, @Value("bean") String lastname) {
// …
}
} </programlisting>
</example>
<para>The entity annotated as such will get the field <code>foo</code>
read from the <interfacename>PDXReader</interfacename> and handed as
constructor parameter value for <code>firstname</code>. The value for
<code>lastname</code> will be the Spring bean with name
<code>bean</code>.</para>
</section>
</chapter>

View File

@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0" xml:id="gemfire-repositories"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ns5="http://www.w3.org/1999/xhtml"
xmlns:ns4="http://www.w3.org/2000/svg"
xmlns:ns3="http://www.w3.org/1998/Math/MathML"
xmlns:ns="http://docbook.org/ns/docbook">
<title>Gemfire Repositories</title>
<section>
<title xml:id="gemfire-repositories.intro">Introduction</title>
<para>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 <xref linkend="repositories" />.</para>
</section>
<section xml:id="gemfire-repositories.spring-configuration">
<title>Spring configuration</title>
<para>To bootstrap Spring Data repositories you use the
<code>&lt;repositories /&gt;</code> element from the Gemfire
namespace:</para>
<example>
<title>Bootstrap Gemfire repositories</title>
<programlisting language="xml">&lt;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&gt;
&lt;gf:repositories base-package="com.acme.repository" /&gt;
&lt;/beans&gt;</programlisting>
</example>
<para>This configuration snippet will look for interfaces below the
configured base package and create repository instances for those
interfaces backed by a <classname>SimpleGemfireRepository</classname>.
Note that you have to have your domain classes correctly mapped to
configured regions as the bottstrap process will fail otherwise.</para>
</section>
<section xml:id="gemfire-repositories.executing-queries">
<title>Executing OQL queries</title>
<para>The Gemfire repositories allow the definition of query methods to
easily execute OQL queries against the Region the managed entity is mapped
to.</para>
<example>
<title>Sample repository</title>
<programlisting language="java">@Region("myRegion")
public class Person { … }</programlisting>
<programlisting language="java">public interface PersonRepository extends CrudRepository&lt;Person, Long&gt; {
Person findByEmailAddress(String emailAddress);
Collection&lt;Person&gt; findByFirstname(String firstname);
@Query("SELECT * FROM /Person p WHERE p.firstname = $1")
Collection&lt;Person&gt; findByFirstnameAnnotated(String firstname);
@Query("SELECT * FROM /Person p WHERE p.firstname IN SET $1")
Collection&lt;Person&gt; findByFirstnamesAnnotated(Collection&lt;String&gt; firstnames);
}</programlisting>
</example>
<para>The first method listed here will cause the following query to be
derived: <code>SELECT x FROM /myRegion x WHERE x.emailAddress = $1</code>.
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
<interfacename>@Query</interfacename> as seen for methods 3 and 4.</para>
<para><table>
<title>Supported keywords for query methods</title>
<tgroup cols="3">
<colspec colwidth="1*" />
<colspec colwidth="2*" />
<colspec colwidth="2*" />
<thead>
<row>
<entry>Keyword</entry>
<entry>Sample</entry>
<entry>Logical result</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>GreaterThan</literal></entry>
<entry><methodname>findByAgeGreaterThan(int
age)</methodname></entry>
<entry><code>x.age &gt; $1</code></entry>
</row>
<row>
<entry><literal>GreaterThanEqual</literal></entry>
<entry><methodname>findByAgeGreaterThanEqual(int
age)</methodname></entry>
<entry><code>x.age &gt;= $1</code></entry>
</row>
<row>
<entry><literal>LessThan</literal></entry>
<entry><methodname>findByAgeLessThan(int
age)</methodname></entry>
<entry><code>x.age &lt; $1</code></entry>
</row>
<row>
<entry><literal>LessThanEqual</literal></entry>
<entry><methodname>findByAgeLessThanEqual(int
age)</methodname></entry>
<entry><code>x.age &lt;= $1</code></entry>
</row>
<row>
<entry><literal>IsNotNull</literal>,
<literal>NotNull</literal></entry>
<entry><methodname>findByFirstnameNotNull()</methodname></entry>
<entry><code>x.firstname =! NULL</code></entry>
</row>
<row>
<entry><literal>IsNull</literal>,
<literal>Null</literal></entry>
<entry><methodname>findByFirstnameNull()</methodname></entry>
<entry><code>x.firstname = NULL</code></entry>
</row>
<row>
<entry><literal>In</literal></entry>
<entry><methodname>findByFirstnameIn(Collection&lt;String&gt;
x)</methodname></entry>
<entry><code>x.firstname IN SET $1</code></entry>
</row>
<row>
<entry><literal>NotIn</literal></entry>
<entry><methodname>findByFirstnameNotIn(Collection&lt;String&gt;
x)</methodname></entry>
<entry><code>x.firstname NOT IN SET $1</code></entry>
</row>
<row>
<entry>(No keyword)</entry>
<entry><methodname>findByFirstname(String
name)</methodname></entry>
<entry><code>x.firstname = $1</code></entry>
</row>
<row>
<entry><literal>Not</literal></entry>
<entry><methodname>findByFirstnameNot(String
name)</methodname></entry>
<entry><code>x.firstname != $1</code></entry>
</row>
<row>
<entry><literal>IsTrue</literal>,
<literal>True</literal></entry>
<entry><code>findByActiveIsTrue()</code></entry>
<entry><code>x.active = true</code></entry>
</row>
<row>
<entry><literal>IsFalse</literal>,
<literal>False</literal></entry>
<entry><code>findByActiveIsFalse()</code></entry>
<entry><code>x.active = false</code></entry>
</row>
</tbody>
</tgroup>
</table></para>
</section>
</chapter>

View File

@@ -5,20 +5,22 @@ log4jVersion = 1.2.16
slf4jVersion = 1.6.4
# Common libraries
springVersion = 3.1.0.RELEASE
gemfireVersion = 6.6.1
springVersion = 3.1.1.RELEASE
springDataCommonsVersion = 1.3.0.BUILD-SNAPSHOT
gemfireVersion = 6.6.2
# Testing
junitVersion = 4.8.1
mockitoVersion = 1.8.5
hamcrestVersion = 1.2.1
# Manifest properties
## OSGi ranges
spring.range = "[3.1.0, 4.0.0)"
spring.range = "[3.0.0, 4.0.0)"
gemfire.range = "[6.5, 7.0)"
# --------------------
# Project wide version
# --------------------
springGemfireVersion=1.1.1.BUILD-SNAPSHOT
springGemfireVersion=1.1.1.BUILD-SNAPSHOT

View File

@@ -105,6 +105,14 @@ def customizePom(pom) {
}
pom.project {
name = project.description
description = project.description
url = 'http://github.com/SpringSource/spring-gemfire'
organization {
name = 'SpringSource'
url = 'http://www.springsource.org/spring-gemfire'
}
licenses {
license {
name 'The Apache Software License, Version 2.0'
@@ -112,6 +120,18 @@ def customizePom(pom) {
distribution 'repo'
}
}
scm {
url = 'http://github.com/SpringSource/spring-gemfire'
connection = 'scm:git:git://github.com/SpringSource/spring-gemfire'
developerConnection = 'scm:git:git://github.com/SpringSource/spring-gemfire'
}
developers {
developer {
id = 'costin'
name = 'Costin Leau'
email = 'cleau@vmware.com'
}
}
// similar to Spring's configuration
dependencies {

View File

@@ -1,3 +0,0 @@
junitVersion = 4.8.1
springVersion = 3.1.0.RELEASE
version = 1.1.1.BUILD-SNAPSHOT

View File

@@ -16,7 +16,7 @@
package org.springframework.data.gemfire;
import com.gemstone.gemfire.cache.TransactionException;
import org.springframework.transaction.TransactionException;
/**
* Gemfire-specific subclass of {@link org.springframework.transaction.TransactionException}, indicating a transaction failure at commit time.
@@ -25,10 +25,6 @@ import com.gemstone.gemfire.cache.TransactionException;
*/
public class GemfireTransactionCommitException extends TransactionException {
public GemfireTransactionCommitException() {
super();
}
public GemfireTransactionCommitException(String message, Throwable cause) {
super(message, cause);
}
@@ -36,8 +32,4 @@ public class GemfireTransactionCommitException extends TransactionException {
public GemfireTransactionCommitException(String message) {
super(message);
}
public GemfireTransactionCommitException(Throwable cause) {
super(cause);
}
}

View File

@@ -30,7 +30,6 @@ import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheTransactionManager;
import com.gemstone.gemfire.cache.CommitConflictException;
import com.gemstone.gemfire.cache.Region;
/**
@@ -136,7 +135,7 @@ public class GemfireTransactionManager extends AbstractPlatformTransactionManage
} catch (IllegalStateException ex) {
throw new NoTransactionException(
"No transaction associated with the current thread; are there multiple transaction managers ?", ex);
} catch (CommitConflictException ex) {
} catch (TransactionException ex) {
throw new GemfireTransactionCommitException("Unexpected failure on commit of Cache local transaction", ex);
}
}

View File

@@ -38,6 +38,7 @@ import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientRegionFactory;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
/**
* Client extension for GemFire regions.
@@ -74,8 +75,12 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
@Override
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
Assert.isTrue(cache instanceof ClientCache, "Unable to create regions from " + cache);
ClientCache c = (ClientCache) cache;
if (cache instanceof GemFireCacheImpl) {
Assert.isTrue(((GemFireCacheImpl) cache).isClient(), "A client-cache instance is required");
}
// first look at shortcut
ClientRegionShortcut s = null;
@@ -88,8 +93,16 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
else if (DataPolicy.PERSISTENT_REPLICATE.equals(dataPolicy)) {
s = ClientRegionShortcut.LOCAL_PERSISTENT;
}
else if (DataPolicy.NORMAL.equals(this.dataPolicy)) {
s = ClientRegionShortcut.CACHING_PROXY;
}
else {
s = ClientRegionShortcut.LOCAL;
}
}
else {
s = ClientRegionShortcut.LOCAL;
}
s = ClientRegionShortcut.LOCAL;
} else {
s = shortcut;
}

View File

@@ -45,7 +45,7 @@ class CacheParser extends AbstractSingleBeanDefinitionParser {
ParsingUtils.setPropertyValue(element, builder, "cache-xml-location", "cacheXml");
ParsingUtils.setPropertyReference(element, builder, "properties-ref", "properties");
ParsingUtils.setPropertyReference(element, builder, "pdx-serializer", "pdxSerializer");
ParsingUtils.setPropertyValue(element, builder, "pdx-disk-store", "pdxDiskStore");
ParsingUtils.setPropertyValue(element, builder, "pdx-disk-store", "pdxDiskStoreName");
ParsingUtils.setPropertyValue(element, builder, "pdx-persistent", "pdxPersistent");
ParsingUtils.setPropertyValue(element, builder, "pdx-read-serialized", "pdxReadSerialized");
ParsingUtils.setPropertyValue(element, builder, "pdx-ignore-unread-fields", "pdxIgnoreUnreadFields");

View File

@@ -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());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-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.
@@ -68,6 +68,7 @@ import com.gemstone.gemfire.cache.query.CqQuery;
*
* @author Juergen Hoeller
* @author Costin Leau
* @author Oliver Gierke
* @see org.springframework.jms.listener.adapter.MessageListenerAdapter
*/
public class ContinuousQueryListenerAdapter implements ContinuousQueryListener {
@@ -260,7 +261,6 @@ public class ContinuousQueryListenerAdapter implements ContinuousQueryListener {
* @param event the incoming GemFire event
* @see #handleListenerException
*/
@SuppressWarnings("unchecked")
public void onEvent(CqEvent event) {
try {
@@ -269,6 +269,7 @@ public class ContinuousQueryListenerAdapter implements ContinuousQueryListener {
if (delegate != this) {
if (delegate instanceof ContinuousQueryListener) {
((ContinuousQueryListener) delegate).onEvent(event);
return;
}
}
@@ -283,7 +284,6 @@ public class ContinuousQueryListenerAdapter implements ContinuousQueryListener {
+ "override the 'getListenerMethodName' method.");
}
invokeListenerMethod(event, methodName);
} catch (Throwable th) {
handleListenerException(th);

View File

@@ -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<GemfirePersistentEntity<?>, GemfirePersistentProperty> {
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
*/
@Override
protected <T> GemfirePersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
return new GemfirePersistentEntity<T>(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);
}
}

View File

@@ -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<T> extends BasicPersistentEntity<T, GemfirePersistentProperty> {
private final String regionName;
/**
* Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
*
* @param information must not be {@literal null}.
*/
public GemfirePersistentEntity(TypeInformation<T> information) {
super(information);
Class<T> 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 the name of the region the entity shall be stored in.
*/
public String getRegionName() {
return this.regionName;
}
}

View File

@@ -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<GemfirePersistentProperty> {
/**
* @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<GemfirePersistentProperty> createAssociation() {
return null;
}
}

View File

@@ -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<GemfirePersistentProperty> {
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> T getPropertyValue(GemfirePersistentProperty property) {
return (T) reader.readObject(property.getName());
}
}

View File

@@ -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<Class<?>, 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<GemfirePersistentProperty> provider = new PersistentEntityParameterValueProvider<GemfirePersistentProperty>(
entity, propertyValueProvider, null);
provider.setSpELEvaluator(new DefaultSpELExpressionEvaluator(reader, context));
Object instance = instantiator.createInstance(entity, provider);
final BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(instance, conversionService);
entity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
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<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(value, conversionService);
entity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
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;
}
}

View File

@@ -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();
}
}

View File

@@ -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 "";
}

View File

@@ -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<Region<?, ?>> {
private final Map<String, Region<?, ?>> 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<Region<?, ?>> regions, MappingContext<? extends GemfirePersistentEntity<?>, ?> context) {
Assert.notNull(regions);
Assert.notNull(context);
Map<String, com.gemstone.gemfire.cache.Region<?, ?>> regionMap = new HashMap<String, Region<?, ?>>();
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 the {@link Region} the given type is mapped to.
*/
@SuppressWarnings("unchecked")
public <T> Region<?, T> getRegion(Class<T> type) {
Assert.notNull(type);
GemfirePersistentEntity<?> entity = context.getPersistentEntity(type);
return (Region<?, T>) (entity == null ? regions.get(type.getSimpleName()) : regions.get(entity.getRegionName()));
}
/**
* Returns the {@link Region} with the given name.
*
* @param name must not be {@literal null}.
* @return the {@link Region} with the given name.
*/
@SuppressWarnings("unchecked")
public <S, T> Region<S, T> getRegion(String name) {
Assert.notNull(name);
return (Region<S, T>) regions.get(name);
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Region<?, ?>> iterator() {
return regions.values().iterator();
}
}

View File

@@ -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<T, ID extends Serializable> extends CrudRepository<T, ID> {
T save(Wrapper<T, ID> wrapper);
}

View File

@@ -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 "";
}

View File

@@ -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<T, KEY extends Serializable> {
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;
}
}

View File

@@ -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<SimpleGemfireRepositoryConfiguration, GemfireRepositoryConfiguration> {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#getGlobalRepositoryConfigInformation(org.w3c.dom.Element)
*/
@Override
protected SimpleGemfireRepositoryConfiguration getGlobalRepositoryConfigInformation(Element element) {
return new SimpleGemfireRepositoryConfiguration(element);
}
}

View File

@@ -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<GemfireRepositoryConfiguration, SimpleGemfireRepositoryConfiguration> {
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<SimpleGemfireRepositoryConfiguration> {
String getGemfireTemplateRef();
}
static class ManualGemfireRepositoryConfiguration extends
ManualRepositoryConfigInformation<SimpleGemfireRepositoryConfiguration> 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<SimpleGemfireRepositoryConfiguration> 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();
}
}
}

View File

@@ -0,0 +1,5 @@
/**
* Implementations of Spring Data COmmons Core repository abstraction.
*/
package org.springframework.data.gemfire.repository;

View File

@@ -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<T, ID extends Serializable> extends DelegatingEntityInformation<T, ID>
implements GemfireEntityInformation<T, ID> {
private final GemfirePersistentEntity<T> entity;
/**
* Creates a new {@link DefaultGemfireEntityInformation}.
*
* @param entity must not be {@literal null}.
*/
public DefaultGemfireEntityInformation(GemfirePersistentEntity<T> entity) {
super(new ReflectionEntityInformation<T, ID>(entity.getType()));
this.entity = entity;
}
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.repository.query.GemfireEntityInformation#getRegionName()
*/
@Override
public String getRegionName() {
return entity.getRegionName();
}
}

View File

@@ -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<T, ID extends Serializable> extends EntityInformation<T, ID> {
/**
* Returns the name of the {@link Region} the entity is held in.
*
* @return the name of the {@link Region} the entity is held in.
*/
String getRegionName();
}

View File

@@ -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<QueryString, Predicates> {
private static final Log LOG = LogFactory.getLog(GemfireQueryCreator.class);
private final QueryBuilder query;
private Iterator<Integer> 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<Object> iterator) {
return Predicates.create(part, this.indexes);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#and(org.springframework.data.repository.query.parser.Part, java.lang.Object, java.util.Iterator)
*/
@Override
protected Predicates and(Part part, Predicates base, Iterator<Object> iterator) {
return base.and(Predicates.create(part, this.indexes));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#or(java.lang.Object, java.lang.Object)
*/
@Override
protected Predicates or(Predicates base, Predicates criteria) {
return base.or(criteria);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#complete(java.lang.Object, org.springframework.data.domain.Sort)
*/
@Override
protected QueryString complete(Predicates criteria, Sort sort) {
QueryString result = query.create(criteria);
if (LOG.isDebugEnabled()) {
LOG.debug("Created query: " + result.toString());
}
return result;
}
private static class IndexProvider implements Iterator<Integer> {
private int index;
public IndexProvider() {
this.index = 1;
}
/*
* (non-Javadoc)
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return index <= Integer.MAX_VALUE;
}
/*
* (non-Javadoc)
* @see java.util.Iterator#next()
*/
@Override
public Integer next() {
return index++;
}
/*
* (non-Javadoc)
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.lang.reflect.Method;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
import org.springframework.data.gemfire.repository.Query;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Gemfire specific {@link QueryMethod}.
*
* @author Oliver Gierke
*/
public class GemfireQueryMethod extends QueryMethod {
private final Method method;
private final GemfirePersistentEntity<?> entity;
/**
* Creates a new {@link GemfireQueryMethod} from the given {@link Method} and {@link RepositoryMetadata}.
*
* @param method must not be {@literal null}.
* @param metadata must not be {@literal null}.
* @param context must not be {@literal null}.
*/
public GemfireQueryMethod(Method method, RepositoryMetadata metadata,
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
super(method, metadata);
Assert.notNull(context);
this.method = method;
this.entity = context.getPersistentEntity(getDomainClass());
}
/**
* Returns whether the query method contains an annotated, non-empty query.
*
* @return whether the query method contains an annotated, non-empty query.
*/
public boolean hasAnnotatedQuery() {
return StringUtils.hasText(getAnnotatedQuery());
}
/**
* Returns the {@link GemfirePersistentEntity} the method deals with.
*
* @return the {@link GemfirePersistentEntity} the method deals with.
*/
public GemfirePersistentEntity<?> getPersistentEntity() {
return entity;
}
/**
* Returns the query annotated to the query method.
*
* @return the annotated query or {@literal null} in case it's empty or none available.
*/
String getAnnotatedQuery() {
Query query = method.getAnnotation(Query.class);
String queryString = query == null ? null : (String) AnnotationUtils.getValue(query);
return StringUtils.hasText(queryString) ? queryString : null;
}
}

View File

@@ -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.repository.query;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.util.Assert;
/**
* Base class for GemFire specific {@link RepositoryQuery} implementations.
*
* @author Oliver Gierke
*/
abstract class GemfireRepositoryQuery implements RepositoryQuery {
private final GemfireQueryMethod queryMethod;
/**
* Creates a new {@link GemfireRepositoryQuery} using the given {@link GemfireQueryMethod}.
*
* @param queryMethod must not be {@literal null}.
*/
public GemfireRepositoryQuery(GemfireQueryMethod queryMethod) {
Assert.notNull(queryMethod);
this.queryMethod = queryMethod;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
*/
@Override
public QueryMethod getQueryMethod() {
return this.queryMethod;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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 org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.parser.PartTree;
/**
* {@link GemfireRepositoryQuery} backed by a {@link PartTree} and thus, deriving an OQL query from the backing query
* method's name.
*
* @author Oliver Gierke
*/
public class PartTreeGemfireRepositoryQuery extends GemfireRepositoryQuery {
private final GemfireQueryMethod method;
private final PartTree tree;
private final GemfireTemplate template;
/**
* Creates a new {@link PartTreeGemfireRepositoryQuery} using the given {@link GemfireQueryMethod} and
* {@link GemfireTemplate}.
*
* @param method must not be {@literal null}.
* @param template must not be {@literal null}.
*/
public PartTreeGemfireRepositoryQuery(GemfireQueryMethod method, GemfireTemplate template) {
super(method);
Class<?> domainClass = method.getEntityInformation().getJavaType();
this.tree = new PartTree(method.getName(), domainClass);
this.method = method;
this.template = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
*/
@Override
public Object execute(Object[] parameters) {
ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(method.getParameters(), parameters);
QueryString query = new GemfireQueryCreator(tree, method.getPersistentEntity()).createQuery(parameterAccessor
.getSort());
RepositoryQuery repositoryQuery = new StringBasedGemfireRepositoryQuery(query.toString(), method, template);
return repositoryQuery.execute(parameters);
}
}

View File

@@ -0,0 +1,6 @@
package org.springframework.data.gemfire.repository.query;
interface Predicate {
String toString(String alias);
}

View File

@@ -0,0 +1,173 @@
/*
* 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.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.util.Assert;
class Predicates implements Predicate {
private final Predicate current;
/**
* Creates a new {@link Predicates} wrapper instance.
*
* @param predicate must not be {@literal null}.
*/
private Predicates(Predicate predicate) {
this.current = predicate;
}
private static Predicates create(Predicate predicate) {
return new Predicates(predicate);
}
/**
* Creates a new Predicate for the given {@link Part} and index iterator.
*
* @param part must not be {@literal null}.
* @param value must not be {@literal null}.
* @return
*/
public static Predicates create(Part part, Iterator<Integer> value) {
return create(new AtomicPredicate(part, value));
}
/**
* And-concatenates the given {@link Predicate} to the current one.
*
* @param predicate must not be {@literal null}.
* @return
*/
public Predicates and(final Predicate predicate) {
return create(new Predicate() {
@Override
public String toString(String alias) {
return String.format("%s AND %s", Predicates.this.current.toString(alias), predicate.toString(alias));
}
});
}
/**
* Or-concatenates the given {@link Predicate} to the current one.
*
* @param predicate must not be {@literal null}.
* @return
*/
public Predicates or(final Predicate predicate) {
return create(new Predicate() {
@Override
public String toString(String alias) {
return String.format("%s OR %s", Predicates.this.current.toString(alias), predicate.toString(alias));
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.repository.query.Predicate#toString(java.lang.String)
*/
@Override
public String toString(String alias) {
return current.toString(alias);
}
/**
* Predicate to create a predicate expression for a {@link Part}.
*
* @author Oliver Gierke
*/
public static class AtomicPredicate implements Predicate {
private final Part part;
private final Iterator<Integer> value;
/**
* Creates a new {@link AtomicPredicate}.
*
* @param part must not be {@literal null}.
* @param value must not be {@literal null}.
*/
public AtomicPredicate(Part part, Iterator<Integer> value) {
Assert.notNull(part);
Assert.notNull(value);
this.part = part;
this.value = value;
}
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.repository.query.Predicate#toString(java.lang.String)
*/
@Override
public String toString(String alias) {
Type type = part.getType();
return String.format("%s.%s %s", alias == null ? QueryBuilder.DEFAULT_ALIAS : alias, part.getProperty()
.toDotPath(), toClause(type));
}
private String toClause(Type type) {
switch (type) {
case IS_NULL:
case IS_NOT_NULL:
return String.format("%s NULL", getOperator(type));
default:
return String.format("%s $%s", getOperator(type), value.next());
}
}
/**
* Maps the given {@link Type} to an OQL operator.
*
* @param type
* @return
*/
private String getOperator(Type type) {
switch (type) {
case IN:
return "IN SET";
case NOT_IN:
return "NOT IN SET";
case GREATER_THAN:
return ">";
case GREATER_THAN_EQUAL:
return ">=";
case LESS_THAN:
return "<";
case LESS_THAN_EQUAL:
return "<=";
case IS_NOT_NULL:
case NEGATING_SIMPLE_PROPERTY:
return "!=";
case IS_NULL:
case SIMPLE_PROPERTY:
return "=";
default:
throw new IllegalArgumentException(String.format("Unsupported operator %s!", type));
}
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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 org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.util.Assert;
/**
*
* @author Oliver Gierke
*/
class QueryBuilder {
static final String DEFAULT_ALIAS = "x";
private final String query;
public QueryBuilder(String source) {
Assert.hasText(source);
this.query = source;
}
public QueryBuilder(GemfirePersistentEntity<?> entity) {
this(String.format("SELECT * FROM /%s %s", entity.getRegionName(), DEFAULT_ALIAS));
}
public QueryString create(Predicate predicate) {
return new QueryString(query + " WHERE " + predicate.toString(DEFAULT_ALIAS));
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return query;
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.Region;
/**
* Value object to work with OQL query strings.
*
* @author Oliver Gierke
*/
class QueryString {
private static final String REGION_PATTERN = "(?<=\\/)%s";
private static final String IN_PARAMETER_PATTERN = "(?<=IN (SET|LIST) \\$)\\d";
private static final String IN_PATTERN = "(?<=IN (SET|LIST) )\\$\\d";
private final String query;
/**
* Creates a {@link QueryString} from the given {@link String} query.
*
* @param source
*/
public QueryString(String source) {
Assert.hasText(source);
this.query = source;
}
/**
* Creates a {@literal SELECT} query for the given domain class.
*
* @param domainClass must not be {@literal null}.
*/
public QueryString(Class<?> domainClass) {
this(String.format("SELECT * FROM /%s", domainClass.getSimpleName()));
}
/**
* Replaces the domain classes referenced inside the current query with the given {@link Region}.
*
* @param domainClass must not be {@literal null}.
* @param region must not be {@literal null}.
* @return
*/
public QueryString forRegion(Class<?> domainClass, Region<?, ?> region) {
String pattern = String.format(REGION_PATTERN, domainClass.getSimpleName());
return new QueryString(query.replaceAll(pattern, region.getName()));
}
/**
* Binds the given values to the {@literal IN} parameter keyword by expanding the given values into a comma-separated
* {@link String}.
*
* @param values the values to bind, returns the {@link QueryString} as is if {@literal null} is given.
* @return
*/
public QueryString bindIn(Collection<?> values) {
if (values == null) {
return this;
}
String valueString = StringUtils.collectionToDelimitedString(values, ", ", "'", "'");
return new QueryString(query.replaceFirst(IN_PATTERN, String.format("(%s)", valueString)));
}
/**
* Returns the parameter indexes used in this query.
*
* @return the parameter indexes used in this query or an empty {@link Iterable} if none are used.
*/
public Iterable<Integer> getInParameterIndexes() {
Pattern pattern = Pattern.compile(IN_PARAMETER_PATTERN);
Matcher matcher = pattern.matcher(query);
List<Integer> result = new ArrayList<Integer>();
while (matcher.find()) {
result.add(Integer.parseInt(matcher.group()));
}
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return query;
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.Collection;
import java.util.Collections;
import java.util.Iterator;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link GemfireRepositoryQuery} using plain {@link String} based OQL queries.
*
* @author Oliver Gierke
*/
public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
private final QueryString query;
private final GemfireQueryMethod method;
private final GemfireTemplate template;
/**
* Creates a new {@link StringBasedGemfireRepositoryQuery} using the given {@link GemfireQueryMethod} and
* {@link GemfireTemplate}. The actual query {@link String} will be looked up from the query method.
*
* @param method must not be {@literal null}.
* @param template must not be {@literal null}.
*/
public StringBasedGemfireRepositoryQuery(GemfireQueryMethod method, GemfireTemplate template) {
this(method.getAnnotatedQuery(), method, template);
}
/**
* Creates a new {@link StringBasedGemfireRepositoryQuery} using the given query {@link String},
* {@link GemfireQueryMethod} and {@link GemfireTemplate}.
*
* @param query will fall back to the query annotated to the given {@link GemfireQueryMethod} if {@literal null} is
* given.
* @param method must not be {@literal null}.
* @param template must not be {@literal null}.
*/
public StringBasedGemfireRepositoryQuery(String query, GemfireQueryMethod method, GemfireTemplate template) {
super(method);
Assert.notNull(template);
this.query = new QueryString(StringUtils.hasText(query) ? query : method.getAnnotatedQuery());
this.method = method;
this.template = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
*/
@Override
public Object execute(Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(method.getParameters(), parameters);
QueryString query = this.query.forRegion(method.getEntityInformation().getJavaType(), template.getRegion());
Iterator<Integer> indexes = query.getInParameterIndexes().iterator();
while (indexes.hasNext()) {
query = query.bindIn(toCollection(accessor.getBindableValue(indexes.next() - 1)));
}
return template.find(query.toString(), parameters);
}
/**
* Returns the given object as collection. Collections will be returned as is, Arrays will be converted into a
* collection and all other objects will be wrapped into a single-element collection.
*
* @param source
* @return
*/
private Collection<?> toCollection(Object source) {
if (source instanceof Collection) {
return (Collection<?>) source;
}
return source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singleton(source);
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.support;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
import org.springframework.data.gemfire.mapping.Regions;
import org.springframework.data.gemfire.repository.query.DefaultGemfireEntityInformation;
import org.springframework.data.gemfire.repository.query.GemfireEntityInformation;
import org.springframework.data.gemfire.repository.query.GemfireQueryMethod;
import org.springframework.data.gemfire.repository.query.PartTreeGemfireRepositoryQuery;
import org.springframework.data.gemfire.repository.query.StringBasedGemfireRepositoryQuery;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.Region;
/**
* {@link RepositoryFactorySupport} implementation creating repository proxies for Gemfire.
*
* @author Oliver Gierke
*/
public class GemfireRepositoryFactory extends RepositoryFactorySupport {
private final MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context;
private final Regions regions;
/**
* Creates a new {@link GemfireRepositoryFactory}.
*
* @param regions must not be {@literal null}.
* @param context
*/
public GemfireRepositoryFactory(Iterable<Region<?, ?>> regions,
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
Assert.notNull(regions);
this.context = context == null ? new GemfireMappingContext() : context;
this.regions = new Regions(regions, this.context);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
*/
@Override
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> GemfireEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
GemfirePersistentEntity<T> entity = (GemfirePersistentEntity<T>) context.getPersistentEntity(domainClass);
return new DefaultGemfireEntityInformation<T, ID>(entity);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object getTargetRepository(RepositoryMetadata metadata) {
GemfireEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
GemfireTemplate gemfireTemplate = getTemplate(metadata);
return new SimpleGemfireRepository(gemfireTemplate, entityInformation);
}
private GemfireTemplate getTemplate(RepositoryMetadata metadata) {
Class<?> domainClass = metadata.getDomainType();
GemfirePersistentEntity<?> entity = context.getPersistentEntity(domainClass);
Region<?, ?> region = regions.getRegion(domainClass);
if (region == null) {
throw new IllegalStateException(String.format("No region '%s' found for domain class %s! Make sure you have "
+ "configured a Gemfire region of that name in your application context!", entity.getRegionName(), domainClass));
}
Class<?> regionKeyType = region.getAttributes().getKeyConstraint();
Class<?> entityIdType = metadata.getIdType();
if (regionKeyType != null && entity.getIdProperty() != null) {
Assert.isTrue(regionKeyType.isAssignableFrom(entityIdType), String.format(
"The region referenced only supports keys of type %s but the entity to be stored has an id of type %s!",
regionKeyType, entityIdType));
}
return new GemfireTemplate(region);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleGemfireRepository.class;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key)
*/
@Override
protected QueryLookupStrategy getQueryLookupStrategy(Key key) {
return new QueryLookupStrategy() {
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
GemfireQueryMethod queryMethod = new GemfireQueryMethod(method, metadata, context);
GemfireTemplate template = getTemplate(metadata);
if (queryMethod.hasAnnotatedQuery()) {
return new StringBasedGemfireRepositoryQuery(queryMethod, template);
}
String namedQueryName = queryMethod.getNamedQueryName();
if (namedQueries.hasQuery(namedQueryName)) {
return new StringBasedGemfireRepositoryQuery(namedQueries.getQuery(namedQueryName), queryMethod, template);
}
return new PartTreeGemfireRepositoryQuery(queryMethod, template);
}
};
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.support;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import com.gemstone.bp.edu.emory.mathcs.backport.java.util.Collections;
import com.gemstone.gemfire.cache.Region;
/**
* {@link FactoryBean} adapter for {@link GemfireRepositoryFactory}.
*
* @author Oliver Gierke
*/
public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
private MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context;
private Iterable<Region<?, ?>> regions;
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Collection<Region> regions = applicationContext.getBeansOfType(Region.class).values();
this.regions = Collections.unmodifiableCollection(regions);
}
/**
* Configures the {@link MappingContext} to be used.
*
* @param context the context to set
*/
public void setMappingContext(MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
this.context = context;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#createRepositoryFactory()
*/
@Override
protected RepositoryFactorySupport createRepositoryFactory() {
return new GemfireRepositoryFactory(regions, context);
}
}

View File

@@ -0,0 +1,174 @@
package org.springframework.data.gemfire.repository.support;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.data.gemfire.GemfireCallback;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.repository.GemfireRepository;
import org.springframework.data.gemfire.repository.Wrapper;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.util.Assert;
import com.gemstone.gemfire.GemFireCheckedException;
import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.cache.Region;
/**
* Basic repository implementation.
*
* @author Oliver Gierke
*/
public class SimpleGemfireRepository<T, ID extends Serializable> implements GemfireRepository<T, ID> {
private final GemfireTemplate template;
private final EntityInformation<T, ID> entityInformation;
/**
* Creates a new {@link SimpleGemfireRepository}.
*
* @param template must not be {@literal null}.
* @param entityInformation must not be {@literal null}.
*/
public SimpleGemfireRepository(GemfireTemplate template, EntityInformation<T, ID> entityInformation) {
Assert.notNull(template);
Assert.notNull(entityInformation);
this.template = template;
this.entityInformation = entityInformation;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(S)
*/
public <U extends T> U save(U entity) {
template.put(entityInformation.getId(entity), entity);
return entity;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
*/
public <U extends T> Iterable<U> save(Iterable<U> entities) {
List<U> result = new ArrayList<U>();
for (U entity : entities) {
result.add(save(entity));
}
return result;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
*/
@SuppressWarnings("unchecked")
public T findOne(ID id) {
Object object = template.get(id);
return (T) object;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable)
*/
public boolean exists(ID id) {
return findOne(id) != null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
public Collection<T> findAll() {
return template.execute(new GemfireCallback<Collection<T>>() {
@SuppressWarnings({ "rawtypes", "unchecked" })
public Collection<T> doInGemfire(Region region) {
return region.values();
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
*/
@Override
@SuppressWarnings("unchecked")
public Collection<T> findAll(Iterable<ID> ids) {
List<ID> parameters = new ArrayList<ID>();
for (ID id : ids) {
parameters.add(id);
}
return (Collection<T>) template.getAll(parameters).values();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#count()
*/
public long count() {
return template.execute(new GemfireCallback<Long>() {
@SuppressWarnings("rawtypes")
public Long doInGemfire(Region region) throws GemFireCheckedException, GemFireException {
return Long.valueOf(region.keySet().size());
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
*/
public void delete(T entity) {
template.remove(entityInformation.getId(entity));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable)
*/
public void delete(Iterable<? extends T> entities) {
for (T entity : entities) {
delete(entity);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#deleteAll()
*/
public void deleteAll() {
template.execute(new GemfireCallback<Void>() {
@SuppressWarnings("rawtypes")
public Void doInGemfire(Region region) {
region.clear();
return null;
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
*/
public void delete(ID id) {
template.remove(id);
}
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.repository.GemfireRepository#save(org.springframework.data.gemfire.repository.Wrapper)
*/
@Override
public T save(Wrapper<T, ID> wrapper) {
return template.put(wrapper.getKey(), wrapper.getEntity());
}
}

View File

@@ -1,3 +1,4 @@
http\://www.springframework.org/schema/gemfire/spring-gemfire-1.0.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.0.xsd
http\://www.springframework.org/schema/gemfire/spring-gemfire-1.1.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.1.xsd
http\://www.springframework.org/schema/gemfire/spring-gemfire.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.1.xsd
http\://www.springframework.org/schema/gemfire/spring-gemfire-1.2.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.2.xsd
http\://www.springframework.org/schema/gemfire/spring-gemfire.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.2.xsd

View File

@@ -6,7 +6,7 @@
targetNamespace="http://www.springframework.org/schema/gemfire"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
version="1.1">
version="1.1.1">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
@@ -1074,7 +1074,7 @@ The client subscription configuration that is used to control a clients use of s
<xsd:attribute name="max-time-between-pings" use="optional" type="xsd:string" default="60000" />
<xsd:attribute name="message-time-to-live" use="optional" type="xsd:string" default="180" />
<xsd:attribute name="socket-buffer-size" use="optional" type="xsd:string" default="32768" />
<xsd:attribute name="notify-by-subscription" use="optional" type="xsd:boolean" default="true" />
<xsd:attribute name="notify-by-subscription" use="optional" type="xsd:string" default="true" />
<xsd:attribute name="groups" use="optional" type="xsd:string" default="">
<xsd:annotation>
<xsd:documentation><![CDATA[

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-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.
@@ -16,11 +16,9 @@
package org.springframework.data.gemfire.listener.adapter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
@@ -31,9 +29,9 @@ import com.gemstone.gemfire.cache.query.CqEvent;
import com.gemstone.gemfire.cache.query.CqQuery;
import com.gemstone.gemfire.cache.query.internal.CqQueryImpl;
/**
* @author Costin Leau
* @author Oliver Gierke
*/
public class QueryListenerAdapterTest {
@@ -92,16 +90,17 @@ public class QueryListenerAdapterTest {
void handleOperation(Operation op);
void handleArray(byte[] ba);
void handleKey(Object key);
void handleKV(Object k, Object v);
void handleEx(Throwable th);
void handleOps(Operation base, Operation query);
void handleAll(CqEvent event, CqQuery query, byte[] ba, Object key, Operation op, Throwable th, Operation qOp, Object v);
void handleAll(CqEvent event, CqQuery query, byte[] ba, Object key, Operation op, Throwable th, Operation qOp,
Object v);
void handleInvalid(Object o1, Object o2, Object o3);
}
@@ -212,4 +211,31 @@ public class QueryListenerAdapterTest {
doThrow(new IllegalArgumentException()).when(mock);
}
/**
* @see SGF-89
*/
@Test
public void triggersListenerImplementingInterfaceCorrectly() {
SampleListener listener = new SampleListener();
ContinuousQueryListener listenerAdapter = new ContinuousQueryListenerAdapter(listener) {
protected void handleListenerException(Throwable ex) {
throw new RuntimeException(ex);
}
};
listenerAdapter.onEvent(event());
assertThat(listener.count, is(1));
}
class SampleListener implements ContinuousQueryListener {
int count;
@Override
public void onEvent(CqEvent event) {
count++;
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.util.ClassTypeInformation;
/**
* Unit tests for {@link GemfirePersistentEntity}.
*
* @author Oliver Gierke
*/
public class GemfirePersistentEntityUnitTests {
@Test
public void defaultsRegionNameToClassName() {
GemfirePersistentEntity<UnannotatedRegion> entity = new GemfirePersistentEntity<UnannotatedRegion>(
ClassTypeInformation.from(UnannotatedRegion.class));
assertThat(entity.getRegionName(), is(UnannotatedRegion.class.getSimpleName()));
}
@Test
public void defaultsAnnotatedRegionToCLassName() {
GemfirePersistentEntity<UnnamedRegion> entity = new GemfirePersistentEntity<UnnamedRegion>(
ClassTypeInformation.from(UnnamedRegion.class));
assertThat(entity.getRegionName(), is(UnnamedRegion.class.getSimpleName()));
}
@Test
public void readsRegionNameFromAnnotation() {
GemfirePersistentEntity<AnnotatedRegion> entity = new GemfirePersistentEntity<AnnotatedRegion>(
ClassTypeInformation.from(AnnotatedRegion.class));
assertThat(entity.getRegionName(), is("Foo"));
}
static class UnannotatedRegion {
}
@Region("Foo")
static class AnnotatedRegion {
}
@Region
static class UnnamedRegion {
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.MappingPdxSerializer;
import org.springframework.data.gemfire.repository.sample.Address;
import org.springframework.data.gemfire.repository.sample.Person;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionFactory;
/**
* Integration tests for {@link MappingPdxSerializer}.
*
* @author Oliver Gierke
*/
public class MappingPdxSerializerIntegrationTest {
Region<Object, Object> region;
@Before
public void setUp() {
MappingPdxSerializer serializer = new MappingPdxSerializer(new GemfireMappingContext(),
new DefaultConversionService());
CacheFactory factory = new CacheFactory();
factory.setPdxSerializer(serializer);
factory.setPdxPersistent(true);
Cache cache = factory.create();
RegionFactory<Object, Object> regionFactory = cache.createRegionFactory();
regionFactory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
region = regionFactory.create("foo");
}
@Test
public void serializeAndDeserializeCorrectly() {
Address address = new Address();
address.zipCode = "01234";
address.city = "London";
Person person = new Person(1L, "Oliver", "Gierke");
person.address = address;
region.put(1L, person);
Object result = region.get(1L);
assertThat(result instanceof Person, is(true));
Person reference = person;
assertThat(reference.getFirstname(), is(person.getFirstname()));
assertThat(reference.getLastname(), is(person.getLastname()));
assertThat(reference.address, is(person.address));
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.mapping.model.ParameterValueProvider;
import com.gemstone.gemfire.pdx.PdxReader;
/**
* Unit tests for {@link MappingPdxSerializer}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class MappingPdxSerializerUnitTests {
GemfireMappingContext context;
ConversionService conversionService;
MappingPdxSerializer serializer;
@Mock
EntityInstantiator instantiator;
@Mock
PdxReader reader;
@Before
public void setUp() {
context = new GemfireMappingContext();
conversionService = new GenericConversionService();
serializer = new MappingPdxSerializer(context, conversionService);
}
@Test
@SuppressWarnings("unchecked")
public void usesRegisteredInstantiator() {
Person person = new Person(1L, "Oliver", "Gierke");
ParameterValueProvider<GemfirePersistentProperty> provider = any(ParameterValueProvider.class);
GemfirePersistentEntity<?> entity = any(GemfirePersistentEntity.class);
when(instantiator.createInstance(entity, provider)).thenReturn(person);
Map<Class<?>, EntityInstantiator> instantiators = new HashMap<Class<?>, EntityInstantiator>();
instantiators.put(Person.class, instantiator);
serializer.setGemfireInstantiators(instantiators);
serializer.fromData(Person.class, reader);
verify(instantiator, times(1)).createInstance(eq(context.getPersistentEntity(Person.class)),
any(ParameterValueProvider.class));
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.TypedValue;
import com.gemstone.bp.edu.emory.mathcs.backport.java.util.Arrays;
import com.gemstone.gemfire.pdx.PdxReader;
/**
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class PdxReaderPropertyAccessorUnitTests {
@Mock
PdxReader reader;
@Test
@SuppressWarnings("unchecked")
public void appliesToPdxReadersOnly() {
List<Class<?>> classes = Arrays.asList(PdxReaderPropertyAccessor.INSTANCE.getSpecificTargetClasses());
assertThat(classes, hasItem(PdxReader.class));
}
@Test
public void canReadPropertyIfReaderHasField() {
when(reader.hasField("key")).thenReturn(true);
assertThat(PdxReaderPropertyAccessor.INSTANCE.canRead(null, reader, "key"), is(true));
when(reader.hasField("key")).thenReturn(false);
assertThat(PdxReaderPropertyAccessor.INSTANCE.canRead(null, reader, "key"), is(false));
}
@Test
public void returnsTypedNullIfNullIsReadFromReader() {
when(reader.readObject("key")).thenReturn(null);
assertThat(PdxReaderPropertyAccessor.INSTANCE.read(null, reader, "key"), is(TypedValue.NULL));
}
@Test
public void returnsTypeValueWithValueReadFromReader() {
when(reader.readObject("key")).thenReturn("String");
TypedValue result = PdxReaderPropertyAccessor.INSTANCE.read(null, reader, "key");
assertThat(result.getTypeDescriptor(), is(TypeDescriptor.valueOf(String.class)));
assertThat(result.getValue(), is((Object) "String"));
}
@Test(expected = UnsupportedOperationException.class)
public void doesNotSupportWrites() {
assertThat(PdxReaderPropertyAccessor.INSTANCE.canWrite(null, null, null), is(false));
PdxReaderPropertyAccessor.INSTANCE.write(null, null, null, reader);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.annotation.Autowired;
import org.springframework.data.gemfire.mapping.Regions;
import org.springframework.data.gemfire.repository.sample.PersonRepository;
import org.springframework.data.gemfire.repository.support.AbstractGemfireRepositoryFactoryIntegrationTests;
import org.springframework.test.context.ContextConfiguration;
/**
* Integration tests for namespace usage.
*
* @author Oliver Gierke
*/
@ContextConfiguration("repo-context.xml")
public class NamespaceRepositoryIntegrationTests extends AbstractGemfireRepositoryFactoryIntegrationTests {
@Autowired
PersonRepository repository;
@Override
protected PersonRepository getRepository(Regions regions) {
return repository;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.repository.query.parser.PartTree;
/**
* Unit tests for {@link GemfireQueryCreator}.
*
* @author Oliver Gierke
*/
public class GemfireQueryCreatorUnitTests {
GemfirePersistentEntity<Person> entity;
@Before
@SuppressWarnings("unchecked")
public void setUp() {
GemfireMappingContext context = new GemfireMappingContext();
entity = (GemfirePersistentEntity<Person>) context.getPersistentEntity(Person.class);
}
@Test
public void createsQueryForSimplePropertyReferenceCorrectly() {
PartTree partTree = new PartTree("findByFirstname", Person.class);
GemfireQueryCreator creator = new GemfireQueryCreator(partTree, entity);
QueryString query = creator.createQuery();
assertThat(query.toString(), is("SELECT * FROM /simple x WHERE x.firstname = $1"));
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.repository.Query;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.repository.core.RepositoryMetadata;
/**
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class GemfireQueryMethodUnitTests {
@Mock
RepositoryMetadata metadata;
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void detectsAnnotatedQueryCorrectly() throws Exception {
GemfireMappingContext context = new GemfireMappingContext();
when(metadata.getDomainType()).thenReturn((Class) Person.class);
when(metadata.getReturnedDomainClass(Mockito.any(Method.class))).thenReturn((Class) Person.class);
GemfireQueryMethod method = new GemfireQueryMethod(Sample.class.getMethod("annotated"), metadata, context);
assertThat(method.hasAnnotatedQuery(), is(true));
assertThat(method.getAnnotatedQuery(), is("foo"));
method = new GemfireQueryMethod(Sample.class.getMethod("annotatedButEmpty"), metadata, context);
assertThat(method.hasAnnotatedQuery(), is(false));
assertThat(method.getAnnotatedQuery(), is(nullValue()));
method = new GemfireQueryMethod(Sample.class.getMethod("notAnnotated"), metadata, context);
assertThat(method.hasAnnotatedQuery(), is(false));
assertThat(method.getAnnotatedQuery(), is(nullValue()));
}
interface Sample {
@Query("foo")
void annotated();
@Query("")
void annotatedButEmpty();
void notAnnotated();
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Iterator;
import org.junit.Test;
import org.springframework.data.gemfire.repository.query.Predicates.AtomicPredicate;
import org.springframework.data.repository.query.parser.Part;
/**
*
* @author Oliver Gierke
*/
public class PredicatesUnitTests {
@Test
public void atomicPredicateDefaultsAlias() {
Part part = new Part("firstname", Person.class);
Iterable<Integer> indexes = Arrays.asList(1);
Predicate predicate = new AtomicPredicate(part, indexes.iterator());
assertThat(predicate.toString(null), is("x.firstname = $1"));
}
@Test
public void concatenatesAndPredicateCorrectly() {
Part left = new Part("firstname", Person.class);
Part right = new Part("lastname", Person.class);
Iterator<Integer> indexes = Arrays.asList(1, 2).iterator();
Predicates predicate = Predicates.create(left, indexes);
predicate = predicate.and(new AtomicPredicate(right, indexes));
assertThat(predicate.toString(null), is("x.firstname = $1 AND x.lastname = $2"));
}
@Test
public void concatenatesOrPredicateCorrectly() {
Part left = new Part("firstname", Person.class);
Part right = new Part("lastname", Person.class);
Iterator<Integer> indexes = Arrays.asList(1, 2).iterator();
Predicates predicate = Predicates.create(left, indexes);
predicate = predicate.or(new AtomicPredicate(right, indexes));
assertThat(predicate.toString(null), is("x.firstname = $1 OR x.lastname = $2"));
}
static class Person {
String firstname;
String lastname;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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 static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.gemfire.repository.sample.Person;
import com.gemstone.gemfire.cache.Region;
/**
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class QueryStringUnitTests {
@Mock
@SuppressWarnings("rawtypes")
Region region;
@Test
public void replacesDomainObjectWithRegionNameCorrectly() {
QueryString query = new QueryString("SELECT * FROM /Person p WHERE p.firstname = $1");
when(region.getName()).thenReturn("foo");
assertThat(query.forRegion(Person.class, region).toString(), is("SELECT * FROM /foo p WHERE p.firstname = $1"));
}
@Test
public void bindsInValuesCorrectly() {
QueryString query = new QueryString("SELECT * FROM /Person p WHERE p.firstname IN SET $1");
List<Integer> values = Arrays.asList(1, 2, 3);
assertThat(query.bindIn(values).toString(), is("SELECT * FROM /Person p WHERE p.firstname IN SET ('1', '2', '3')"));
}
@Test
public void detectsInParameterIndexesCorrectly() {
QueryString query = new QueryString("IN SET $1 OR IN SET $2");
Iterable<Integer> indexes = query.getInParameterIndexes();
assertThat(indexes, is((Iterable<Integer>) Arrays.asList(1, 2)));
}
}

View File

@@ -0,0 +1,26 @@
/*
* 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.sample;
/**
*
* @author Oliver Gierke
*/
public class Address {
public String zipCode;
public String city;
}

View File

@@ -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.repository.sample;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.Region;
/**
*
* @author Oliver Gierke
*/
@Region("simple")
public class Person implements Serializable {
private static final long serialVersionUID = 508843183613325255L;
@Id
public Long id;
public String firstname;
public String lastname;
public Address address;
public Person(Long id, String firstname, String lastname) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
}
/**
* @return the firstname
*/
public String getFirstname() {
return firstname;
}
/**
* @return the lastname
*/
public String getLastname() {
return lastname;
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.sample;
import java.util.Collection;
import org.springframework.data.gemfire.repository.Query;
import org.springframework.data.repository.Repository;
/**
*
*
* @author Oliver Gierke
*/
public interface PersonRepository extends Repository<Person, Long> {
@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);
Collection<Person> findByFirstname(String firstname);
Collection<Person> findByFirstnameIn(Collection<String> firstnames);
Collection<Person> findByFirstnameIn(String... firstnames);
Collection<Person> findByFirstnameAndLastname(String firstname, String lastname);
Collection<Person> findByFirstnameOrLastname(String firstname, String lastname);
}

View File

@@ -0,0 +1,120 @@
/*
* 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.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.Regions;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.gemfire.repository.sample.PersonRepository;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.gemstone.gemfire.cache.Region;
/**
* Integration test for {@link GemfireRepositoryFactory}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
public abstract class AbstractGemfireRepositoryFactoryIntegrationTests {
@Autowired
List<Region<?, ?>> regions;
Person dave, carter, boyd, stefan, leroi, jeff;
PersonRepository repository;
@Before
public void setUp() {
dave = new Person(1L, "Dave", "Matthews");
carter = new Person(2L, "Carter", "Beauford");
boyd = new Person(3L, "Boyd", "Tinsley");
stefan = new Person(4L, "Stefan", "Lessard");
leroi = new Person(5L, "Leroi", "Moore");
jeff = new Person(6L, "Jeff", "Coffin");
GemfireMappingContext context = new GemfireMappingContext();
Regions regions = new Regions(this.regions, context);
GemfireTemplate template = new GemfireTemplate(regions.getRegion(Person.class));
template.put(dave.id, dave);
template.put(carter.id, carter);
template.put(boyd.id, boyd);
template.put(stefan.id, stefan);
template.put(leroi.id, leroi);
template.put(jeff.id, jeff);
repository = getRepository(regions);
}
protected abstract PersonRepository getRepository(Regions regions);
@Test
public void foo() {
assertResultsFound(repository.findByFirstnameAnnotated("Dave"), dave);
}
@Test
public void executesAnnotatedInQueryMethodCorrectly() {
assertResultsFound(repository.findByFirstnamesAnnotated(Arrays.asList("Carter", "Dave")), carter, dave);
}
@Test
public void executesInQueryMethodCorrectly() {
assertResultsFound(repository.findByFirstnameIn(Arrays.asList("Carter", "Dave")), carter, dave);
}
@Test
public void executesDerivedQueryCorrectly() {
assertResultsFound(repository.findByFirstname("Carter"), carter);
assertResultsFound(repository.findByFirstnameIn(Arrays.asList("Stefan", "Boyd")), stefan, boyd);
assertResultsFound(repository.findByFirstnameIn("Leroi"), leroi);
}
@Test
public void executesDerivedQueryWithAndCorrectly() {
assertResultsFound(repository.findByFirstnameAndLastname("Carter", "Beauford"), carter);
}
@Test
public void executesDerivedQueryWithOrCorrectly() {
assertResultsFound(repository.findByFirstnameOrLastname("Carter", "Matthews"), carter, dave);
}
private <T> void assertResultsFound(Collection<T> result, T... expected) {
assertThat(result, is(notNullValue()));
assertThat(result.size(), is(expected.length));
for (T element : expected) {
assertThat(result.contains(element), is(true));
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.support;
import org.junit.Test;
import org.springframework.data.gemfire.mapping.Regions;
import org.springframework.data.gemfire.repository.sample.PersonRepository;
import org.springframework.test.context.ContextConfiguration;
import com.gemstone.bp.edu.emory.mathcs.backport.java.util.Collections;
/**
* Integration test for {@link GemfireRepositoryFactory}.
*
* @author Oliver Gierke
*/
@ContextConfiguration("../config/repo-context.xml")
public class GemfireRepositoryFactoryIntegrationTests extends AbstractGemfireRepositoryFactoryIntegrationTests {
@Override
protected PersonRepository getRepository(Regions regions) {
GemfireRepositoryFactory factory = new GemfireRepositoryFactory(regions, null);
return factory.getRepository(PersonRepository.class);
}
@Test(expected = IllegalStateException.class)
@SuppressWarnings("unchecked")
public void throwsExceptionIfReferencedRegionIsNotConfigured() {
GemfireRepositoryFactory factory = new GemfireRepositoryFactory(Collections.emptySet(), null);
factory.getRepository(PersonRepository.class);
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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.support;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.support.ReflectionEntityInformation;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.gemstone.gemfire.cache.query.SelectResults;
/**
* Integration tests for {@link SimpleGemfireRepository}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("../../basic-template.xml")
public class SimpleGemfireRepositoryIntegrationTest {
@Autowired
GemfireTemplate template;
SimpleGemfireRepository<Person, Long> repository;
@Before
public void setUp() {
EntityInformation<Person, Long> information = new ReflectionEntityInformation<Person, Long>(Person.class);
repository = new SimpleGemfireRepository<Person, Long>(template, information);
}
@Test
public void storeAndDeleteEntity() {
Person person = new Person(1L, "Oliver", "Gierke");
repository.save(person);
assertThat(repository.count(), is(1L));
assertThat(repository.findOne(person.id), is(person));
assertThat(repository.findAll().size(), is(1));
repository.delete(person);
assertThat(repository.count(), is(0L));
assertThat(repository.findOne(person.id), is(nullValue()));
assertThat(repository.findAll().size(), is(0));
}
@Test
public void queryRegion() throws Exception {
Person person = new Person(1L, "Oliver", "Gierke");
template.put(1L, person);
SelectResults<Person> persons = template.find("SELECT * FROM /simple s WHERE s.firstname = $1", person.firstname);
assertThat(persons.size(), is(1));
assertThat(persons.iterator().next(), is(person));
}
@Test
public void findAllWithGivenIds() {
Person dave = new Person(1L, "Dave", "Matthews");
Person carter = new Person(2L, "Carter", "Beauford");
Person leroi = new Person(3L, "Leroi", "Moore");
template.put(dave.id, dave);
template.put(carter.id, carter);
template.put(leroi.id, leroi);
Collection<Person> result = repository.findAll(Arrays.asList(carter.id, leroi.id));
assertThat(result, hasItems(carter, leroi));
assertThat(result, not(hasItems(dave)));
}
}

View File

@@ -5,6 +5,7 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.category.org.springframework.data.gemfire.listener=TRACE
log4j.category.org.springframework.data.gemfire.repository=DEBUG
# for debugging datasource initialization
# log4j.category.test.jdbc=DEBUG

View File

@@ -12,6 +12,6 @@
</gfe:pool>
-->
<gfe:cache/>
<gfe:client-cache/>
<gfe:client-region data-policy="NORMAL" name="ChallengeQuestions" id="challengeQuestionsRegion"/>
</beans>

View File

@@ -9,7 +9,7 @@
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<gfe:cache />
<gfe:client-cache />
<gfe:client-region id="simple" pool-name="gemfire-pool"/>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xsi:schemaLocation="http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<gfe:repositories base-package="org.springframework.data.gemfire.repository.sample" />
<gfe:cache use-bean-factory-locator="false" />
<gfe:replicated-region id="simple" />
</beans>

View File

@@ -12,6 +12,8 @@ Import-Template:
org.springframework.context.*;version=${spring.range},
org.springframework.core.*;version=${spring.range},
org.springframework.dao.*;version=${spring.range},
org.springframework.data.*;version="${springDataCommonsVersion:[=.=.=.=,+1.0.0)}",
org.springframework.expression.*;version="${springVersion:[=.=.=,+1.0.0)}",
org.springframework.util.*;version=${spring.range},
org.springframework.transaction.*;version=${spring.range},
com.gemstone.gemfire.*;version=${gemfire.range},