SGF-548 - Configure Regions with annotations.
Related JIRA: SGF-250 - @EnableGemfireRegions for @Region.
(cherry picked from commit 701aa5f6ef)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.data.gemfire;
|
package org.springframework.data.gemfire;
|
||||||
|
|
||||||
import org.apache.geode.cache.FixedPartitionAttributes;
|
import org.apache.geode.cache.FixedPartitionAttributes;
|
||||||
@@ -21,15 +22,93 @@ import org.springframework.beans.factory.InitializingBean;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author David Turanski
|
* Spring {@link FactoryBean} to create a instance of the {@link FixedPartitionAttributes}.
|
||||||
*
|
*
|
||||||
|
* @author David Turanski
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean
|
||||||
|
* @see org.springframework.beans.factory.InitializingBean
|
||||||
|
* @see org.apache.geode.cache.FixedPartitionAttributes
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class FixedPartitionAttributesFactoryBean implements FactoryBean<FixedPartitionAttributes>, InitializingBean {
|
public class FixedPartitionAttributesFactoryBean implements FactoryBean<FixedPartitionAttributes>, InitializingBean {
|
||||||
|
|
||||||
private Boolean primary;
|
private Boolean primary;
|
||||||
private String partitionName;
|
|
||||||
private Integer numBuckets;
|
|
||||||
private FixedPartitionAttributes fixedPartitionAttributes;
|
private FixedPartitionAttributes fixedPartitionAttributes;
|
||||||
|
|
||||||
|
private Integer numBuckets;
|
||||||
|
|
||||||
|
private String partitionName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.hasText(this.partitionName, "partitionName must be specified");
|
||||||
|
|
||||||
|
if (this.primary == null && this.numBuckets == null){
|
||||||
|
this.fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(this.partitionName);
|
||||||
|
}
|
||||||
|
else if (this.primary == null && this.numBuckets != null){
|
||||||
|
this.fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(
|
||||||
|
this.partitionName, this.numBuckets);
|
||||||
|
}
|
||||||
|
else if (this.primary != null && this.numBuckets == null) {
|
||||||
|
this.fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(
|
||||||
|
this.partitionName, this.primary);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(
|
||||||
|
this.partitionName, this.primary, this.numBuckets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FixedPartitionAttributes getObject() throws Exception {
|
||||||
|
return this.fixedPartitionAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return (this.fixedPartitionAttributes != null ? this.fixedPartitionAttributes.getClass()
|
||||||
|
: FixedPartitionAttributes.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of buckets in the Partition Region.
|
||||||
|
*
|
||||||
|
* @param numBuckets integer value indicating the number of buckets in the Partition Region.
|
||||||
|
*/
|
||||||
|
public void setNumBuckets(Integer numBuckets) {
|
||||||
|
this.numBuckets = numBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of the partition in the Partition Region.
|
||||||
|
*
|
||||||
|
* @param partitionName name of the partition.
|
||||||
|
*/
|
||||||
|
public void setPartitionName(String partitionName) {
|
||||||
|
this.partitionName = partitionName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether this particular PARTITION Region is the primary (i.e. not secondary).
|
* Sets whether this particular PARTITION Region is the primary (i.e. not secondary).
|
||||||
*
|
*
|
||||||
@@ -38,63 +117,4 @@ public class FixedPartitionAttributesFactoryBean implements FactoryBean<FixedPar
|
|||||||
public void setPrimary(boolean primary) {
|
public void setPrimary(boolean primary) {
|
||||||
this.primary = primary;
|
this.primary = primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param partitionName the partitionName to set
|
|
||||||
*/
|
|
||||||
public void setPartitionName(String partitionName) {
|
|
||||||
this.partitionName = partitionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param numBuckets the numBuckets to set
|
|
||||||
*/
|
|
||||||
public void setNumBuckets(Integer numBuckets) {
|
|
||||||
this.numBuckets = numBuckets;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public FixedPartitionAttributes getObject() throws Exception {
|
|
||||||
return fixedPartitionAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Class<?> getObjectType() {
|
|
||||||
return FixedPartitionAttributes.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isSingleton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
Assert.hasText(partitionName,"partitionName cannot be empty or null");
|
|
||||||
|
|
||||||
fixedPartitionAttributes = null;
|
|
||||||
if (primary == null && numBuckets == null){
|
|
||||||
fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(partitionName);
|
|
||||||
} else if (primary == null && numBuckets != null){
|
|
||||||
fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(partitionName, numBuckets);
|
|
||||||
} else if (primary != null && numBuckets == null) {
|
|
||||||
fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(partitionName, primary);
|
|
||||||
} else {
|
|
||||||
fixedPartitionAttributes = FixedPartitionAttributes.createFixedPartition(partitionName,primary,numBuckets);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,49 +20,84 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.geode.cache.FixedPartitionAttributes;
|
import org.apache.geode.cache.FixedPartitionAttributes;
|
||||||
import org.apache.geode.cache.PartitionAttributes;
|
import org.apache.geode.cache.PartitionAttributes;
|
||||||
|
import org.apache.geode.cache.PartitionAttributesFactory;
|
||||||
import org.apache.geode.cache.PartitionResolver;
|
import org.apache.geode.cache.PartitionResolver;
|
||||||
import org.apache.geode.cache.partition.PartitionListener;
|
import org.apache.geode.cache.partition.PartitionListener;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring-friendly bean for creating {@link PartitionAttributes}. Eliminates the need of using
|
* Spring {@link FactoryBean} for creating {@link PartitionAttributes}.
|
||||||
* a XML 'factory-method' tag and allows the attributes properties to be set directly.
|
*
|
||||||
|
* Eliminates the need to use a XML 'factory-method' tag and allows the attributes properties to be set directly.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
* @author David Turanski
|
* @author David Turanski
|
||||||
* @author John Blum
|
* @author John Blum
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean
|
||||||
|
* @see org.springframework.beans.factory.InitializingBean
|
||||||
|
* @see org.apache.geode.cache.FixedPartitionAttributes
|
||||||
|
* @see org.apache.geode.cache.PartitionAttributes
|
||||||
|
* @see org.apache.geode.cache.PartitionAttributesFactory
|
||||||
|
* @see org.apache.geode.cache.PartitionResolver
|
||||||
|
* @see org.apache.geode.cache.partition.PartitionListener
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
|
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
|
||||||
public class PartitionAttributesFactoryBean implements FactoryBean<PartitionAttributes>, InitializingBean {
|
public class PartitionAttributesFactoryBean<K, V> implements FactoryBean<PartitionAttributes<K, V>>, InitializingBean {
|
||||||
|
|
||||||
private final org.apache.geode.cache.PartitionAttributesFactory partitionAttributesFactory =
|
private List<PartitionListener> partitionListeners;
|
||||||
new org.apache.geode.cache.PartitionAttributesFactory();
|
|
||||||
|
|
||||||
private List<PartitionListener> listeners;
|
private PartitionAttributes<K, V> partitionAttributes;
|
||||||
|
|
||||||
|
private final PartitionAttributesFactory<K, V> partitionAttributesFactory =
|
||||||
|
new PartitionAttributesFactory<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
for (PartitionListener listener : CollectionUtils.nullSafeList(partitionListeners)) {
|
||||||
|
partitionAttributesFactory.addPartitionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.partitionAttributes = partitionAttributesFactory.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PartitionAttributes getObject() throws Exception {
|
public PartitionAttributes getObject() throws Exception {
|
||||||
return partitionAttributesFactory.create();
|
return this.partitionAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return PartitionAttributes.class;
|
return (this.partitionAttributes != null ? this.partitionAttributes.getClass() : PartitionAttributes.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isSingleton() {
|
public boolean isSingleton() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColocatedWith(String colocatedRegionFullPath) {
|
public void setColocatedWith(String collocatedWith) {
|
||||||
partitionAttributesFactory.setColocatedWith(colocatedRegionFullPath);
|
partitionAttributesFactory.setColocatedWith(collocatedWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFixedPartitionAttributes(List<FixedPartitionAttributes> fixedPartitionAttributes) {
|
public void setFixedPartitionAttributes(List<FixedPartitionAttributes> fixedPartitionAttributes) {
|
||||||
for (FixedPartitionAttributes fpa : fixedPartitionAttributes) {
|
for (FixedPartitionAttributes fixedPartitionAttributesElement :
|
||||||
partitionAttributesFactory.addFixedPartitionAttributes(fpa);
|
CollectionUtils.nullSafeList(fixedPartitionAttributes)) {
|
||||||
|
|
||||||
|
partitionAttributesFactory.addFixedPartitionAttributes(fixedPartitionAttributesElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,12 +105,12 @@ public class PartitionAttributesFactoryBean implements FactoryBean<PartitionAttr
|
|||||||
partitionAttributesFactory.setLocalMaxMemory(mb);
|
partitionAttributesFactory.setLocalMaxMemory(mb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPartitionResolver(PartitionResolver resolver) {
|
public void setPartitionListeners(List<PartitionListener> partitionListeners) {
|
||||||
partitionAttributesFactory.setPartitionResolver(resolver);
|
this.partitionListeners = partitionListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPartitionListeners(List<PartitionListener> listeners) {
|
public void setPartitionResolver(PartitionResolver resolver) {
|
||||||
this.listeners = listeners;
|
partitionAttributesFactory.setPartitionResolver(resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRecoveryDelay(long recoveryDelay) {
|
public void setRecoveryDelay(long recoveryDelay) {
|
||||||
@@ -97,15 +132,4 @@ public class PartitionAttributesFactoryBean implements FactoryBean<PartitionAttr
|
|||||||
public void setTotalNumBuckets(int numBuckets) {
|
public void setTotalNumBuckets(int numBuckets) {
|
||||||
partitionAttributesFactory.setTotalNumBuckets(numBuckets);
|
partitionAttributesFactory.setTotalNumBuckets(numBuckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
if (listeners != null) {
|
|
||||||
for (PartitionListener listener : listeners) {
|
|
||||||
partitionAttributesFactory.addPartitionListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
|||||||
|
|
||||||
private CacheWriter<K, V> cacheWriter;
|
private CacheWriter<K, V> cacheWriter;
|
||||||
|
|
||||||
|
private Class<K> keyConstraint;
|
||||||
|
private Class<V> valueConstraint;
|
||||||
|
|
||||||
private DataPolicy dataPolicy;
|
private DataPolicy dataPolicy;
|
||||||
|
|
||||||
private EvictionAttributes evictionAttributes;
|
private EvictionAttributes evictionAttributes;
|
||||||
@@ -146,10 +149,18 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
|||||||
regionFactory.setEvictionAttributes(evictionAttributes);
|
regionFactory.setEvictionAttributes(evictionAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyConstraint != null) {
|
||||||
|
regionFactory.setKeyConstraint(keyConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
regionFactory.setScope(scope);
|
regionFactory.setScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valueConstraint != null) {
|
||||||
|
regionFactory.setValueConstraint(valueConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
if (attributes != null) {
|
if (attributes != null) {
|
||||||
Assert.state(!attributes.isLockGrantor() || (scope == null) || scope.isGlobal(),
|
Assert.state(!attributes.isLockGrantor() || (scope == null) || scope.isGlobal(),
|
||||||
"Lock Grantor only applies to a 'GLOBAL' scoped Region.");
|
"Lock Grantor only applies to a 'GLOBAL' scoped Region.");
|
||||||
@@ -671,6 +682,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
|||||||
this.gatewaySenders = gatewaySenders;
|
this.gatewaySenders = gatewaySenders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setKeyConstraint(Class<K> keyConstraint) {
|
||||||
|
this.keyConstraint = keyConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPersistent(Boolean persistent) {
|
public void setPersistent(Boolean persistent) {
|
||||||
this.persistent = persistent;
|
this.persistent = persistent;
|
||||||
}
|
}
|
||||||
@@ -714,6 +729,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
|||||||
this.snapshot = snapshot;
|
this.snapshot = snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setValueConstraint(Class<V> valueConstraint) {
|
||||||
|
this.valueConstraint = valueConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,18 +70,17 @@ public abstract class RegionLookupFactoryBean<K, V>
|
|||||||
|
|
||||||
synchronized (this.cache) {
|
synchronized (this.cache) {
|
||||||
if (isLookupEnabled()) {
|
if (isLookupEnabled()) {
|
||||||
if (getParent() != null) {
|
this.region = (getParent() != null ? getParent().<K, V>getSubregion(regionName)
|
||||||
this.region = getParent().getSubregion(regionName);
|
: this.cache.<K, V>getRegion(regionName));
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.region = this.cache.getRegion(regionName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region != null) {
|
if (region != null) {
|
||||||
log.info(String.format("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName()));
|
log.info(String.format("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
log.info(String.format("Falling back to creating Region [%1$s] in Cache [%2$s]",
|
||||||
|
regionName, cache.getName()));
|
||||||
|
|
||||||
region = lookupRegion(cache, regionName);
|
region = lookupRegion(cache, regionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
package org.springframework.data.gemfire;
|
package org.springframework.data.gemfire;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.DataPolicy;
|
||||||
import org.apache.geode.cache.RegionShortcut;
|
import org.apache.geode.cache.RegionShortcut;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The RegionShortcutWrapper enum is a Java enumerated type that wraps GemFire's RegionShortcuts
|
* The {@link RegionShortcutWrapper} enum is a Java enumerated type that wraps GemFire's {@link RegionShortcut RegionShortcuts}
|
||||||
* with Spring Data GemFire RegionShortcutWrapper enumerated values.
|
* with Spring Data GemFire {@link RegionShortcutWrapper} enumerated values.
|
||||||
*
|
*
|
||||||
* @author John Blum
|
* @author John Blum
|
||||||
* @see org.apache.geode.cache.RegionShortcut
|
* @see org.apache.geode.cache.RegionShortcut
|
||||||
@@ -29,38 +30,41 @@ import org.springframework.util.ObjectUtils;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public enum RegionShortcutWrapper {
|
public enum RegionShortcutWrapper {
|
||||||
LOCAL(RegionShortcut.LOCAL),
|
LOCAL(RegionShortcut.LOCAL, DataPolicy.NORMAL),
|
||||||
LOCAL_HEAP_LRU(RegionShortcut.LOCAL_HEAP_LRU),
|
LOCAL_HEAP_LRU(RegionShortcut.LOCAL_HEAP_LRU, DataPolicy.NORMAL),
|
||||||
LOCAL_OVERFLOW(RegionShortcut.LOCAL_OVERFLOW),
|
LOCAL_OVERFLOW(RegionShortcut.LOCAL_OVERFLOW, DataPolicy.NORMAL),
|
||||||
LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT),
|
LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT, DataPolicy.NORMAL),
|
||||||
LOCAL_PERSISTENT_OVERFLOW(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW),
|
LOCAL_PERSISTENT_OVERFLOW(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
|
||||||
PARTITION(RegionShortcut.PARTITION),
|
PARTITION(RegionShortcut.PARTITION, DataPolicy.PARTITION),
|
||||||
PARTITION_HEAP_LRU(RegionShortcut.PARTITION_HEAP_LRU),
|
PARTITION_HEAP_LRU(RegionShortcut.PARTITION_HEAP_LRU, DataPolicy.PARTITION),
|
||||||
PARTITION_OVERFLOW(RegionShortcut.PARTITION_OVERFLOW),
|
PARTITION_OVERFLOW(RegionShortcut.PARTITION_OVERFLOW, DataPolicy.PARTITION),
|
||||||
PARTITION_PERSISTENT(RegionShortcut.PARTITION_PERSISTENT),
|
PARTITION_PERSISTENT(RegionShortcut.PARTITION_PERSISTENT, DataPolicy.PERSISTENT_PARTITION),
|
||||||
PARTITION_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW),
|
PARTITION_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_PARTITION),
|
||||||
PARTITION_PROXY(RegionShortcut.PARTITION_PROXY),
|
PARTITION_PROXY(RegionShortcut.PARTITION_PROXY, DataPolicy.PARTITION),
|
||||||
PARTITION_PROXY_REDUNDANT(RegionShortcut.PARTITION_PROXY_REDUNDANT),
|
PARTITION_PROXY_REDUNDANT(RegionShortcut.PARTITION_PROXY_REDUNDANT, DataPolicy.PARTITION),
|
||||||
PARTITION_REDUNDANT(RegionShortcut.PARTITION_REDUNDANT),
|
PARTITION_REDUNDANT(RegionShortcut.PARTITION_REDUNDANT, DataPolicy.PARTITION),
|
||||||
PARTITION_REDUNDANT_HEAP_LRU(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU),
|
PARTITION_REDUNDANT_HEAP_LRU(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU, DataPolicy.PARTITION),
|
||||||
PARTITION_REDUNDANT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW),
|
PARTITION_REDUNDANT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW, DataPolicy.PARTITION),
|
||||||
PARTITION_REDUNDANT_PERSISTENT(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT),
|
PARTITION_REDUNDANT_PERSISTENT(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT, DataPolicy.PERSISTENT_PARTITION),
|
||||||
PARTITION_REDUNDANT_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW),
|
PARTITION_REDUNDANT_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_PARTITION),
|
||||||
REPLICATE(RegionShortcut.REPLICATE),
|
REPLICATE(RegionShortcut.REPLICATE, DataPolicy.REPLICATE),
|
||||||
REPLICATE_HEAP_LRU(RegionShortcut.REPLICATE_HEAP_LRU),
|
REPLICATE_HEAP_LRU(RegionShortcut.REPLICATE_HEAP_LRU, DataPolicy.REPLICATE),
|
||||||
REPLICATE_OVERFLOW(RegionShortcut.REPLICATE_OVERFLOW),
|
REPLICATE_OVERFLOW(RegionShortcut.REPLICATE_OVERFLOW, DataPolicy.REPLICATE),
|
||||||
REPLICATE_PERSISTENT(RegionShortcut.REPLICATE_PERSISTENT),
|
REPLICATE_PERSISTENT(RegionShortcut.REPLICATE_PERSISTENT, DataPolicy.PERSISTENT_REPLICATE),
|
||||||
REPLICATE_PERSISTENT_OVERFLOW(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW),
|
REPLICATE_PERSISTENT_OVERFLOW(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
|
||||||
REPLICATE_PROXY(RegionShortcut.REPLICATE_PROXY),
|
REPLICATE_PROXY(RegionShortcut.REPLICATE_PROXY, DataPolicy.EMPTY),
|
||||||
UNSPECIFIED(null);
|
UNSPECIFIED(null, null);
|
||||||
|
|
||||||
|
private final DataPolicy dataPolicy;
|
||||||
|
|
||||||
private final RegionShortcut regionShortcut;
|
private final RegionShortcut regionShortcut;
|
||||||
|
|
||||||
RegionShortcutWrapper(final RegionShortcut regionShortcut) {
|
RegionShortcutWrapper(RegionShortcut regionShortcut, DataPolicy dataPolicy) {
|
||||||
this.regionShortcut = regionShortcut;
|
this.regionShortcut = regionShortcut;
|
||||||
|
this.dataPolicy = dataPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegionShortcutWrapper valueOf(final RegionShortcut regionShortcut) {
|
public static RegionShortcutWrapper valueOf(RegionShortcut regionShortcut) {
|
||||||
for (RegionShortcutWrapper wrapper : values()) {
|
for (RegionShortcutWrapper wrapper : values()) {
|
||||||
if (ObjectUtils.nullSafeEquals(wrapper.getRegionShortcut(), regionShortcut)) {
|
if (ObjectUtils.nullSafeEquals(wrapper.getRegionShortcut(), regionShortcut)) {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
@@ -70,6 +74,14 @@ public enum RegionShortcutWrapper {
|
|||||||
return RegionShortcutWrapper.UNSPECIFIED;
|
return RegionShortcutWrapper.UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataPolicy getDataPolicy() {
|
||||||
|
return this.dataPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionShortcut getRegionShortcut() {
|
||||||
|
return this.regionShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isHeapLru() {
|
public boolean isHeapLru() {
|
||||||
return name().contains("HEAP_LRU");
|
return name().contains("HEAP_LRU");
|
||||||
}
|
}
|
||||||
@@ -105,9 +117,4 @@ public enum RegionShortcutWrapper {
|
|||||||
public boolean isReplicate() {
|
public boolean isReplicate() {
|
||||||
return name().contains("REPLICATE");
|
return name().contains("REPLICATE");
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegionShortcut getRegionShortcut() {
|
|
||||||
return regionShortcut;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
|||||||
|
|
||||||
private CacheWriter<K, V> cacheWriter;
|
private CacheWriter<K, V> cacheWriter;
|
||||||
|
|
||||||
|
private Class<K> keyConstraint;
|
||||||
|
private Class<V> valueConstraint;
|
||||||
|
|
||||||
private ClientRegionShortcut shortcut = null;
|
private ClientRegionShortcut shortcut = null;
|
||||||
|
|
||||||
private DataPolicy dataPolicy;
|
private DataPolicy dataPolicy;
|
||||||
@@ -125,6 +128,14 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
|||||||
setEvictionAttributes(clientRegionFactory);
|
setEvictionAttributes(clientRegionFactory);
|
||||||
setPoolName(clientRegionFactory);
|
setPoolName(clientRegionFactory);
|
||||||
|
|
||||||
|
if (keyConstraint != null) {
|
||||||
|
clientRegionFactory.setKeyConstraint(keyConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueConstraint != null) {
|
||||||
|
clientRegionFactory.setValueConstraint(valueConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
return logCreateRegionEvent(create(clientRegionFactory, regionName));
|
return logCreateRegionEvent(create(clientRegionFactory, regionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,6 +573,10 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
|||||||
return this.interests;
|
return this.interests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setKeyConstraint(Class<K> keyConstraint) {
|
||||||
|
this.keyConstraint = keyConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean isPersistentUnspecified() {
|
protected boolean isPersistentUnspecified() {
|
||||||
return (persistent == null);
|
return (persistent == null);
|
||||||
}
|
}
|
||||||
@@ -619,4 +634,8 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
|||||||
public void setSnapshot(Resource snapshot) {
|
public void setSnapshot(Resource snapshot) {
|
||||||
this.snapshot = snapshot;
|
this.snapshot = snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setValueConstraint(Class<V> valueConstraint) {
|
||||||
|
this.valueConstraint = valueConstraint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
package org.springframework.data.gemfire.client;
|
package org.springframework.data.gemfire.client;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.DataPolicy;
|
||||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ClientRegionShortcutWrapper enum is a Java enumerated type that wraps GemFire's ClientRegionShortcuts
|
* The {@link ClientRegionShortcutWrapper} enum is a Java enumerated type that wraps GemFire's {@link ClientRegionShortcut ClientRegionShortcuts}
|
||||||
* with Spring Data GemFire ClientRegionShortcutWrapper enumerated values.
|
* with Spring Data GemFire {@link ClientRegionShortcutWrapper} enumerated values.
|
||||||
*
|
*
|
||||||
* @author John Blum
|
* @author John Blum
|
||||||
* @see org.apache.geode.cache.client.ClientRegionShortcut
|
* @see org.apache.geode.cache.client.ClientRegionShortcut
|
||||||
@@ -29,24 +30,27 @@ import org.springframework.util.ObjectUtils;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public enum ClientRegionShortcutWrapper {
|
public enum ClientRegionShortcutWrapper {
|
||||||
CACHING_PROXY(ClientRegionShortcut.CACHING_PROXY),
|
CACHING_PROXY(ClientRegionShortcut.CACHING_PROXY, DataPolicy.NORMAL),
|
||||||
CACHING_PROXY_HEAP_LRU(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU),
|
CACHING_PROXY_HEAP_LRU(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU, DataPolicy.NORMAL),
|
||||||
CACHING_PROXY_OVERFLOW(ClientRegionShortcut.CACHING_PROXY_OVERFLOW),
|
CACHING_PROXY_OVERFLOW(ClientRegionShortcut.CACHING_PROXY_OVERFLOW, DataPolicy.NORMAL),
|
||||||
LOCAL(ClientRegionShortcut.LOCAL),
|
LOCAL(ClientRegionShortcut.LOCAL, DataPolicy.NORMAL),
|
||||||
LOCAL_HEAP_LRU(ClientRegionShortcut.LOCAL_HEAP_LRU),
|
LOCAL_HEAP_LRU(ClientRegionShortcut.LOCAL_HEAP_LRU, DataPolicy.NORMAL),
|
||||||
LOCAL_OVERFLOW(ClientRegionShortcut.LOCAL_OVERFLOW),
|
LOCAL_OVERFLOW(ClientRegionShortcut.LOCAL_OVERFLOW, DataPolicy.NORMAL),
|
||||||
LOCAL_PERSISTENT(ClientRegionShortcut.LOCAL_PERSISTENT),
|
LOCAL_PERSISTENT(ClientRegionShortcut.LOCAL_PERSISTENT, DataPolicy.PERSISTENT_REPLICATE),
|
||||||
LOCAL_PERSISTENT_OVERFLOW(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW),
|
LOCAL_PERSISTENT_OVERFLOW(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
|
||||||
PROXY(ClientRegionShortcut.PROXY),
|
PROXY(ClientRegionShortcut.PROXY, DataPolicy.EMPTY),
|
||||||
UNSPECIFIED(null);
|
UNSPECIFIED(null, null);
|
||||||
|
|
||||||
private final ClientRegionShortcut clientRegionShortcut;
|
private final ClientRegionShortcut clientRegionShortcut;
|
||||||
|
|
||||||
ClientRegionShortcutWrapper(final ClientRegionShortcut clientRegionShortcut) {
|
private final DataPolicy dataPolicy;
|
||||||
|
|
||||||
|
ClientRegionShortcutWrapper(ClientRegionShortcut clientRegionShortcut, DataPolicy dataPolicy) {
|
||||||
this.clientRegionShortcut = clientRegionShortcut;
|
this.clientRegionShortcut = clientRegionShortcut;
|
||||||
|
this.dataPolicy = dataPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClientRegionShortcutWrapper valueOf(final ClientRegionShortcut clientRegionShortcut) {
|
public static ClientRegionShortcutWrapper valueOf(ClientRegionShortcut clientRegionShortcut) {
|
||||||
for (ClientRegionShortcutWrapper wrapper : values()) {
|
for (ClientRegionShortcutWrapper wrapper : values()) {
|
||||||
if (ObjectUtils.nullSafeEquals(wrapper.getClientRegionShortcut(), clientRegionShortcut)) {
|
if (ObjectUtils.nullSafeEquals(wrapper.getClientRegionShortcut(), clientRegionShortcut)) {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
@@ -57,7 +61,11 @@ public enum ClientRegionShortcutWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ClientRegionShortcut getClientRegionShortcut() {
|
public ClientRegionShortcut getClientRegionShortcut() {
|
||||||
return clientRegionShortcut;
|
return this.clientRegionShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataPolicy getDataPolicy() {
|
||||||
|
return this.dataPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCaching() {
|
public boolean isCaching() {
|
||||||
@@ -87,5 +95,4 @@ public enum ClientRegionShortcutWrapper {
|
|||||||
public boolean isProxy() {
|
public boolean isProxy() {
|
||||||
return name().contains("PROXY");
|
return name().contains("PROXY");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.Region;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link EnableEntityDefinedRegions} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
|
||||||
|
* annotated class to enable the creation of the GemFire/Geode {@link Region Regions} based on
|
||||||
|
* the application domain model object entities.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.context.annotation.ComponentScan
|
||||||
|
* @see org.springframework.context.annotation.Import
|
||||||
|
* @see org.springframework.core.annotation.AliasFor
|
||||||
|
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
|
||||||
|
* @see org.apache.geode.cache.Region
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Import(EntityDefinedRegionsConfiguration.class)
|
||||||
|
@SuppressWarnings({ "unused" })
|
||||||
|
public @interface EnableEntityDefinedRegions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for {@link #basePackages()} attribute.
|
||||||
|
*
|
||||||
|
* @return a {@link String} array specifying the packages to search for application persistent entities.
|
||||||
|
* @see #basePackages()
|
||||||
|
*/
|
||||||
|
@AliasFor(attribute = "basePackages")
|
||||||
|
String[] value() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base packages to scan for {@link org.springframework.data.gemfire.mapping.Region @Region} annotated
|
||||||
|
* application persistent entities. {@link #value()} is an alias for this attribute.
|
||||||
|
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
|
||||||
|
*
|
||||||
|
* @return a {@link String} array specifying the packages to search for application persistent entities.
|
||||||
|
* @see #value()
|
||||||
|
*/
|
||||||
|
@AliasFor(attribute = "value")
|
||||||
|
String[] basePackages() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for
|
||||||
|
* {@link org.springframework.data.gemfire.mapping.Region @Region} annotated application persistent entities.
|
||||||
|
* The package of each class specified will be scanned. Consider creating a special no-op marker class or interface
|
||||||
|
* in each package that serves no other purpose than being referenced by this attribute.
|
||||||
|
*
|
||||||
|
* @return an array of {@link Class classes} used to determine the packages to scan
|
||||||
|
* for application persistent entities.
|
||||||
|
*/
|
||||||
|
Class<?>[] basePackageClasses() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components
|
||||||
|
* from everything in {@link #basePackages()} to everything in the base packages that matches the given filter
|
||||||
|
* or filters.
|
||||||
|
*
|
||||||
|
* @return an array {@link org.springframework.context.annotation.ComponentScan.Filter} of Filters used to
|
||||||
|
* specify application persistent entities to be included during the component scan.
|
||||||
|
*/
|
||||||
|
ComponentScan.Filter[] includeFilters() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies which types are not eligible for component scanning.
|
||||||
|
*
|
||||||
|
* @return an array of {@link org.springframework.context.annotation.ComponentScan.Filter Filters} used to
|
||||||
|
* specify application persistent entities to be excluded during the component scan.
|
||||||
|
*/
|
||||||
|
ComponentScan.Filter[] excludeFilters() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the created {@link Region} will have strongly-typed key and value constraints
|
||||||
|
* based on the ID and {@link Class} type of application persistent entity.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false}.
|
||||||
|
*/
|
||||||
|
boolean strict() default false;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,603 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation;
|
||||||
|
|
||||||
|
import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
|
||||||
|
import static org.springframework.data.gemfire.util.ArrayUtils.defaultIfEmpty;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.Region;
|
||||||
|
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.beans.factory.support.ManagedList;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||||
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||||
|
import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||||
|
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||||
|
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||||
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
|
import org.springframework.data.gemfire.FixedPartitionAttributesFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.LocalRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.PartitionAttributesFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.RegionLookupFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.ScopeType;
|
||||||
|
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner;
|
||||||
|
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||||
|
import org.springframework.data.gemfire.mapping.ClientRegion;
|
||||||
|
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
|
||||||
|
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||||
|
import org.springframework.data.gemfire.mapping.LocalRegion;
|
||||||
|
import org.springframework.data.gemfire.mapping.PartitionRegion;
|
||||||
|
import org.springframework.data.gemfire.mapping.ReplicateRegion;
|
||||||
|
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||||
|
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EntityDefinedRegionsConfiguration class...
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class EntityDefinedRegionsConfiguration
|
||||||
|
implements BeanClassLoaderAware, BeanFactoryAware, ImportBeanDefinitionRegistrar {
|
||||||
|
|
||||||
|
protected static final Class<? extends RegionLookupFactoryBean> DEFAULT_REGION_FACTORY_BEAN_CLASS =
|
||||||
|
GemFireCacheTypeAwareRegionFactoryBean.class;
|
||||||
|
|
||||||
|
protected static final Map<Class<? extends Annotation>, Class<? extends RegionLookupFactoryBean>> regionAnnotationToRegionFactoryBeanClass =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
regionAnnotationToRegionFactoryBeanClass.put(ClientRegion.class, ClientRegionFactoryBean.class);
|
||||||
|
regionAnnotationToRegionFactoryBeanClass.put(LocalRegion.class, LocalRegionFactoryBean.class);
|
||||||
|
regionAnnotationToRegionFactoryBeanClass.put(PartitionRegion.class, PartitionedRegionFactoryBean.class);
|
||||||
|
regionAnnotationToRegionFactoryBeanClass.put(ReplicateRegion.class, ReplicatedRegionFactoryBean.class);
|
||||||
|
regionAnnotationToRegionFactoryBeanClass.put(org.springframework.data.gemfire.mapping.Region.class,
|
||||||
|
DEFAULT_REGION_FACTORY_BEAN_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeanFactory beanFactory;
|
||||||
|
|
||||||
|
private ClassLoader beanClassLoader;
|
||||||
|
|
||||||
|
private GemfireMappingContext mappingContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link Annotation} {@link Class type} that configures and creates {@link Region Regions}
|
||||||
|
* for application persistent entities.
|
||||||
|
*
|
||||||
|
* @return the {@link Annotation} {@link Class type} that configures and creates {@link Region Regions}
|
||||||
|
* for application persistent entities.
|
||||||
|
* @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions
|
||||||
|
* @see java.lang.annotation.Annotation
|
||||||
|
* @see java.lang.Class
|
||||||
|
*/
|
||||||
|
protected Class<? extends Annotation> getAnnotationType() {
|
||||||
|
return EnableEntityDefinedRegions.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the {@link Annotation} type that configures and creates {@link Region Regions}
|
||||||
|
* for application persistent entities.
|
||||||
|
*
|
||||||
|
* @return the name of the {@link Annotation} type that configures and creates {@link Region Regions}
|
||||||
|
* for application persistent entities.
|
||||||
|
* @see java.lang.Class#getName()
|
||||||
|
* @see #getAnnotationType()
|
||||||
|
*/
|
||||||
|
protected String getAnnotationTypeName() {
|
||||||
|
return getAnnotationType().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the simple name of the {@link Annotation} type that configures and creates {@link Region Regions}
|
||||||
|
* for application persistent entities.
|
||||||
|
*
|
||||||
|
* @return the simple name of the {@link Annotation} type that configures and creates {@link Region Regions}
|
||||||
|
* for application persistent entities.
|
||||||
|
* @see java.lang.Class#getSimpleName()
|
||||||
|
* @see #getAnnotationType()
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
protected String getAnnotationTypeSimpleName() {
|
||||||
|
return getAnnotationType().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
this.beanClassLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected ClassLoader getBeanClassLoader() {
|
||||||
|
return this.beanClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanFactory getBeanFactory() {
|
||||||
|
return this.beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata) {
|
||||||
|
return isAnnotationPresent(importingClassMetadata, getAnnotationTypeName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata, String annotationName) {
|
||||||
|
return importingClassMetadata.hasAnnotation(annotationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected AnnotationAttributes getAnnotationAttributes(AnnotationMetadata importingClassMetadata) {
|
||||||
|
return getAnnotationAttributes(importingClassMetadata, getAnnotationTypeName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected AnnotationAttributes getAnnotationAttributes(AnnotationMetadata importingClassMetadata,
|
||||||
|
String annotationName) {
|
||||||
|
|
||||||
|
return AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(annotationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected GemfirePersistentEntity<?> getPersistentEntity(Class<?> persistentEntityType) {
|
||||||
|
return resolveMappingContext().getPersistentEntity(persistentEntityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected GemfireMappingContext resolveMappingContext() {
|
||||||
|
if (this.mappingContext == null) {
|
||||||
|
try {
|
||||||
|
this.mappingContext = getBeanFactory().getBean(GemfireMappingContext.class);
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) {
|
||||||
|
this.mappingContext = new GemfireMappingContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mappingContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||||
|
if (isAnnotationPresent(importingClassMetadata)) {
|
||||||
|
AnnotationAttributes enableEntityDefinedRegionsAttributes = getAnnotationAttributes(importingClassMetadata);
|
||||||
|
|
||||||
|
boolean strict = enableEntityDefinedRegionsAttributes.getBoolean("strict");
|
||||||
|
|
||||||
|
for (Class<?> persistentEntityClass : newGemFireComponentClassTypeScanner(
|
||||||
|
importingClassMetadata, enableEntityDefinedRegionsAttributes).scan()) {
|
||||||
|
|
||||||
|
GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass);
|
||||||
|
|
||||||
|
registerRegionBeanDefinition(persistentEntity, strict, registry);
|
||||||
|
postProcess(persistentEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected GemFireComponentClassTypeScanner newGemFireComponentClassTypeScanner(
|
||||||
|
AnnotationMetadata importingClassMetadata, AnnotationAttributes enableEntityDefinedRegionsAttributes) {
|
||||||
|
|
||||||
|
Set<String> resolvedBasePackages = resolveBasePackages(importingClassMetadata,
|
||||||
|
enableEntityDefinedRegionsAttributes);
|
||||||
|
|
||||||
|
return GemFireComponentClassTypeScanner.from(resolvedBasePackages).with(resolveBeanClassLoader())
|
||||||
|
.withExcludes(resolveExcludes(enableEntityDefinedRegionsAttributes))
|
||||||
|
.withIncludes(resolveIncludes(enableEntityDefinedRegionsAttributes))
|
||||||
|
.withIncludes(regionAnnotatedPersistentEntityTypeFilters());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected Set<String> resolveBasePackages(AnnotationMetadata importingClassMetaData,
|
||||||
|
AnnotationAttributes enableEntityDefinedRegionAttributes) {
|
||||||
|
|
||||||
|
Set<String> resolvedBasePackages = new HashSet<>();
|
||||||
|
|
||||||
|
Collections.addAll(resolvedBasePackages, ArrayUtils.nullSafeArray(defaultIfEmpty(
|
||||||
|
enableEntityDefinedRegionAttributes.getStringArray("basePackages"),
|
||||||
|
enableEntityDefinedRegionAttributes.getStringArray("value")), String.class));
|
||||||
|
|
||||||
|
for (Class<?> type : ArrayUtils.nullSafeArray(
|
||||||
|
enableEntityDefinedRegionAttributes.getClassArray("basePackageClasses"), Class.class)) {
|
||||||
|
|
||||||
|
resolvedBasePackages.add(type.getPackage().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedBasePackages.isEmpty()) {
|
||||||
|
resolvedBasePackages.add(ClassUtils.getPackageName(importingClassMetaData.getClassName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedBasePackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected ClassLoader resolveBeanClassLoader() {
|
||||||
|
return (this.beanClassLoader != null ? this.beanClassLoader : Thread.currentThread().getContextClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected Iterable<TypeFilter> resolveExcludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) {
|
||||||
|
return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("excludeFilters"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected Iterable<TypeFilter> resolveIncludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) {
|
||||||
|
return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("includeFilters"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
private Iterable<TypeFilter> parseFilters(AnnotationAttributes[] componentScanFilterAttributes) {
|
||||||
|
Set<TypeFilter> typeFilters = new HashSet<>();
|
||||||
|
|
||||||
|
for (AnnotationAttributes filterAttributes : ArrayUtils.nullSafeArray(
|
||||||
|
componentScanFilterAttributes, AnnotationAttributes.class)) {
|
||||||
|
|
||||||
|
CollectionUtils.addAll(typeFilters, typeFiltersFor(filterAttributes));
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Iterable<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
|
||||||
|
Set<TypeFilter> typeFilters = new HashSet<>();
|
||||||
|
FilterType filterType = filterAttributes.getEnum("type");
|
||||||
|
|
||||||
|
for (Class<?> filterClass : ArrayUtils.nullSafeArray(filterAttributes.getClassArray("value"), Class.class)) {
|
||||||
|
switch (filterType) {
|
||||||
|
case ANNOTATION:
|
||||||
|
Assert.isAssignable(Annotation.class, filterClass,
|
||||||
|
String.format("@ComponentScan.Filter class [%s] must be an Annotation", filterClass));
|
||||||
|
typeFilters.add(new AnnotationTypeFilter((Class<Annotation>) filterClass));
|
||||||
|
break;
|
||||||
|
case ASSIGNABLE_TYPE:
|
||||||
|
typeFilters.add(new AssignableTypeFilter(filterClass));
|
||||||
|
break;
|
||||||
|
case CUSTOM:
|
||||||
|
Assert.isAssignable(TypeFilter.class, filterClass,
|
||||||
|
String.format("@ComponentScan.Filter class [%s] must be a TypeFilter", filterClass));
|
||||||
|
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Illegal filter type [%s] when 'value' or 'classes' are specified", filterType));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String pattern : nullSafeGetPatterns(filterAttributes)) {
|
||||||
|
switch (filterType) {
|
||||||
|
case ASPECTJ:
|
||||||
|
typeFilters.add(new AspectJTypeFilter(pattern, resolveBeanClassLoader()));
|
||||||
|
break;
|
||||||
|
case REGEX:
|
||||||
|
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(pattern)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Illegal filter type [%s] when 'patterns' are specified", filterType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely reads the {@code pattern} attribute from the given {@link AnnotationAttributes}
|
||||||
|
* and returns an empty array if the attribute is not present.
|
||||||
|
*
|
||||||
|
* @param filterAttributes {@link AnnotationAttributes} from which to extract the {@code pattern} attribute value.
|
||||||
|
* @return a {@link String} array.
|
||||||
|
*/
|
||||||
|
private String[] nullSafeGetPatterns(AnnotationAttributes filterAttributes) {
|
||||||
|
try {
|
||||||
|
return ArrayUtils.nullSafeArray(filterAttributes.getStringArray("pattern"), String.class);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ignore) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected Iterable<TypeFilter> regionAnnotatedPersistentEntityTypeFilters() {
|
||||||
|
Set<TypeFilter> regionAnnotatedPersistentEntityTypeFilters = new HashSet<>();
|
||||||
|
|
||||||
|
for (Class<? extends Annotation> annotationType :
|
||||||
|
org.springframework.data.gemfire.mapping.Region.REGION_ANNOTATION_TYPES) {
|
||||||
|
|
||||||
|
regionAnnotatedPersistentEntityTypeFilters.add(new AnnotationTypeFilter(annotationType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionAnnotatedPersistentEntityTypeFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void registerRegionBeanDefinition(GemfirePersistentEntity persistentEntity, boolean strict,
|
||||||
|
BeanDefinitionRegistry registry) {
|
||||||
|
|
||||||
|
BeanDefinitionBuilder regionFactoryBeanBuilder =
|
||||||
|
BeanDefinitionBuilder.genericBeanDefinition(resolveRegionFactoryBeanClass(persistentEntity))
|
||||||
|
.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)
|
||||||
|
.addPropertyValue("close", false);
|
||||||
|
|
||||||
|
setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, strict);
|
||||||
|
|
||||||
|
registry.registerBeanDefinition(persistentEntity.getRegionName(),
|
||||||
|
regionFactoryBeanBuilder.getBeanDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected Class<? extends RegionLookupFactoryBean> resolveRegionFactoryBeanClass(
|
||||||
|
GemfirePersistentEntity persistentEntity) {
|
||||||
|
|
||||||
|
return defaultIfNull(regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType()),
|
||||||
|
DEFAULT_REGION_FACTORY_BEAN_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanDefinitionBuilder setRegionAttributes(GemfirePersistentEntity persistentEntity,
|
||||||
|
BeanDefinitionBuilder regionFactoryBeanBuilder, boolean strict) {
|
||||||
|
|
||||||
|
Annotation regionAnnotation = persistentEntity.getRegionAnnotation();
|
||||||
|
|
||||||
|
if (regionAnnotation != null) {
|
||||||
|
AnnotationAttributes regionAnnotationAttributes =
|
||||||
|
AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(regionAnnotation));
|
||||||
|
|
||||||
|
if (strict) {
|
||||||
|
regionFactoryBeanBuilder.addPropertyValue("keyConstraint", resolveIdType(persistentEntity));
|
||||||
|
regionFactoryBeanBuilder.addPropertyValue("valueConstraint", resolveDomainType(persistentEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("diskStoreName")) {
|
||||||
|
String diskStoreName = regionAnnotationAttributes.getString("diskStoreName");
|
||||||
|
|
||||||
|
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName", diskStoreName, "");
|
||||||
|
|
||||||
|
if (StringUtils.hasText(diskStoreName)) {
|
||||||
|
regionFactoryBeanBuilder.addDependsOn(diskStoreName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("persistent")) {
|
||||||
|
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "persistent",
|
||||||
|
regionAnnotationAttributes.getBoolean("persistent"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder =
|
||||||
|
resolveRegionAttributesFactoryBeanBuilder(regionAnnotation, regionFactoryBeanBuilder);
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("diskSynchronous")) {
|
||||||
|
setPropertyValueIfNotDefault(regionAttributesFactoryBeanBuilder, "diskSynchronous",
|
||||||
|
regionAnnotationAttributes.getBoolean("diskSynchronous"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("ignoreJta")) {
|
||||||
|
setPropertyValueIfNotDefault(regionAttributesFactoryBeanBuilder, "ignoreJTA",
|
||||||
|
regionAnnotationAttributes.getBoolean("ignoreJta"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setClientRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder);
|
||||||
|
|
||||||
|
setPartitionRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder,
|
||||||
|
regionAttributesFactoryBeanBuilder);
|
||||||
|
|
||||||
|
setReplicateRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionFactoryBeanBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected Class<?> resolveDomainType(GemfirePersistentEntity persistentEntity) {
|
||||||
|
return defaultIfNull(persistentEntity.getType(), Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected Class<?> resolveIdType(GemfirePersistentEntity persistentEntity) {
|
||||||
|
return (persistentEntity.hasIdProperty() ?
|
||||||
|
defaultIfNull(persistentEntity.getIdProperty().getActualType(), Object.class) : Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanDefinitionBuilder resolveRegionAttributesFactoryBeanBuilder(Annotation regionAnnotation,
|
||||||
|
BeanDefinitionBuilder regionFactoryBeanBuilder) {
|
||||||
|
|
||||||
|
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder = regionFactoryBeanBuilder;
|
||||||
|
|
||||||
|
if (!ClientRegion.class.isAssignableFrom(regionAnnotation.annotationType())) {
|
||||||
|
regionAttributesFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||||
|
RegionAttributesFactoryBean.class);
|
||||||
|
|
||||||
|
regionFactoryBeanBuilder.addPropertyValue("attributes",
|
||||||
|
regionAttributesFactoryBeanBuilder.getBeanDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionAttributesFactoryBeanBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanDefinitionBuilder setClientRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
|
||||||
|
BeanDefinitionBuilder regionFactoryBeanBuilder) {
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("poolName")) {
|
||||||
|
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName",
|
||||||
|
regionAnnotationAttributes.getString("poolName"), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("shortcut")) {
|
||||||
|
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "shortcut",
|
||||||
|
regionAnnotationAttributes.getEnum("shortcut"), ClientRegionShortcut.PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionFactoryBeanBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanDefinitionBuilder setPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
|
||||||
|
BeanDefinitionBuilder regionFactoryBeanBuilder, BeanDefinitionBuilder regionAttributesFactoryBeanBuilder) {
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("redundantCopies")) {
|
||||||
|
BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder =
|
||||||
|
BeanDefinitionBuilder.genericBeanDefinition(PartitionAttributesFactoryBean.class);
|
||||||
|
|
||||||
|
String collocatedWith = regionAnnotationAttributes.getString("collocatedWith");
|
||||||
|
|
||||||
|
setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "colocatedWith", collocatedWith, "");
|
||||||
|
|
||||||
|
if (StringUtils.hasText(collocatedWith)) {
|
||||||
|
regionFactoryBeanBuilder.addDependsOn(collocatedWith);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPropertyReferenceIfSet(partitionAttributesFactoryBeanBuilder, "partitionResolver",
|
||||||
|
regionAnnotationAttributes.getString("partitionResolverName"));
|
||||||
|
|
||||||
|
setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "redundantCopies",
|
||||||
|
regionAnnotationAttributes.<Integer>getNumber("redundantCopies"), 0);
|
||||||
|
|
||||||
|
setFixedPartitionRegionAttributes(regionAnnotationAttributes, partitionAttributesFactoryBeanBuilder);
|
||||||
|
|
||||||
|
regionAttributesFactoryBeanBuilder.addPropertyValue("partitionAttributes",
|
||||||
|
partitionAttributesFactoryBeanBuilder.getBeanDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionAttributesFactoryBeanBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanDefinitionBuilder setFixedPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
|
||||||
|
BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder) {
|
||||||
|
|
||||||
|
PartitionRegion.FixedPartition[] fixedPartitions = ArrayUtils.nullSafeArray(
|
||||||
|
regionAnnotationAttributes.getAnnotationArray("fixedPartitions", PartitionRegion.FixedPartition.class),
|
||||||
|
PartitionRegion.FixedPartition.class);
|
||||||
|
|
||||||
|
if (!ObjectUtils.isEmpty(fixedPartitions)) {
|
||||||
|
ManagedList<BeanDefinition> fixedPartitionAttributesFactoryBeans =
|
||||||
|
new ManagedList<BeanDefinition>(fixedPartitions.length);
|
||||||
|
|
||||||
|
for (PartitionRegion.FixedPartition fixedPartition : fixedPartitions) {
|
||||||
|
BeanDefinitionBuilder fixedPartitionAttributesFactoryBeanBuilder =
|
||||||
|
BeanDefinitionBuilder.genericBeanDefinition(FixedPartitionAttributesFactoryBean.class);
|
||||||
|
|
||||||
|
fixedPartitionAttributesFactoryBeanBuilder.addPropertyValue("partitionName", fixedPartition.name());
|
||||||
|
|
||||||
|
setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "primary",
|
||||||
|
fixedPartition.primary(), false);
|
||||||
|
|
||||||
|
setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "numBuckets",
|
||||||
|
fixedPartition.numBuckets(), 1);
|
||||||
|
|
||||||
|
fixedPartitionAttributesFactoryBeans.add(
|
||||||
|
fixedPartitionAttributesFactoryBeanBuilder.getBeanDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
|
partitionAttributesFactoryBeanBuilder.addPropertyValue("fixedPartitionAttributes",
|
||||||
|
fixedPartitionAttributesFactoryBeans);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partitionAttributesFactoryBeanBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected BeanDefinitionBuilder setReplicateRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
|
||||||
|
BeanDefinitionBuilder regionFactoryBeanBuilder) {
|
||||||
|
|
||||||
|
if (regionAnnotationAttributes.containsKey("scope")) {
|
||||||
|
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "scope",
|
||||||
|
regionAnnotationAttributes.<ScopeType>getEnum("scope").getScope(), ScopeType.DISTRIBUTED_NO_ACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionFactoryBeanBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
private <T> BeanDefinitionBuilder setPropertyReferenceIfSet(BeanDefinitionBuilder beanDefinitionBuilder,
|
||||||
|
String propertyName, String beanName) {
|
||||||
|
|
||||||
|
return (StringUtils.hasText(beanName) ? beanDefinitionBuilder.addPropertyReference(propertyName, beanName)
|
||||||
|
: beanDefinitionBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
private <T> BeanDefinitionBuilder setPropertyValueIfNotDefault(BeanDefinitionBuilder beanDefinitionBuilder,
|
||||||
|
String propertyName, T value, T defaultValue) {
|
||||||
|
|
||||||
|
return (value != null && !value.equals(defaultValue) ?
|
||||||
|
beanDefinitionBuilder.addPropertyValue(propertyName, value) : beanDefinitionBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs addition post processing on the {@link GemfirePersistentEntity} to offer additional feature support
|
||||||
|
* (e.g. dynamic Index creation).
|
||||||
|
*
|
||||||
|
* @param persistentEntity {@link GemfirePersistentEntity} to process.
|
||||||
|
* @return the given {@link GemfirePersistentEntity}.
|
||||||
|
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
|
||||||
|
*/
|
||||||
|
protected GemfirePersistentEntity<?> postProcess(GemfirePersistentEntity<?> persistentEntity) {
|
||||||
|
return persistentEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.support;
|
||||||
|
|
||||||
|
import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
|
||||||
|
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.DataPolicy;
|
||||||
|
import org.apache.geode.cache.GemFireCache;
|
||||||
|
import org.apache.geode.cache.Region;
|
||||||
|
import org.apache.geode.cache.RegionAttributes;
|
||||||
|
import org.apache.geode.cache.RegionShortcut;
|
||||||
|
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.data.gemfire.GemfireUtils;
|
||||||
|
import org.springframework.data.gemfire.GenericRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.RegionLookupFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||||
|
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link GemFireCacheTypeAwareRegionFactoryBean} class is a smart Spring {@link FactoryBean} that knows how to
|
||||||
|
* create a client or server {@link Region} depending on whether the {@link GemFireCache} is
|
||||||
|
* a {@link org.apache.geode.cache.client.ClientCache} or a peer {@link org.apache.geode.cache.Cache}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.beans.factory.BeanFactory
|
||||||
|
* @see org.springframework.beans.factory.BeanFactoryAware
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean
|
||||||
|
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
|
||||||
|
* @see org.apache.geode.cache.GemFireCache
|
||||||
|
* @see org.apache.geode.cache.Region
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||||
|
implements BeanFactoryAware {
|
||||||
|
|
||||||
|
private GemFireCache gemfireCache;
|
||||||
|
|
||||||
|
private BeanFactory beanFactory;
|
||||||
|
|
||||||
|
private Boolean close = false;
|
||||||
|
|
||||||
|
private Class<K> keyConstraint;
|
||||||
|
private Class<V> valueConstraint;
|
||||||
|
|
||||||
|
private ClientRegionShortcut clientRegionShortcut = ClientRegionShortcut.PROXY;
|
||||||
|
|
||||||
|
private DataPolicy dataPolicy = DataPolicy.DEFAULT;
|
||||||
|
|
||||||
|
private RegionAttributes<K, V> regionAttributes;
|
||||||
|
|
||||||
|
private RegionShortcut serverRegionShortcut;
|
||||||
|
|
||||||
|
private String poolName;
|
||||||
|
private String regionName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Region<K, V> lookupRegion(GemFireCache gemfireCache, String regionName) throws Exception {
|
||||||
|
return (GemfireUtils.isClient(gemfireCache) ? newClientRegion(gemfireCache, regionName)
|
||||||
|
: newServerRegion(gemfireCache, regionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new client {@link Region} using the {@link ClientRegionFactoryBean}.
|
||||||
|
*
|
||||||
|
* @param gemfireCache reference to the {@link GemFireCache} used to create/initialize the factory
|
||||||
|
* used to create the client {@link Region}.
|
||||||
|
* @param regionName name given to the client {@link Region}.
|
||||||
|
* @return a new instance of a client {@link Region} with the given {@code regionName}.
|
||||||
|
* @throws Exception if the client {@link Region} could not be created.
|
||||||
|
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||||
|
* @see org.apache.geode.cache.GemFireCache
|
||||||
|
* @see org.apache.geode.cache.Region
|
||||||
|
*/
|
||||||
|
protected Region<K, V> newClientRegion(GemFireCache gemfireCache, String regionName) throws Exception {
|
||||||
|
ClientRegionFactoryBean<K, V> clientRegion = new ClientRegionFactoryBean<K, V>();
|
||||||
|
|
||||||
|
clientRegion.setAttributes(getRegionAttributes());
|
||||||
|
clientRegion.setBeanFactory(getBeanFactory());
|
||||||
|
clientRegion.setCache(gemfireCache);
|
||||||
|
clientRegion.setClose(isClose());
|
||||||
|
clientRegion.setKeyConstraint(getKeyConstraint());
|
||||||
|
clientRegion.setPoolName(getPoolName());
|
||||||
|
clientRegion.setRegionName(regionName);
|
||||||
|
clientRegion.setShortcut(getClientRegionShortcut());
|
||||||
|
clientRegion.setValueConstraint(getValueConstraint());
|
||||||
|
clientRegion.afterPropertiesSet();
|
||||||
|
|
||||||
|
return clientRegion.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new server {@link Region} using the {@link GenericRegionFactoryBean}.
|
||||||
|
*
|
||||||
|
* @param gemfireCache reference to the {@link GemFireCache} used to create/initialize the factory
|
||||||
|
* used to create the server {@link Region}.
|
||||||
|
* @param regionName name given to the server {@link Region}.
|
||||||
|
* @return a new instance of a server {@link Region} with the given {@code regionName}.
|
||||||
|
* @throws Exception if the server {@link Region} could not be created.
|
||||||
|
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
|
||||||
|
* @see org.apache.geode.cache.GemFireCache
|
||||||
|
* @see org.apache.geode.cache.Region
|
||||||
|
*/
|
||||||
|
protected Region<K, V> newServerRegion(GemFireCache gemfireCache, String regionName) throws Exception {
|
||||||
|
GenericRegionFactoryBean<K, V> serverRegion = new GenericRegionFactoryBean<K, V>();
|
||||||
|
|
||||||
|
serverRegion.setAttributes(getRegionAttributes());
|
||||||
|
serverRegion.setCache(gemfireCache);
|
||||||
|
serverRegion.setClose(isClose());
|
||||||
|
serverRegion.setDataPolicy(getDataPolicy());
|
||||||
|
serverRegion.setKeyConstraint(getKeyConstraint());
|
||||||
|
serverRegion.setRegionName(regionName);
|
||||||
|
serverRegion.setShortcut(getServerRegionShortcut());
|
||||||
|
serverRegion.setValueConstraint(getValueConstraint());
|
||||||
|
serverRegion.afterPropertiesSet();
|
||||||
|
|
||||||
|
return serverRegion.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttributes(RegionAttributes<K, V> regionAttributes) {
|
||||||
|
this.regionAttributes = regionAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RegionAttributes<K, V> getRegionAttributes() {
|
||||||
|
return this.regionAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BeanFactory getBeanFactory() {
|
||||||
|
Assert.state(this.beanFactory != null, "BeanFactory was not properly initialized");
|
||||||
|
return this.beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientRegionShortcut(ClientRegionShortcut clientRegionShortcut) {
|
||||||
|
this.clientRegionShortcut = clientRegionShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ClientRegionShortcut getClientRegionShortcut() {
|
||||||
|
return defaultIfNull(this.clientRegionShortcut, ClientRegionShortcut.PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClose(Boolean close) {
|
||||||
|
this.close = close;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Boolean getClose() {
|
||||||
|
return this.close;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isClose() {
|
||||||
|
return Boolean.TRUE.equals(getClose());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataPolicy(DataPolicy dataPolicy) {
|
||||||
|
this.dataPolicy = dataPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DataPolicy getDataPolicy() {
|
||||||
|
return defaultIfNull(this.dataPolicy, DataPolicy.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyConstraint(Class<K> keyConstraint) {
|
||||||
|
this.keyConstraint = keyConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<K> getKeyConstraint() {
|
||||||
|
return this.keyConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoolName(String poolName) {
|
||||||
|
this.poolName = poolName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getPoolName() {
|
||||||
|
return defaultIfEmpty(this.poolName, GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerRegionShortcut(RegionShortcut shortcut) {
|
||||||
|
this.serverRegionShortcut = shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RegionShortcut getServerRegionShortcut() {
|
||||||
|
return this.serverRegionShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueConstraint(Class<V> valueConstraint) {
|
||||||
|
this.valueConstraint = valueConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<V> getValueConstraint() {
|
||||||
|
return this.valueConstraint;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.support;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
|
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||||
|
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link GemFireComponentClassTypeScanner} class is a classpath component scanner used to search
|
||||||
|
* for GemFire components based on {@link Class} type.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see java.lang.Iterable
|
||||||
|
* @see org.springframework.context.ConfigurableApplicationContext
|
||||||
|
* @see org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
|
||||||
|
* @see org.springframework.core.env.Environment
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class GemFireComponentClassTypeScanner implements Iterable<String> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to construct an instance of the {@link GemFireComponentClassTypeScanner} initialized with
|
||||||
|
* the given array of base packages to scan.
|
||||||
|
*
|
||||||
|
* @param basePackages array of base packages to scan for GemFire components.
|
||||||
|
* @throws IllegalArgumentException if the array of base packages is {@literal null} or empty.
|
||||||
|
* @return an initialized instance of {@link GemFireComponentClassTypeScanner}.
|
||||||
|
* @see #GemFireComponentClassTypeScanner(Set)
|
||||||
|
*/
|
||||||
|
public static GemFireComponentClassTypeScanner from(String... basePackages) {
|
||||||
|
return new GemFireComponentClassTypeScanner(CollectionUtils.asSet(
|
||||||
|
ArrayUtils.nullSafeArray(basePackages, String.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to construct an instance of the {@link GemFireComponentClassTypeScanner} initialized with
|
||||||
|
* the given {@link Iterable} of base packages to scan.
|
||||||
|
*
|
||||||
|
* @param basePackages {@link Iterable} of base packages to scan for GemFire components.
|
||||||
|
* @throws IllegalArgumentException if the {@link Iterable} of base packages is {@literal null} or empty.
|
||||||
|
* @return an initialized instance of {@link GemFireComponentClassTypeScanner}.
|
||||||
|
* @see #GemFireComponentClassTypeScanner(Set)
|
||||||
|
*/
|
||||||
|
public static GemFireComponentClassTypeScanner from(Iterable<String> basePackages) {
|
||||||
|
Set<String> basePackageSet = new HashSet<String>();
|
||||||
|
|
||||||
|
for (String basePackage : CollectionUtils.nullSafeIterable(basePackages)) {
|
||||||
|
basePackageSet.add(basePackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GemFireComponentClassTypeScanner(basePackageSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassLoader entityClassLoader;
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
|
private Set<TypeFilter> excludes = new HashSet<TypeFilter>();
|
||||||
|
private Set<TypeFilter> includes = new HashSet<TypeFilter>();
|
||||||
|
|
||||||
|
protected final Log log = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
private final Set<String> basePackages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of the {@link GemFireComponentClassTypeScanner} initialized with
|
||||||
|
* the given {@link Set} of base packages to scan.
|
||||||
|
*
|
||||||
|
* @param basePackages {@link Set} of base packages to scan for GemFire component clases.
|
||||||
|
* @throws IllegalArgumentException if the {@link Set} is {@literal null} or empty.
|
||||||
|
* @see java.util.Set
|
||||||
|
*/
|
||||||
|
protected GemFireComponentClassTypeScanner(Set<String> basePackages) {
|
||||||
|
Assert.notEmpty(basePackages, "Base packages must be specified");
|
||||||
|
this.basePackages = basePackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the Spring {@link org.springframework.context.ApplicationContext}.
|
||||||
|
*
|
||||||
|
* @return a reference to the Spring {@link org.springframework.context.ApplicationContext}.
|
||||||
|
* @see org.springframework.context.ConfigurableApplicationContext
|
||||||
|
*/
|
||||||
|
protected ConfigurableApplicationContext getApplicationContext() {
|
||||||
|
return this.applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable {@link Set} of base packages to scan for GemFire components.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable {@link Set} of base packages to scan for GemFire components.
|
||||||
|
*/
|
||||||
|
protected Set<String> getBasePackages() {
|
||||||
|
return Collections.unmodifiableSet(this.basePackages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the {@link ClassLoader} to find and load GemFire application persistent entity classes.
|
||||||
|
*
|
||||||
|
* @return a {@link ClassLoader} to find and load GemFire application persistent entity classes.
|
||||||
|
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
|
||||||
|
* @see java.lang.Thread#getContextClassLoader()
|
||||||
|
* @see java.lang.ClassLoader
|
||||||
|
* @see #getApplicationContext()
|
||||||
|
*/
|
||||||
|
protected ClassLoader getEntityClassLoader() {
|
||||||
|
ConfigurableApplicationContext applicationContext = getApplicationContext();
|
||||||
|
|
||||||
|
return (this.entityClassLoader != null ? this.entityClassLoader
|
||||||
|
: (applicationContext != null ? applicationContext.getBeanFactory().getBeanClassLoader()
|
||||||
|
: Thread.currentThread().getContextClassLoader()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the Spring {@link Environment} in which the Spring GemFire application is running.
|
||||||
|
*
|
||||||
|
* @return a reference to the Spring {@link Environment}.
|
||||||
|
* @see org.springframework.context.ApplicationContext#getEnvironment()
|
||||||
|
* @see org.springframework.core.env.Environment
|
||||||
|
* @see org.springframework.core.env.StandardEnvironment
|
||||||
|
* @see #getApplicationContext()
|
||||||
|
*/
|
||||||
|
protected Environment getEnvironment() {
|
||||||
|
ConfigurableApplicationContext applicationContext = getApplicationContext();
|
||||||
|
return (applicationContext != null ? applicationContext.getEnvironment() : new StandardEnvironment());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of {@link TypeFilter TypeFilters} used to exclude types found
|
||||||
|
* during the classpath component scan.
|
||||||
|
*
|
||||||
|
* @return a collection of {@link TypeFilter} objects
|
||||||
|
* @see org.springframework.core.type.filter.TypeFilter
|
||||||
|
*/
|
||||||
|
protected Iterable<TypeFilter> getExcludes() {
|
||||||
|
return this.excludes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of {@link TypeFilter TypeFilters} used to include (match) types found
|
||||||
|
* during the classpath component scan.
|
||||||
|
*
|
||||||
|
* @return a collection of {@link TypeFilter} objects
|
||||||
|
* @see org.springframework.core.type.filter.TypeFilter
|
||||||
|
*/
|
||||||
|
protected Iterable<TypeFilter> getIncludes() {
|
||||||
|
return this.includes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterator<String> iterator() {
|
||||||
|
return getBasePackages().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the {@link Set} of base packages searching for GemFire application components accepted by the filters
|
||||||
|
* of this scanner.
|
||||||
|
*
|
||||||
|
* @return a {@link Set} of GemFire application component {@link Class} types.
|
||||||
|
* @see #newClassPathScanningCandidateComponentProvider(boolean)
|
||||||
|
* @see java.util.Set
|
||||||
|
*/
|
||||||
|
public Set<Class<?>> scan() {
|
||||||
|
Set<Class<?>> componentClasses = new HashSet<Class<?>>();
|
||||||
|
|
||||||
|
ClassLoader entityClassLoader = getEntityClassLoader();
|
||||||
|
|
||||||
|
ClassPathScanningCandidateComponentProvider componentProvider =
|
||||||
|
newClassPathScanningCandidateComponentProvider();
|
||||||
|
|
||||||
|
for (String packageName : this) {
|
||||||
|
for (BeanDefinition beanDefinition : componentProvider.findCandidateComponents(packageName)) {
|
||||||
|
try {
|
||||||
|
componentClasses.add(ClassUtils.forName(beanDefinition.getBeanClassName(), entityClassLoader));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ignore) {
|
||||||
|
log.warn(String.format("Class not found for component type [%s]",
|
||||||
|
beanDefinition.getBeanClassName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of the {@link ClassPathScanningCandidateComponentProvider} initialized with
|
||||||
|
* no default filters.
|
||||||
|
*
|
||||||
|
* @return a new instance of the {@link ClassPathScanningCandidateComponentProvider}.
|
||||||
|
* @see org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
|
||||||
|
* @see #newClassPathScanningCandidateComponentProvider(boolean)
|
||||||
|
*/
|
||||||
|
protected ClassPathScanningCandidateComponentProvider newClassPathScanningCandidateComponentProvider() {
|
||||||
|
return newClassPathScanningCandidateComponentProvider(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of the {@link ClassPathScanningCandidateComponentProvider} initialized with
|
||||||
|
* the {@code useDefaultFilters} boolean value to indicate whether to use default values or not. Additionally,
|
||||||
|
* the exclude/include filters are also set.
|
||||||
|
*
|
||||||
|
* @param useDefaultFilters boolean value to indicate whether to use default filters.
|
||||||
|
* @return a new instance of the {@link ClassPathScanningCandidateComponentProvider}.
|
||||||
|
* @see org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
|
||||||
|
* @see #newClassPathScanningCandidateComponentProvider(boolean)
|
||||||
|
*/
|
||||||
|
protected ClassPathScanningCandidateComponentProvider newClassPathScanningCandidateComponentProvider(
|
||||||
|
boolean useDefaultFilters) {
|
||||||
|
|
||||||
|
ClassPathScanningCandidateComponentProvider componentProvider =
|
||||||
|
new ClassPathScanningCandidateComponentProvider(useDefaultFilters, getEnvironment());
|
||||||
|
|
||||||
|
for (TypeFilter exclude : excludes) {
|
||||||
|
componentProvider.addExcludeFilter(exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypeFilter include : includes) {
|
||||||
|
componentProvider.addIncludeFilter(include);
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
public GemFireComponentClassTypeScanner with(ClassLoader entityClassLoader) {
|
||||||
|
this.entityClassLoader = entityClassLoader;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
public GemFireComponentClassTypeScanner with(ConfigurableApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
public GemFireComponentClassTypeScanner withExcludes(TypeFilter... excludes) {
|
||||||
|
return withExcludes(CollectionUtils.asSet(ArrayUtils.nullSafeArray(excludes, TypeFilter.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
public GemFireComponentClassTypeScanner withExcludes(Iterable<TypeFilter> excludes) {
|
||||||
|
for (TypeFilter exclude : CollectionUtils.nullSafeIterable(excludes)) {
|
||||||
|
this.excludes.add(exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
public GemFireComponentClassTypeScanner withIncludes(TypeFilter... includes) {
|
||||||
|
return withIncludes(CollectionUtils.asSet(ArrayUtils.nullSafeArray(includes, TypeFilter.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
public GemFireComponentClassTypeScanner withIncludes(Iterable<TypeFilter> includes) {
|
||||||
|
for (TypeFilter include : CollectionUtils.nullSafeIterable(includes)) {
|
||||||
|
this.includes.add(include);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.Annotation;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||||
|
import org.apache.geode.cache.client.Pool;
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Annotation} defining the Client {@link org.apache.geode.cache.Region} in which the application
|
||||||
|
* persistent entity will be stored.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Region
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public @interface ClientRegion {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "name")
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "value")
|
||||||
|
String value() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the {@link org.apache.geode.cache.DiskStore} in which this persistent entity's data is overflowed
|
||||||
|
* and/or persisted.
|
||||||
|
*
|
||||||
|
* Maybe the name of a Spring bean defined in the Spring context.
|
||||||
|
*
|
||||||
|
* Defaults to unset.
|
||||||
|
*/
|
||||||
|
String diskStoreName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal synchronous}.
|
||||||
|
*/
|
||||||
|
boolean diskSynchronous() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the GemFire/Geode {@link Pool} used by this persistent entity's {@link org.apache.geode.cache.Region}
|
||||||
|
* data access operations sent to the corresponding {@link org.apache.geode.cache.Region}
|
||||||
|
* on the GemFire/Geode Server.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal gemfirePool}.
|
||||||
|
*/
|
||||||
|
String poolName() default GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ClientRegionShortcut} used by this persistent entity's client {@link org.apache.geode.cache.Region}
|
||||||
|
* to define the {@link org.apache.geode.cache.DataPolicy}.
|
||||||
|
*
|
||||||
|
* Defaults to {@link ClientRegionShortcut#PROXY}.
|
||||||
|
*
|
||||||
|
* @see org.apache.geode.cache.client.ClientRegionShortcut
|
||||||
|
*/
|
||||||
|
ClientRegionShortcut shortcut() default ClientRegionShortcut.PROXY;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,42 +16,109 @@
|
|||||||
|
|
||||||
package org.springframework.data.gemfire.mapping;
|
package org.springframework.data.gemfire.mapping;
|
||||||
|
|
||||||
|
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
import org.springframework.data.mapping.PersistentEntity;
|
||||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||||
import org.springframework.data.util.TypeInformation;
|
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
|
* {@link PersistentEntity} implementation adding custom GemFire persistent entity related metadata, such as the
|
||||||
* mapped to etc.
|
* {@link org.apache.geode.cache.Region} to which the entity is mapped, etc.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author John Blum
|
* @author John Blum
|
||||||
|
* @see org.springframework.data.gemfire.mapping.GemfirePersistentProperty
|
||||||
|
* @see org.springframework.data.mapping.model.BasicPersistentEntity
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, GemfirePersistentProperty> {
|
public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, GemfirePersistentProperty> {
|
||||||
|
|
||||||
|
private final Annotation regionAnnotation;
|
||||||
|
|
||||||
private final String regionName;
|
private final String regionName;
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static Annotation resolveRegionAnnotation(Class<?> persistentEntityType) {
|
||||||
|
|
||||||
|
for (Class<? extends Annotation> regionAnnotationType : Region.REGION_ANNOTATION_TYPES) {
|
||||||
|
Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation(
|
||||||
|
persistentEntityType, regionAnnotationType);
|
||||||
|
|
||||||
|
if (regionAnnotation != null) {
|
||||||
|
return regionAnnotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static String resolveRegionName(Class<?> persistentEntityType, Annotation regionAnnotation) {
|
||||||
|
|
||||||
|
String regionName = (regionAnnotation != null ? AnnotationAttributes.fromMap(
|
||||||
|
AnnotationUtils.getAnnotationAttributes(regionAnnotation)).getString("value") : null);
|
||||||
|
|
||||||
|
return defaultIfEmpty(regionName, persistentEntityType.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
|
* Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
|
||||||
*
|
*
|
||||||
* @param information must not be {@literal null}.
|
* @param information must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public GemfirePersistentEntity(TypeInformation<T> information) {
|
public GemfirePersistentEntity(TypeInformation<T> information) {
|
||||||
|
|
||||||
super(information);
|
super(information);
|
||||||
|
|
||||||
Class<T> rawType = information.getType();
|
Class<T> rawType = information.getType();
|
||||||
Region region = rawType.getAnnotation(Region.class);
|
|
||||||
String defaultRegionName = rawType.getSimpleName();
|
|
||||||
|
|
||||||
this.regionName = (region != null && StringUtils.hasText(region.value()) ? region.value() : defaultRegionName);
|
this.regionAnnotation = resolveRegionAnnotation(rawType);
|
||||||
|
this.regionName = resolveRegionName(rawType, this.regionAnnotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the region the entity shall be stored in.
|
* Returns the {@link Region} annotation used to annotate this {@link PersistentEntity} or {@literal null}
|
||||||
|
* if this {@link PersistentEntity} was not annotated with a {@link Region} annotation.
|
||||||
*
|
*
|
||||||
* @return the name of the region the entity shall be stored in.
|
* @param <T> concrete {@link Class} type of the Region {@link Annotation}.
|
||||||
|
* @return the {@link Region} annotation used to annotate this {@link PersistentEntity} or {@literal null}
|
||||||
|
* if this {@link PersistentEntity} was not annotated with a {@link Region} annotation.
|
||||||
|
* @see org.springframework.data.gemfire.mapping.ClientRegion
|
||||||
|
* @see org.springframework.data.gemfire.mapping.LocalRegion
|
||||||
|
* @see org.springframework.data.gemfire.mapping.PartitionRegion
|
||||||
|
* @see org.springframework.data.gemfire.mapping.ReplicateRegion
|
||||||
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
|
* @see java.lang.annotation.Annotation
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends Annotation> T getRegionAnnotation() {
|
||||||
|
return (T) this.regionAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link Class} type of the Region {@link Annotation} or {@literal null}
|
||||||
|
* if this {@link PersistentEntity} was not annotated with a Region {@link Annotation}.
|
||||||
|
*
|
||||||
|
* @return the {@link Class} type of the Region {@link Annotation} or {@literal null}
|
||||||
|
* if this {@link PersistentEntity} was not annotated with a Region {@link Annotation}.
|
||||||
|
* @see java.lang.annotation.Annotation#annotationType()
|
||||||
|
* @see #getRegionAnnotation()
|
||||||
|
*/
|
||||||
|
public Class<? extends Annotation> getRegionAnnotationType() {
|
||||||
|
Annotation regionAnnotation = getRegionAnnotation();
|
||||||
|
return (regionAnnotation != null ? regionAnnotation.annotationType() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the {@link Region} in which this {@link PersistentEntity} will be stored.
|
||||||
|
*
|
||||||
|
* @return the name of the {@link Region} in which this {@link PersistentEntity} will be stored.
|
||||||
|
* @see org.apache.geode.cache.Region#getName()
|
||||||
*/
|
*/
|
||||||
public String getRegionName() {
|
public String getRegionName() {
|
||||||
return this.regionName;
|
return this.regionName;
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.Annotation;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Annotation} defining the Local {@link Region} in which the application persistent entity will be stored.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Region
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public @interface LocalRegion {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "name")
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "value")
|
||||||
|
String value() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the {@link org.apache.geode.cache.DiskStore} in which this persistent entity's data is overflowed
|
||||||
|
* and/or persisted.
|
||||||
|
*
|
||||||
|
* Maybe the name of a Spring bean defined in the Spring context.
|
||||||
|
*
|
||||||
|
* Defaults to unset.
|
||||||
|
*/
|
||||||
|
String diskStoreName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal synchronous}.
|
||||||
|
*/
|
||||||
|
boolean diskSynchronous() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this {@link org.apache.geode.cache.Region Region's} data access operations participates in
|
||||||
|
* any existing, Global JTA transaction in progress.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false} (will NOT ignore JTA).
|
||||||
|
*/
|
||||||
|
boolean ignoreJta() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this persistent entity's {@link org.apache.geode.cache.Region} is persistent,
|
||||||
|
* storing data to disk.
|
||||||
|
*
|
||||||
|
* Note, this setting independent of whether or not the {@link org.apache.geode.cache.Region} associated
|
||||||
|
* with this persistent entity overflows data to disk during eviction due to entry/heap/memory constraints.
|
||||||
|
*
|
||||||
|
* A {@link org.apache.geode.cache.Region} can also be persistent without an explicit
|
||||||
|
* {@link org.apache.geode.cache.DiskStore} defined; in that case, GemFire/Geode writes to the "DEFAULT"
|
||||||
|
* {@link org.apache.geode.cache.DiskStore}.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false}.
|
||||||
|
*
|
||||||
|
* @see org.apache.geode.cache.DataPolicy
|
||||||
|
*/
|
||||||
|
boolean persistent() default false;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.Annotation;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Annotation} defining the Partition {@link Region} in which the application persistent entity will be stored.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Region
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public @interface PartitionRegion {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "name")
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "value")
|
||||||
|
String value() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the {@link org.apache.geode.cache.Region} to which this persistent entity's
|
||||||
|
* {@link org.apache.geode.cache.Region} will be collocated.
|
||||||
|
*
|
||||||
|
* Collocation is used in data access, querying operations where the user wishes to combine data
|
||||||
|
* from multiple {@link org.apache.geode.cache.Region Regions} into a single result set returned
|
||||||
|
* from an OQL statement.
|
||||||
|
*
|
||||||
|
* Defaults to unset.
|
||||||
|
*/
|
||||||
|
String collocatedWith() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the {@link org.apache.geode.cache.DiskStore} in which this persistent entity's data is overflowed
|
||||||
|
* and/or persisted.
|
||||||
|
*
|
||||||
|
* Maybe the name of a Spring bean defined in the Spring context.
|
||||||
|
*
|
||||||
|
* Defaults to unset.
|
||||||
|
*/
|
||||||
|
String diskStoreName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal synchronous}.
|
||||||
|
*/
|
||||||
|
boolean diskSynchronous() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines an array of fixed partitions in a {@link org.apache.geode.cache.DataPolicy#PARTITION}
|
||||||
|
* {@link org.apache.geode.cache.Region}
|
||||||
|
*
|
||||||
|
* Default is unset.
|
||||||
|
*
|
||||||
|
* @see org.apache.geode.cache.FixedPartitionAttributes
|
||||||
|
*/
|
||||||
|
FixedPartition[] fixedPartitions() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this {@link org.apache.geode.cache.Region Region's} data access operations participates in
|
||||||
|
* any existing, Global JTA transaction in progress.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false} (will NOT ignore JTA).
|
||||||
|
*/
|
||||||
|
boolean ignoreJta() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the {@link org.apache.geode.cache.PartitionResolver} used to customize the partitioning strategy
|
||||||
|
* in this persistent entity's {@link org.apache.geode.cache.DataPolicy#PARTITION}
|
||||||
|
* {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* This setting may also be the name of a Spring bean defined in the Spring context.
|
||||||
|
*
|
||||||
|
* Defaults to unset, thus using the default GemFire/Geode partitioning strategy.
|
||||||
|
*/
|
||||||
|
String partitionResolverName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this persistent entity's {@link org.apache.geode.cache.Region} is persistent,
|
||||||
|
* storing data to disk.
|
||||||
|
*
|
||||||
|
* Note, this setting independent of whether or not the {@link org.apache.geode.cache.Region} associated
|
||||||
|
* with this persistent entity overflows data to disk during eviction due to entry/heap/memory constraints.
|
||||||
|
*
|
||||||
|
* A {@link org.apache.geode.cache.Region} can also be persistent without an explicit
|
||||||
|
* {@link org.apache.geode.cache.DiskStore} defined; in that case, GemFire/Geode writes to the "DEFAULT"
|
||||||
|
* {@link org.apache.geode.cache.DiskStore}.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false}.
|
||||||
|
*
|
||||||
|
* @see org.apache.geode.cache.DataPolicy
|
||||||
|
*/
|
||||||
|
boolean persistent() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the number of redundant copies of this persistent entity's data.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal 0}.
|
||||||
|
*/
|
||||||
|
int redundantCopies() default 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link FixedPartition} defined fixed partition meta-data within
|
||||||
|
* a {@link org.apache.geode.cache.DataPolicy#PARTITION} {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @see org.apache.geode.cache.FixedPartitionAttributes
|
||||||
|
*/
|
||||||
|
@interface FixedPartition {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the fixed partition.
|
||||||
|
*/
|
||||||
|
String name();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether this partition is the primary partition in
|
||||||
|
* the {@link org.apache.geode.cache.DataPolicy#PARTITION} {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false}.
|
||||||
|
*/
|
||||||
|
boolean primary() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the number of bucket in this partition.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal 1}.
|
||||||
|
*/
|
||||||
|
int numBuckets() default 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,32 +13,61 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.data.gemfire.mapping;
|
package org.springframework.data.gemfire.mapping;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Inherited;
|
import java.lang.annotation.Inherited;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Annotation to define the region an entity will be stored in.
|
* {@link Annotation} defining the {@link Region} in which the application persistent entity will be stored.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.apache.geode.cache.Region
|
||||||
*/
|
*/
|
||||||
@Inherited
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
@Documented
|
@Documented
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public @interface Region {
|
public @interface Region {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Class<? extends Annotation>> REGION_ANNOTATION_TYPES = Arrays.asList(
|
||||||
|
ClientRegion.class, LocalRegion.class, PartitionRegion.class, ReplicateRegion.class, Region.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region} the entity
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
* shall be stored in (e.g. "Users", or "/Local/Admin/Users").
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
*
|
*
|
||||||
* @return the name or qualified path of the Region the entity shall be persisted in.
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
*/
|
*/
|
||||||
|
@AliasFor(attribute = "value")
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(attribute = "name")
|
||||||
String value() default "";
|
String value() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.Annotation;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
import org.springframework.data.gemfire.ScopeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Annotation} defining the Replicate {@link Region} in which the application persistent entity will be stored.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Region
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public @interface ReplicateRegion {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "name")
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name, or fully-qualified bean name of the {@link org.apache.geode.cache.Region}
|
||||||
|
* in which the application persistent entity will be stored (e.g. "Users", or "/Local/Admin/Users").
|
||||||
|
*
|
||||||
|
* Defaults to simple name of the application persistent entity defined by {@link java.lang.Class#getSimpleName()}.
|
||||||
|
*
|
||||||
|
* @return the name or fully-qualified path of the {@link Region} in which the application persistent entity
|
||||||
|
* will be stored.
|
||||||
|
*/
|
||||||
|
@AliasFor(annotation = Region.class, attribute = "value")
|
||||||
|
String value() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the {@link org.apache.geode.cache.DiskStore} in which this persistent entity's data is overflowed
|
||||||
|
* and/or persisted.
|
||||||
|
*
|
||||||
|
* Maybe the name of a Spring bean defined in the Spring context.
|
||||||
|
*
|
||||||
|
* Defaults to unset.
|
||||||
|
*/
|
||||||
|
String diskStoreName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal synchronous}.
|
||||||
|
*/
|
||||||
|
boolean diskSynchronous() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this {@link org.apache.geode.cache.Region Region's} data access operations participates in
|
||||||
|
* any existing, Global JTA transaction in progress.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false} (will NOT ignore JTA).
|
||||||
|
*/
|
||||||
|
boolean ignoreJta() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this persistent entity's {@link org.apache.geode.cache.Region} is persistent,
|
||||||
|
* storing data to disk.
|
||||||
|
*
|
||||||
|
* Note, this setting independent of whether or not the {@link org.apache.geode.cache.Region} associated
|
||||||
|
* with this persistent entity overflows data to disk during eviction due to entry/heap/memory constraints.
|
||||||
|
*
|
||||||
|
* A {@link org.apache.geode.cache.Region} can also be persistent without an explicit
|
||||||
|
* {@link org.apache.geode.cache.DiskStore} defined; in that case, GemFire/Geode writes to the "DEFAULT"
|
||||||
|
* {@link org.apache.geode.cache.DiskStore}.
|
||||||
|
*
|
||||||
|
* Defaults to {@literal false}.
|
||||||
|
*
|
||||||
|
* @see org.apache.geode.cache.DataPolicy
|
||||||
|
*/
|
||||||
|
boolean persistent() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the {@link org.apache.geode.cache.Scope} used by this persistent entity's
|
||||||
|
* {@link org.apache.geode.cache.DataPolicy#REPLICATE} {@link org.apache.geode.cache.Region} to
|
||||||
|
* acknowledge messages sent between peers.
|
||||||
|
*
|
||||||
|
* Defaults to {@link ScopeType#DISTRIBUTED_NO_ACK}
|
||||||
|
*/
|
||||||
|
ScopeType scope() default ScopeType.DISTRIBUTED_NO_ACK;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
||||||
return Collections.<Class<? extends Annotation>>singleton(Region.class);
|
return Region.REGION_ANNOTATION_TYPES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ package org.springframework.data.gemfire.util;
|
|||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ArrayUtils class is a utility class for working with Object arrays.
|
* The ArrayUtils class is a utility class for working with Object arrays.
|
||||||
*
|
*
|
||||||
@@ -37,6 +39,18 @@ public abstract class ArrayUtils {
|
|||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the given {@code array} if not {@literal null} or empty, otherwise returns the {@code defaultArray}.
|
||||||
|
*
|
||||||
|
* @param <T> {@link Class} type of the array elements.
|
||||||
|
* @param array array to evaluate.
|
||||||
|
* @param defaultArray array to return if the given {@code array} is {@literal null} or empty.
|
||||||
|
* @return the given {@code array} if not {@literal null} or empty otherwise return the {@code defaultArray}.
|
||||||
|
*/
|
||||||
|
public static <T> T[] defaultIfEmpty(T[] array, T[] defaultArray) {
|
||||||
|
return (!ObjectUtils.isEmpty(array) ? array : defaultArray);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Null-safe method to return the first element in the array or {@literal null}
|
* Null-safe method to return the first element in the array or {@literal null}
|
||||||
* if the array is {@literal null} or empty.
|
* if the array is {@literal null} or empty.
|
||||||
|
|||||||
@@ -46,6 +46,28 @@ import org.springframework.util.Assert;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public abstract class CollectionUtils extends org.springframework.util.CollectionUtils {
|
public abstract class CollectionUtils extends org.springframework.util.CollectionUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all elements from the given {@link Iterable} to the {@link Collection}.
|
||||||
|
*
|
||||||
|
* @param <E> {@link Class} type of the elements in the {@link Collection} and {@link Iterable}.
|
||||||
|
* @param <T> concrete {@link Class} type of the {@link Collection}.
|
||||||
|
* @param collection {@link Collection} in which to add the elements from the {@link Iterable}.
|
||||||
|
* @param iterable {@link Iterable} containing the elements to add to the {@link Collection}.
|
||||||
|
* @return the given {@link Collection}.
|
||||||
|
* @throws IllegalArgumentException if {@link Collection} is {@literal null}.
|
||||||
|
* @see java.lang.Iterable
|
||||||
|
* @see java.util.Collection
|
||||||
|
*/
|
||||||
|
public static <E, T extends Collection<E>> T addAll(T collection, Iterable<E> iterable) {
|
||||||
|
Assert.notNull(collection, "Collection must not be null");
|
||||||
|
|
||||||
|
for (E element : nullSafeIterable(iterable)) {
|
||||||
|
collection.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an unmodifiable {@link Set} containing the elements from the given object array.
|
* Returns an unmodifiable {@link Set} containing the elements from the given object array.
|
||||||
*
|
*
|
||||||
@@ -60,6 +82,32 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
|||||||
return Collections.unmodifiableSet(set);
|
return Collections.unmodifiableSet(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the given {@link Iterable} if not {@literal null} or empty, otherwise returns the {@code defaultIterable}.
|
||||||
|
*
|
||||||
|
* @param <T> concrete {@link Class} type of the {@link Iterable}.
|
||||||
|
* @param <E> {@link Class} type of the elements in the {@link Iterable Iterables}.
|
||||||
|
* @param iterable {@link Iterable} to evaluate.
|
||||||
|
* @param defaultIterable {@link Iterable} to return if the given {@code iterable} is {@literal null} or empty.
|
||||||
|
* @return {@code iterable} if not {@literal null} or empty otherwise return {@code defaultIterable}.
|
||||||
|
* @see java.lang.Iterable
|
||||||
|
*/
|
||||||
|
public static <E, T extends Iterable<E>> T defaultIfEmpty(T iterable, T defaultIterable) {
|
||||||
|
return (iterable != null && iterable.iterator().hasNext() ? iterable : defaultIterable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an empty {@link Iterable} object.
|
||||||
|
*
|
||||||
|
* @param <T> {@link Class} type of the elements in the {@link Iterable}.
|
||||||
|
* @return an empty {@link Iterable}.
|
||||||
|
* @see java.lang.Iterable
|
||||||
|
* @see #nullSafeIterable(Iterable)
|
||||||
|
*/
|
||||||
|
public static <T> Iterable<T> emptyIterable() {
|
||||||
|
return nullSafeIterable(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapts the given Enumeration as an Iterable object for use within a for each loop.
|
* Adapts the given Enumeration as an Iterable object for use within a for each loop.
|
||||||
*
|
*
|
||||||
@@ -140,6 +188,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
|||||||
* @see java.util.Collections#emptyMap()
|
* @see java.util.Collections#emptyMap()
|
||||||
* @see java.util.Map
|
* @see java.util.Map
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("all")
|
||||||
public static <K, V> Map<K, V> nullSafeMap(Map<K, V> map) {
|
public static <K, V> Map<K, V> nullSafeMap(Map<K, V> map) {
|
||||||
return (map != null ? map : Collections.emptyMap());
|
return (map != null ? map : Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ import org.apache.geode.cache.PartitionResolver;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The PartitionAttributesFactoryBeanTest class is test suite of test cases testing the contract and functionality of
|
* Unit tests for {@link PartitionAttributesFactoryBean}.
|
||||||
* the PartitionAttributesFactoryBean class.
|
|
||||||
*
|
*
|
||||||
* @author John Blum
|
* @author John Blum
|
||||||
* @see org.junit.Test
|
* @see org.junit.Test
|
||||||
@@ -52,11 +51,12 @@ public class PartitionAttributesFactoryBeanTest {
|
|||||||
partitionAttributesFactoryBean.setColocatedWith("mockColocatedRegion");
|
partitionAttributesFactoryBean.setColocatedWith("mockColocatedRegion");
|
||||||
partitionAttributesFactoryBean.setLocalMaxMemory(1024);
|
partitionAttributesFactoryBean.setLocalMaxMemory(1024);
|
||||||
partitionAttributesFactoryBean.setPartitionResolver(createMockPartitionResolver("mockPartitionResolver"));
|
partitionAttributesFactoryBean.setPartitionResolver(createMockPartitionResolver("mockPartitionResolver"));
|
||||||
partitionAttributesFactoryBean.setRecoveryDelay(1000l);
|
partitionAttributesFactoryBean.setRecoveryDelay(1000L);
|
||||||
partitionAttributesFactoryBean.setRedundantCopies(1);
|
partitionAttributesFactoryBean.setRedundantCopies(1);
|
||||||
partitionAttributesFactoryBean.setStartupRecoveryDelay(60000l);
|
partitionAttributesFactoryBean.setStartupRecoveryDelay(60000L);
|
||||||
partitionAttributesFactoryBean.setTotalMaxMemory(8192l);
|
partitionAttributesFactoryBean.setTotalMaxMemory(8192L);
|
||||||
partitionAttributesFactoryBean.setTotalNumBuckets(42);
|
partitionAttributesFactoryBean.setTotalNumBuckets(42);
|
||||||
|
partitionAttributesFactoryBean.afterPropertiesSet();
|
||||||
|
|
||||||
PartitionAttributes partitionAttributes = partitionAttributesFactoryBean.getObject();
|
PartitionAttributes partitionAttributes = partitionAttributesFactoryBean.getObject();
|
||||||
|
|
||||||
@@ -65,10 +65,10 @@ public class PartitionAttributesFactoryBeanTest {
|
|||||||
assertEquals(1024, partitionAttributes.getLocalMaxMemory());
|
assertEquals(1024, partitionAttributes.getLocalMaxMemory());
|
||||||
assertNotNull(partitionAttributes.getPartitionResolver());
|
assertNotNull(partitionAttributes.getPartitionResolver());
|
||||||
assertEquals("mockPartitionResolver", partitionAttributes.getPartitionResolver().getName());
|
assertEquals("mockPartitionResolver", partitionAttributes.getPartitionResolver().getName());
|
||||||
assertEquals(1000l, partitionAttributes.getRecoveryDelay());
|
assertEquals(1000L, partitionAttributes.getRecoveryDelay());
|
||||||
assertEquals(1, partitionAttributes.getRedundantCopies());
|
assertEquals(1, partitionAttributes.getRedundantCopies());
|
||||||
assertEquals(60000l, partitionAttributes.getStartupRecoveryDelay());
|
assertEquals(60000L, partitionAttributes.getStartupRecoveryDelay());
|
||||||
assertEquals(8192l, partitionAttributes.getTotalMaxMemory());
|
assertEquals(8192L, partitionAttributes.getTotalMaxMemory());
|
||||||
assertEquals(42, partitionAttributes.getTotalNumBuckets());
|
assertEquals(42, partitionAttributes.getTotalNumBuckets());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,14 +76,13 @@ public class PartitionAttributesFactoryBeanTest {
|
|||||||
public void testValidationOnRedundantCopiesWhenExceedsBound() throws Exception {
|
public void testValidationOnRedundantCopiesWhenExceedsBound() throws Exception {
|
||||||
PartitionAttributesFactoryBean partitionAttributesFactoryBean = new PartitionAttributesFactoryBean();
|
PartitionAttributesFactoryBean partitionAttributesFactoryBean = new PartitionAttributesFactoryBean();
|
||||||
partitionAttributesFactoryBean.setRedundantCopies(4);
|
partitionAttributesFactoryBean.setRedundantCopies(4);
|
||||||
partitionAttributesFactoryBean.getObject();
|
partitionAttributesFactoryBean.afterPropertiesSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testValidationOnRedundantCopiesWhenPrecedesBound() throws Exception {
|
public void testValidationOnRedundantCopiesWhenPrecedesBound() throws Exception {
|
||||||
PartitionAttributesFactoryBean partitionAttributesFactoryBean = new PartitionAttributesFactoryBean();
|
PartitionAttributesFactoryBean partitionAttributesFactoryBean = new PartitionAttributesFactoryBean();
|
||||||
partitionAttributesFactoryBean.setRedundantCopies(-1);
|
partitionAttributesFactoryBean.setRedundantCopies(-1);
|
||||||
partitionAttributesFactoryBean.getObject();
|
partitionAttributesFactoryBean.afterPropertiesSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,528 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.Cache;
|
||||||
|
import org.apache.geode.cache.DataPolicy;
|
||||||
|
import org.apache.geode.cache.DiskStore;
|
||||||
|
import org.apache.geode.cache.FixedPartitionAttributes;
|
||||||
|
import org.apache.geode.cache.PartitionAttributes;
|
||||||
|
import org.apache.geode.cache.PartitionResolver;
|
||||||
|
import org.apache.geode.cache.Region;
|
||||||
|
import org.apache.geode.cache.RegionAttributes;
|
||||||
|
import org.apache.geode.cache.RegionFactory;
|
||||||
|
import org.apache.geode.cache.Scope;
|
||||||
|
import org.apache.geode.cache.client.ClientCache;
|
||||||
|
import org.apache.geode.cache.client.ClientRegionFactory;
|
||||||
|
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.data.gemfire.client.ClientRegionShortcutWrapper;
|
||||||
|
import org.springframework.data.gemfire.config.annotation.test.entities.ClientRegionEntity;
|
||||||
|
import org.springframework.data.gemfire.config.annotation.test.entities.CollocatedPartitionRegionEntity;
|
||||||
|
import org.springframework.data.gemfire.config.annotation.test.entities.GenericRegionEntity;
|
||||||
|
import org.springframework.data.gemfire.config.annotation.test.entities.NonEntity;
|
||||||
|
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||||
|
import org.springframework.data.gemfire.mapping.ClientRegion;
|
||||||
|
import org.springframework.data.gemfire.mapping.LocalRegion;
|
||||||
|
import org.springframework.data.gemfire.mapping.PartitionRegion;
|
||||||
|
import org.springframework.data.gemfire.mapping.ReplicateRegion;
|
||||||
|
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the {@link EnableEntityDefinedRegions} annotation and {@link EntityDefinedRegionsConfiguration} class.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.junit.Test
|
||||||
|
* @see org.mockito.Mockito
|
||||||
|
* @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions
|
||||||
|
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
public class EnableEntityDefinedRegionsConfigurationUnitTests {
|
||||||
|
|
||||||
|
private static final AtomicInteger MOCK_ID = new AtomicInteger(0);
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
if (applicationContext != null) {
|
||||||
|
applicationContext.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertRegion(Region<?, ?> region, String name) {
|
||||||
|
assertRegion(region, name, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected <K, V> void assertRegion(Region<?, ?> region, String name,
|
||||||
|
Class<K> keyConstraint, Class<V> valueConstraint) {
|
||||||
|
|
||||||
|
assertRegion(region, name, String.format("%1$s%2$s", Region.SEPARATOR, name), keyConstraint, valueConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertRegion(Region<?, ?> region, String name, String fullPath) {
|
||||||
|
assertRegion(region, name, fullPath, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected <K, V> void assertRegion(Region<?, ?> region, String name, String fullPath,
|
||||||
|
Class<K> keyConstraint, Class<V> valueConstraint) {
|
||||||
|
|
||||||
|
assertThat(region).isNotNull();
|
||||||
|
assertThat(region.getName()).isEqualTo(name);
|
||||||
|
assertThat(region.getFullPath()).isEqualTo(fullPath);
|
||||||
|
assertThat(region.getAttributes()).isNotNull();
|
||||||
|
assertThat(region.getAttributes().getKeyConstraint()).isEqualTo(keyConstraint);
|
||||||
|
assertThat(region.getAttributes().getValueConstraint()).isEqualTo(valueConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertRegionAttributes(RegionAttributes<?, ?> regionAttributes, DataPolicy dataPolicy,
|
||||||
|
String diskStoreName, Boolean diskSynchronous, Boolean ignoreJta, String poolName, Scope scope) {
|
||||||
|
|
||||||
|
assertThat(regionAttributes).isNotNull();
|
||||||
|
assertThat(regionAttributes.getDataPolicy()).isEqualTo(dataPolicy);
|
||||||
|
assertThat(regionAttributes.getDiskStoreName()).isEqualTo(diskStoreName);
|
||||||
|
assertThat(regionAttributes.isDiskSynchronous()).isEqualTo(diskSynchronous);
|
||||||
|
assertThat(regionAttributes.getIgnoreJTA()).isEqualTo(ignoreJta);
|
||||||
|
assertThat(regionAttributes.getPoolName()).isEqualToIgnoringCase(poolName);
|
||||||
|
assertThat(regionAttributes.getScope()).isEqualTo(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertPartitionAttributes(PartitionAttributes<?, ?> partitionAttributes,
|
||||||
|
String collocatedWith, PartitionResolver partitionResolver, Integer redundantCopies) {
|
||||||
|
|
||||||
|
assertThat(partitionAttributes).isNotNull();
|
||||||
|
assertThat(partitionAttributes.getColocatedWith()).isEqualTo(collocatedWith);
|
||||||
|
assertThat(partitionAttributes.getPartitionResolver()).isEqualTo(partitionResolver);
|
||||||
|
assertThat(partitionAttributes.getRedundantCopies()).isEqualTo(redundantCopies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertFixedPartitionAttributes(FixedPartitionAttributes fixedPartitionAttributes,
|
||||||
|
String partitionName, boolean primary, int numBuckets) {
|
||||||
|
|
||||||
|
assertThat(fixedPartitionAttributes).isNotNull();
|
||||||
|
assertThat(fixedPartitionAttributes.getPartitionName()).isEqualTo(partitionName);
|
||||||
|
assertThat(fixedPartitionAttributes.isPrimary()).isEqualTo(primary);
|
||||||
|
assertThat(fixedPartitionAttributes.getNumBuckets()).isEqualTo(numBuckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected FixedPartitionAttributes findFixedPartitionAttributes(PartitionAttributes partitionAttributes,
|
||||||
|
String partitionName) {
|
||||||
|
|
||||||
|
assertThat(partitionAttributes).isNotNull();
|
||||||
|
|
||||||
|
List<FixedPartitionAttributes> fixedPartitionAttributes =
|
||||||
|
CollectionUtils.nullSafeList(partitionAttributes.getFixedPartitionAttributes());
|
||||||
|
|
||||||
|
for (FixedPartitionAttributes attributes : fixedPartitionAttributes) {
|
||||||
|
if (attributes.getPartitionName().equals(partitionName)) {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
|
||||||
|
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses);
|
||||||
|
applicationContext.registerShutdownHook();
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void entityClientRegionsDefined() {
|
||||||
|
applicationContext = newApplicationContext(ClientPersistentEntitiesConfiguration.class);
|
||||||
|
|
||||||
|
Region<String, ClientRegionEntity> sessions = applicationContext.getBean("Sessions", Region.class);
|
||||||
|
|
||||||
|
assertRegion(sessions, "Sessions", String.class, ClientRegionEntity.class);
|
||||||
|
assertRegionAttributes(sessions.getAttributes(), DataPolicy.NORMAL, null, true, false,
|
||||||
|
GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, null);
|
||||||
|
|
||||||
|
Region<Long, GenericRegionEntity> genericRegionEntity =
|
||||||
|
applicationContext.getBean("GenericRegionEntity", Region.class);
|
||||||
|
|
||||||
|
assertRegion(genericRegionEntity, "GenericRegionEntity", Long.class, GenericRegionEntity.class);
|
||||||
|
assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.EMPTY, null, true, false,
|
||||||
|
GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, null);
|
||||||
|
|
||||||
|
assertThat(applicationContext.containsBean("CollocatedPartitionRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("ContactEvents")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("NonEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("Accounts")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("Customers")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("LocalRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("PartitionRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("ReplicateRegionEntity")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void entityPeerPartitionRegionsDefined() {
|
||||||
|
applicationContext = newApplicationContext(PeerPartitionRegionPersistentEntitiesConfiguration.class);
|
||||||
|
|
||||||
|
Region<Object, Object> customers = applicationContext.getBean("Customers", Region.class);
|
||||||
|
|
||||||
|
assertRegion(customers, "Customers");
|
||||||
|
assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, null, true, false, null,
|
||||||
|
Scope.DISTRIBUTED_NO_ACK);
|
||||||
|
assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null, null, 1);
|
||||||
|
assertFixedPartitionAttributes(findFixedPartitionAttributes(
|
||||||
|
customers.getAttributes().getPartitionAttributes(), "one"), "one", true, 16);
|
||||||
|
assertFixedPartitionAttributes(findFixedPartitionAttributes(
|
||||||
|
customers.getAttributes().getPartitionAttributes(), "two"), "two", false, 21);
|
||||||
|
|
||||||
|
Region<Object, Object> contactEvents = applicationContext.getBean("ContactEvents", Region.class);
|
||||||
|
|
||||||
|
assertRegion(contactEvents, "ContactEvents");
|
||||||
|
assertRegionAttributes(contactEvents.getAttributes(), DataPolicy.PERSISTENT_PARTITION, "mockDiskStore",
|
||||||
|
false, true, null, Scope.DISTRIBUTED_NO_ACK);
|
||||||
|
assertPartitionAttributes(contactEvents.getAttributes().getPartitionAttributes(), "Customers",
|
||||||
|
applicationContext.getBean("mockPartitionResolver", PartitionResolver.class), 2);
|
||||||
|
|
||||||
|
assertThat(applicationContext.getBean("mockDiskStore")).isInstanceOf(DiskStore.class);
|
||||||
|
assertThat(applicationContext.containsBean("ClientRegion")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("NonEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("Accounts")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("LocalRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("PartitionRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("ReplicateRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("Sessions")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void entityServerRegionsDefined() {
|
||||||
|
applicationContext = newApplicationContext(AllServerPersistentEntitiesConfiguration.class);
|
||||||
|
|
||||||
|
Region<Object, Object> accounts = applicationContext.getBean("Accounts", Region.class);
|
||||||
|
|
||||||
|
assertRegion(accounts, "Accounts");
|
||||||
|
assertRegionAttributes(accounts.getAttributes(), DataPolicy.REPLICATE, null, true, false, null,
|
||||||
|
Scope.DISTRIBUTED_ACK);
|
||||||
|
|
||||||
|
Region<Object, Object> customers = applicationContext.getBean("Customers", Region.class);
|
||||||
|
|
||||||
|
assertRegion(customers, "Customers");
|
||||||
|
assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, null, true, false, null,
|
||||||
|
Scope.DISTRIBUTED_NO_ACK);
|
||||||
|
assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null, null, 1);
|
||||||
|
|
||||||
|
Region<Object, Object> localRegionEntity = applicationContext.getBean("LocalRegionEntity", Region.class);
|
||||||
|
|
||||||
|
assertRegion(localRegionEntity, "LocalRegionEntity");
|
||||||
|
assertRegionAttributes(localRegionEntity.getAttributes(), DataPolicy.NORMAL,
|
||||||
|
null, true, false, null, Scope.LOCAL);
|
||||||
|
|
||||||
|
Region<Object, Object> genericRegionEntity = applicationContext.getBean("GenericRegionEntity", Region.class);
|
||||||
|
|
||||||
|
assertRegion(genericRegionEntity, "GenericRegionEntity");
|
||||||
|
assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.NORMAL, null, true, false, null,
|
||||||
|
Scope.DISTRIBUTED_NO_ACK);
|
||||||
|
|
||||||
|
assertThat(applicationContext.containsBean("CollocatedPartitionRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("ContactEvents")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("NonEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("PartitionRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("ReplicateRegionEntity")).isFalse();
|
||||||
|
assertThat(applicationContext.containsBean("Sessions")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static String mockName(String baseMockName) {
|
||||||
|
return String.format("%s%d", baseMockName, MOCK_ID.incrementAndGet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static <K, V> Cache mockCache() {
|
||||||
|
Cache mockCache = mock(Cache.class);
|
||||||
|
|
||||||
|
Answer<RegionFactory<K, V>> createRegionFactory = new Answer<RegionFactory<K, V>>() {
|
||||||
|
@Override @SuppressWarnings("unchecked")
|
||||||
|
public RegionFactory<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
RegionAttributes<K, V> defaultRegionAttributes =
|
||||||
|
mockRegionAttributes(null, null, true, false, null, null, null, Scope.DISTRIBUTED_NO_ACK, null);
|
||||||
|
|
||||||
|
RegionAttributes<K, V> regionAttributes = (invocation.getArguments().length == 1
|
||||||
|
? invocation.getArgumentAt(0, RegionAttributes.class) : defaultRegionAttributes);
|
||||||
|
|
||||||
|
return mockRegionFactory(regionAttributes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
when(mockCache.createRegionFactory()).thenAnswer(createRegionFactory);
|
||||||
|
when(mockCache.createRegionFactory(any(RegionAttributes.class))).thenAnswer(createRegionFactory);
|
||||||
|
|
||||||
|
return mockCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static <K, V> ClientCache mockClientCache() {
|
||||||
|
ClientCache mockClientCache = mock(ClientCache.class, mockName("ClientCache"));
|
||||||
|
|
||||||
|
Answer<ClientRegionFactory<K, V>> createClientRegionFactory = new Answer<ClientRegionFactory<K, V>>() {
|
||||||
|
@Override @SuppressWarnings("unchecked")
|
||||||
|
public ClientRegionFactory<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
return mockClientRegionFactory(invocation.getArgumentAt(0, ClientRegionShortcut.class));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
when(mockClientCache.createClientRegionFactory(any(ClientRegionShortcut.class)))
|
||||||
|
.thenAnswer(createClientRegionFactory);
|
||||||
|
|
||||||
|
return mockClientCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static <K, V> ClientRegionFactory<K, V> mockClientRegionFactory(ClientRegionShortcut shortcut) {
|
||||||
|
ClientRegionFactory<K, V> mockClientRegionFactory =
|
||||||
|
mock(ClientRegionFactory.class, mockName("MockClientRegionFactory"));
|
||||||
|
|
||||||
|
AtomicReference<String> diskStoreName = new AtomicReference<>();
|
||||||
|
AtomicReference<Boolean> diskSynchronous = new AtomicReference<>(true);
|
||||||
|
AtomicReference<Class> keyConstraint = new AtomicReference<>(null);
|
||||||
|
AtomicReference<String> poolName = new AtomicReference<>();
|
||||||
|
AtomicReference<Class> valueConstraint = new AtomicReference<>(null);
|
||||||
|
|
||||||
|
when(mockClientRegionFactory.setDiskStoreName(anyString())).thenAnswer(
|
||||||
|
newSetter(String.class, diskStoreName, mockClientRegionFactory));
|
||||||
|
|
||||||
|
when(mockClientRegionFactory.setDiskSynchronous(anyBoolean())).thenAnswer(
|
||||||
|
newSetter(Boolean.TYPE, diskSynchronous, mockClientRegionFactory));
|
||||||
|
|
||||||
|
when(mockClientRegionFactory.setKeyConstraint(any(Class.class))).thenAnswer(
|
||||||
|
newSetter(Class.class, keyConstraint, mockClientRegionFactory));
|
||||||
|
|
||||||
|
when(mockClientRegionFactory.setPoolName(anyString())).thenAnswer(
|
||||||
|
newSetter(String.class, poolName, mockClientRegionFactory));
|
||||||
|
|
||||||
|
when(mockClientRegionFactory.setValueConstraint(any(Class.class))).thenAnswer(
|
||||||
|
newSetter(Class.class, valueConstraint, mockClientRegionFactory));
|
||||||
|
|
||||||
|
final RegionAttributes<K, V> mockRegionAttributes =
|
||||||
|
mock(RegionAttributes.class, mockName("MockClientRegionAttributes"));
|
||||||
|
|
||||||
|
when(mockRegionAttributes.getDataPolicy()).thenReturn(
|
||||||
|
ClientRegionShortcutWrapper.valueOf(shortcut).getDataPolicy());
|
||||||
|
when(mockRegionAttributes.getDiskStoreName()).thenAnswer(newGetter(diskStoreName));
|
||||||
|
when(mockRegionAttributes.isDiskSynchronous()).thenAnswer(newGetter(diskSynchronous));
|
||||||
|
when(mockRegionAttributes.getKeyConstraint()).thenAnswer(newGetter(keyConstraint));
|
||||||
|
when(mockRegionAttributes.getPoolName()).thenAnswer(newGetter(poolName));
|
||||||
|
when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint));
|
||||||
|
|
||||||
|
when(mockClientRegionFactory.create(anyString())).thenAnswer(new Answer<Region<K, V>>() {
|
||||||
|
@Override
|
||||||
|
public Region<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
return mockRegion(invocation.getArgumentAt(0, String.class), mockRegionAttributes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return mockClientRegionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static <K, V> RegionAttributes<K, V> mockRegionAttributes(DataPolicy dataPolicy,
|
||||||
|
String diskStoreName, boolean diskSynchronous, boolean ignoreJta, Class<K> keyConstraint,
|
||||||
|
PartitionAttributes<K, V> partitionAttributes, String poolName, Scope scope, Class<V> valueConstraint) {
|
||||||
|
|
||||||
|
RegionAttributes<K, V> mockRegionAttributes = mock(RegionAttributes.class, mockName("MockRegionAttributes"));
|
||||||
|
|
||||||
|
when(mockRegionAttributes.getDataPolicy()).thenReturn(dataPolicy);
|
||||||
|
when(mockRegionAttributes.getDiskStoreName()).thenReturn(diskStoreName);
|
||||||
|
when(mockRegionAttributes.isDiskSynchronous()).thenReturn(diskSynchronous);
|
||||||
|
when(mockRegionAttributes.getIgnoreJTA()).thenReturn(ignoreJta);
|
||||||
|
when(mockRegionAttributes.getKeyConstraint()).thenReturn(keyConstraint);
|
||||||
|
when(mockRegionAttributes.getPartitionAttributes()).thenReturn(partitionAttributes);
|
||||||
|
when(mockRegionAttributes.getPoolName()).thenReturn(poolName);
|
||||||
|
when(mockRegionAttributes.getScope()).thenReturn(scope);
|
||||||
|
when(mockRegionAttributes.getValueConstraint()).thenReturn(valueConstraint);
|
||||||
|
|
||||||
|
return mockRegionAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static <K, V> RegionFactory<K, V> mockRegionFactory(RegionAttributes<K, V> regionAttributes) {
|
||||||
|
RegionFactory<K, V> mockRegionFactory = mock(RegionFactory.class, mockName("MockRegionFactory"));
|
||||||
|
|
||||||
|
AtomicReference<DataPolicy> dataPolicy = new AtomicReference<>(regionAttributes.getDataPolicy());
|
||||||
|
AtomicReference<String> diskStoreName = new AtomicReference<>(regionAttributes.getDiskStoreName());
|
||||||
|
AtomicReference<Boolean> diskSynchronous = new AtomicReference<>(regionAttributes.isDiskSynchronous());
|
||||||
|
AtomicReference<Boolean> ignoreJta = new AtomicReference<>(regionAttributes.getIgnoreJTA());
|
||||||
|
AtomicReference<Class> keyConstraint = new AtomicReference<>(null);
|
||||||
|
AtomicReference<PartitionAttributes> partitionAttributes = new AtomicReference<>(
|
||||||
|
regionAttributes.getPartitionAttributes());
|
||||||
|
AtomicReference<Scope> scope = new AtomicReference<>(regionAttributes.getScope());
|
||||||
|
AtomicReference<Class> valueConstraint = new AtomicReference<>(null);
|
||||||
|
|
||||||
|
when(mockRegionFactory.setDataPolicy(any(DataPolicy.class))).thenAnswer(
|
||||||
|
newSetter(DataPolicy.class, dataPolicy, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setDiskStoreName(anyString())).thenAnswer(
|
||||||
|
newSetter(String.class, diskStoreName, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setDiskSynchronous(anyBoolean())).thenAnswer(
|
||||||
|
newSetter(Boolean.TYPE, diskSynchronous, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setIgnoreJTA(anyBoolean())).thenAnswer(
|
||||||
|
newSetter(Boolean.TYPE, ignoreJta, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setKeyConstraint(any(Class.class))).thenAnswer(
|
||||||
|
newSetter(Class.class, keyConstraint, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setPartitionAttributes(any(PartitionAttributes.class))).thenAnswer(
|
||||||
|
newSetter(PartitionAttributes.class, partitionAttributes, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setScope(any(Scope.class))).thenAnswer(
|
||||||
|
newSetter(Scope.class, scope, mockRegionFactory));
|
||||||
|
|
||||||
|
when(mockRegionFactory.setValueConstraint(any(Class.class))).thenAnswer(
|
||||||
|
newSetter(Class.class, valueConstraint, mockRegionFactory));
|
||||||
|
|
||||||
|
final RegionAttributes<K, V> mockRegionAttributes =
|
||||||
|
mock(RegionAttributes.class, mockName("MockRegionAttributes"));
|
||||||
|
|
||||||
|
when(mockRegionAttributes.getDataPolicy()).thenAnswer(newGetter(dataPolicy));
|
||||||
|
when(mockRegionAttributes.getDiskStoreName()).thenAnswer(newGetter(diskStoreName));
|
||||||
|
when(mockRegionAttributes.isDiskSynchronous()).thenAnswer(newGetter(diskSynchronous));
|
||||||
|
when(mockRegionAttributes.getIgnoreJTA()).thenAnswer(newGetter(ignoreJta));
|
||||||
|
when(mockRegionAttributes.getKeyConstraint()).thenAnswer(newGetter(keyConstraint));
|
||||||
|
when(mockRegionAttributes.getPartitionAttributes()).thenAnswer(newGetter(partitionAttributes));
|
||||||
|
when(mockRegionAttributes.getScope()).thenAnswer(newGetter(scope));
|
||||||
|
when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint));
|
||||||
|
|
||||||
|
when(mockRegionFactory.create(anyString())).thenAnswer(new Answer<Region<K, V>>() {
|
||||||
|
@Override
|
||||||
|
public Region<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
return mockRegion(invocation.getArgumentAt(0, String.class), mockRegionAttributes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return mockRegionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static <K, V> Region<K, V> mockRegion(String name, RegionAttributes<K, V> regionAttributes) {
|
||||||
|
Region<K, V> mockRegion = mock(Region.class, mockName(name));
|
||||||
|
|
||||||
|
when(mockRegion.getName()).thenReturn(name);
|
||||||
|
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name));
|
||||||
|
when(mockRegion.getAttributes()).thenReturn(regionAttributes);
|
||||||
|
|
||||||
|
return mockRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static <R> Answer<R> newGetter(AtomicReference<R> returnValue) {
|
||||||
|
return invocation -> returnValue.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static <T, R> Answer<R> newSetter(Class<T> parameterType, AtomicReference<T> argument, R returnValue) {
|
||||||
|
|
||||||
|
return invocation -> {
|
||||||
|
argument.set(invocation.getArgumentAt(0, parameterType));
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
static abstract class ClientCacheConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ClientCache gemfireCache() {
|
||||||
|
return mockClientCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
static abstract class ServerCacheConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Cache gemfireCache() {
|
||||||
|
return mockCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
|
||||||
|
excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = ClientRegion.class),
|
||||||
|
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CollocatedPartitionRegionEntity.class) })
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
static class AllServerPersistentEntitiesConfiguration extends ServerCacheConfiguration {
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, strict = true,
|
||||||
|
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
|
||||||
|
classes = { LocalRegion.class, PartitionRegion.class, ReplicateRegion.class }))
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
static class ClientPersistentEntitiesConfiguration extends ClientCacheConfiguration {
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
|
||||||
|
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
|
||||||
|
classes = { ClientRegion.class, LocalRegion.class, ReplicateRegion.class }))
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
static class PeerPartitionRegionPersistentEntitiesConfiguration extends ServerCacheConfiguration {
|
||||||
|
|
||||||
|
@Bean @Lazy
|
||||||
|
DiskStore mockDiskStore() {
|
||||||
|
return mock(DiskStore.class, mockName("MockDiskStore"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean @Lazy
|
||||||
|
PartitionResolver mockPartitionResolver() {
|
||||||
|
return mock(PartitionResolver.class, mockName("MockPartitionResolver"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.gemfire.mapping.ClientRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ClientRegionEntity} persistent entity stored in the "Users" {@link org.apache.geode.cache.DataPolicy#NORMAL},
|
||||||
|
* client {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@ClientRegion(name = "Sessions", shortcut = ClientRegionShortcut.CACHING_PROXY)
|
||||||
|
public class ClientRegionEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
import org.springframework.data.gemfire.mapping.PartitionRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link CollocatedPartitionRegionEntity} persistent entity stored in the "ContactEvents"
|
||||||
|
* {@link org.apache.geode.cache.DataPolicy#PERSISTENT_PARTITION} {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@PartitionRegion(value = "ContactEvents", collocatedWith = "Customers", diskStoreName = "mockDiskStore",
|
||||||
|
diskSynchronous = false, ignoreJta = true, partitionResolverName = "mockPartitionResolver",
|
||||||
|
persistent = true, redundantCopies = 2)
|
||||||
|
public class CollocatedPartitionRegionEntity {
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String phoneNumber;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.gemfire.mapping.Region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GenericRegionEntity} persistent entity stored in the "GenericRegionEntity"
|
||||||
|
* {@link org.apache.geode.cache.DataPolicy#NORMAL}, {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@Region
|
||||||
|
public class GenericRegionEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.gemfire.mapping.LocalRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link LocalRegionEntity} persistent entity stored in the "LocalRegionEntity" {@link org.apache.geode.cache.DataPolicy#NORMAL},
|
||||||
|
* {@link org.apache.geode.cache.Scope#LOCAL} {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@LocalRegion
|
||||||
|
public class LocalRegionEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non-persistent entity class.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
public class NonEntity {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.gemfire.mapping.PartitionRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link PartitionRegionEntity} persistent entity stored in the "Customers"
|
||||||
|
* {@link org.apache.geode.cache.DataPolicy#PERSISTENT_PARTITION} {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@PartitionRegion(name = "Customers", persistent = true, redundantCopies = 1,
|
||||||
|
fixedPartitions = {
|
||||||
|
@PartitionRegion.FixedPartition(name = "one", primary = true, numBuckets = 16),
|
||||||
|
@PartitionRegion.FixedPartition(name = "two", numBuckets = 21)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public class PartitionRegionEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.config.annotation.test.entities;
|
||||||
|
|
||||||
|
import org.springframework.data.gemfire.ScopeType;
|
||||||
|
import org.springframework.data.gemfire.mapping.ReplicateRegion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ReplicateRegionEntity} persistent entity stored in the "Accounts"
|
||||||
|
* {@link org.apache.geode.cache.DataPolicy#REPLICATE} {@link org.apache.geode.cache.Region}.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
@ReplicateRegion(name = "Accounts", scope = ScopeType.DISTRIBUTED_ACK)
|
||||||
|
public class ReplicateRegionEntity {
|
||||||
|
|
||||||
|
private String number;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ package org.springframework.data.gemfire.repository.sample;
|
|||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.gemfire.mapping.Region;
|
import org.springframework.data.gemfire.mapping.Region;
|
||||||
|
import org.springframework.data.gemfire.mapping.ReplicateRegion;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,7 +28,7 @@ import org.springframework.util.Assert;
|
|||||||
* @see org.springframework.data.gemfire.mapping.Region
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
@Region("Accounts")
|
@ReplicateRegion("Accounts")
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class Account {
|
public class Account {
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.springframework.data.gemfire.repository.sample;
|
|||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.gemfire.mapping.Region;
|
import org.springframework.data.gemfire.mapping.Region;
|
||||||
|
import org.springframework.data.gemfire.mapping.ReplicateRegion;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,8 +29,8 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* @see org.springframework.data.gemfire.mapping.Region
|
* @see org.springframework.data.gemfire.mapping.Region
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
|
@ReplicateRegion("Customers")
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Region("Customers")
|
|
||||||
public class Customer {
|
public class Customer {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import org.junit.Test;
|
|||||||
public class ArrayUtilsUnitTests {
|
public class ArrayUtilsUnitTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void asArrayRetursEmptyArray() {
|
public void asArrayReturnsEmptyArray() {
|
||||||
Object[] array = ArrayUtils.asArray();
|
Object[] array = ArrayUtils.asArray();
|
||||||
|
|
||||||
assertThat(array).isNotNull();
|
assertThat(array).isNotNull();
|
||||||
@@ -58,6 +58,34 @@ public class ArrayUtilsUnitTests {
|
|||||||
assertThat(array).isEqualTo(new Object[] { 1 });
|
assertThat(array).isEqualTo(new Object[] { 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithNonNullNonEmptyArrayReturnsArray() {
|
||||||
|
Object[] array = { "test" };
|
||||||
|
Object[] defaultArray = { "tested" };
|
||||||
|
|
||||||
|
assertThat(ArrayUtils.defaultIfEmpty(array, defaultArray)).isSameAs(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithEmptyArrayReturnsDefaultArray() {
|
||||||
|
Object[] array = {};
|
||||||
|
Object[] defaultArray = { "tested" };
|
||||||
|
|
||||||
|
assertThat(ArrayUtils.defaultIfEmpty(array, defaultArray)).isSameAs(defaultArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithNullArrayReturnsDefaultArray() {
|
||||||
|
Object[] defaultArray = { "tested" };
|
||||||
|
|
||||||
|
assertThat(ArrayUtils.defaultIfEmpty(null, defaultArray)).isSameAs(defaultArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithNullArrayAndNullDefaultArrayReturnsNull() {
|
||||||
|
assertThat(ArrayUtils.defaultIfEmpty(null, null)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFirstWithNonNullArray() {
|
public void getFirstWithNonNullArray() {
|
||||||
assertThat(ArrayUtils.getFirst(ArrayUtils.asArray(1, 2, 3))).isEqualTo(1);
|
assertThat(ArrayUtils.getFirst(ArrayUtils.asArray(1, 2, 3))).isEqualTo(1);
|
||||||
@@ -187,6 +215,7 @@ public class ArrayUtilsUnitTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void sortIsSuccessful() {
|
public void sortIsSuccessful() {
|
||||||
Comparable[] array = new Comparable[] { 2, 3, 1 };
|
Comparable[] array = new Comparable[] { 2, 3, 1 };
|
||||||
Comparable[] sortedArray = ArrayUtils.sort(array);
|
Comparable[] sortedArray = ArrayUtils.sort(array);
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import static org.mockito.Mockito.when;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -59,6 +61,61 @@ public class CollectionUtilsUnitTests {
|
|||||||
@Rule
|
@Rule
|
||||||
public ExpectedException exception = ExpectedException.none();
|
public ExpectedException exception = ExpectedException.none();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addAllIterableElementsToList() {
|
||||||
|
List<Integer> target = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
|
||||||
|
Set<Integer> source = new HashSet<Integer>(Arrays.asList(1, 2, 3));
|
||||||
|
|
||||||
|
target = CollectionUtils.addAll(target, source);
|
||||||
|
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
assertThat(target.size()).isEqualTo(6);
|
||||||
|
assertThat(target).isEqualTo(Arrays.asList(1, 2, 3, 1, 2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addAllIterableElementsToSet() {
|
||||||
|
Set<Integer> target = new HashSet<Integer>(Arrays.asList(1, 2, 3));
|
||||||
|
Set<Integer> source = new HashSet<Integer>(Arrays.asList(1, 2, 3, 4, 5));
|
||||||
|
|
||||||
|
target = CollectionUtils.addAll(target, source);
|
||||||
|
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
assertThat(target.size()).isEqualTo(5);
|
||||||
|
assertThat(target).contains(1, 2, 3, 4, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addIterableToNullCollection() {
|
||||||
|
exception.expect(IllegalArgumentException.class);
|
||||||
|
exception.expectCause(is(nullValue(Throwable.class)));
|
||||||
|
exception.expectMessage("Collection must not be null");
|
||||||
|
|
||||||
|
CollectionUtils.addAll(null, Collections.emptySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addEmptyIterableToCollection() {
|
||||||
|
Collection<Integer> target = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
|
||||||
|
|
||||||
|
target = CollectionUtils.addAll(target, Collections.<Integer>emptyList());
|
||||||
|
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
assertThat(target.size()).isEqualTo(3);
|
||||||
|
assertThat(target).contains(1, 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNullIterableToCollection() {
|
||||||
|
Collection<Integer> target = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
|
||||||
|
|
||||||
|
target = CollectionUtils.addAll(target, null);
|
||||||
|
|
||||||
|
assertThat(target).isNotNull();
|
||||||
|
assertThat(target.size()).isEqualTo(3);
|
||||||
|
assertThat(target).contains(1, 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void asSetContainsAllArrayElements() {
|
public void asSetContainsAllArrayElements() {
|
||||||
Object[] elements = { "a", "b", "c" };
|
Object[] elements = { "a", "b", "c" };
|
||||||
@@ -67,7 +124,7 @@ public class CollectionUtilsUnitTests {
|
|||||||
|
|
||||||
assertThat(set).isNotNull();
|
assertThat(set).isNotNull();
|
||||||
assertThat(set.size()).isEqualTo(elements.length);
|
assertThat(set.size()).isEqualTo(elements.length);
|
||||||
assertThat(set).containsAll(Arrays.asList(elements));
|
assertThat(set.containsAll(Arrays.asList(elements))).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -78,7 +135,7 @@ public class CollectionUtilsUnitTests {
|
|||||||
|
|
||||||
assertThat(set).isNotNull();
|
assertThat(set).isNotNull();
|
||||||
assertThat(set.size()).isEqualTo(2);
|
assertThat(set.size()).isEqualTo(2);
|
||||||
assertThat(set).containsAll(Arrays.asList(elements));
|
assertThat(set.containsAll(Arrays.asList(elements))).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = UnsupportedOperationException.class)
|
@Test(expected = UnsupportedOperationException.class)
|
||||||
@@ -99,6 +156,43 @@ public class CollectionUtilsUnitTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithNonNullNonEmptyIterableReturnsIterable() {
|
||||||
|
Iterable<Object> iterable = Collections.<Object>singleton(1);
|
||||||
|
Iterable<Object> defaultIterable = Collections.<Object>singleton(2);
|
||||||
|
|
||||||
|
assertThat(CollectionUtils.defaultIfEmpty(iterable, defaultIterable)).isSameAs(iterable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithEmptyIterableReturnsDefault() {
|
||||||
|
Iterable<Object> iterable = Collections.emptySet();
|
||||||
|
Iterable<Object> defaultIterable = Collections.<Object>singleton(2);
|
||||||
|
|
||||||
|
assertThat(CollectionUtils.defaultIfEmpty(iterable, defaultIterable)).isSameAs(defaultIterable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithNullIterableReturnsDefault() {
|
||||||
|
Iterable<?> defaultIterable = Collections.singleton(2);
|
||||||
|
|
||||||
|
assertThat(CollectionUtils.defaultIfEmpty(null, defaultIterable)).isSameAs(defaultIterable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIfEmptyWithNullIterableAndNullDefaultReturnsNull() {
|
||||||
|
assertThat(CollectionUtils.defaultIfEmpty((Iterable<?>) null, null)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyIterableReturnsEmptyIterable() {
|
||||||
|
Iterable<?> iterable = CollectionUtils.emptyIterable();
|
||||||
|
|
||||||
|
assertThat(iterable).isNotNull();
|
||||||
|
assertThat(iterable.iterator()).isNotNull();
|
||||||
|
assertThat(iterable.iterator().hasNext()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void iterableEnumeration() {
|
public void iterableEnumeration() {
|
||||||
|
|||||||
Reference in New Issue
Block a user