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
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire;
|
||||
|
||||
import org.apache.geode.cache.FixedPartitionAttributes;
|
||||
@@ -21,15 +22,93 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
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 {
|
||||
|
||||
private Boolean primary;
|
||||
private String partitionName;
|
||||
private Integer numBuckets;
|
||||
|
||||
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).
|
||||
*
|
||||
@@ -38,63 +117,4 @@ public class FixedPartitionAttributesFactoryBean implements FactoryBean<FixedPar
|
||||
public void setPrimary(boolean 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.PartitionAttributes;
|
||||
import org.apache.geode.cache.PartitionAttributesFactory;
|
||||
import org.apache.geode.cache.PartitionResolver;
|
||||
import org.apache.geode.cache.partition.PartitionListener;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
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
|
||||
* a XML 'factory-method' tag and allows the attributes properties to be set directly.
|
||||
* Spring {@link FactoryBean} for creating {@link PartitionAttributes}.
|
||||
*
|
||||
* Eliminates the need to use a XML 'factory-method' tag and allows the attributes properties to be set directly.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author David Turanski
|
||||
* @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" })
|
||||
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 =
|
||||
new org.apache.geode.cache.PartitionAttributesFactory();
|
||||
private List<PartitionListener> partitionListeners;
|
||||
|
||||
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
|
||||
public PartitionAttributes getObject() throws Exception {
|
||||
return partitionAttributesFactory.create();
|
||||
return this.partitionAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return PartitionAttributes.class;
|
||||
return (this.partitionAttributes != null ? this.partitionAttributes.getClass() : PartitionAttributes.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setColocatedWith(String colocatedRegionFullPath) {
|
||||
partitionAttributesFactory.setColocatedWith(colocatedRegionFullPath);
|
||||
public void setColocatedWith(String collocatedWith) {
|
||||
partitionAttributesFactory.setColocatedWith(collocatedWith);
|
||||
}
|
||||
|
||||
public void setFixedPartitionAttributes(List<FixedPartitionAttributes> fixedPartitionAttributes) {
|
||||
for (FixedPartitionAttributes fpa : fixedPartitionAttributes) {
|
||||
partitionAttributesFactory.addFixedPartitionAttributes(fpa);
|
||||
for (FixedPartitionAttributes fixedPartitionAttributesElement :
|
||||
CollectionUtils.nullSafeList(fixedPartitionAttributes)) {
|
||||
|
||||
partitionAttributesFactory.addFixedPartitionAttributes(fixedPartitionAttributesElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,12 +105,12 @@ public class PartitionAttributesFactoryBean implements FactoryBean<PartitionAttr
|
||||
partitionAttributesFactory.setLocalMaxMemory(mb);
|
||||
}
|
||||
|
||||
public void setPartitionResolver(PartitionResolver resolver) {
|
||||
partitionAttributesFactory.setPartitionResolver(resolver);
|
||||
public void setPartitionListeners(List<PartitionListener> partitionListeners) {
|
||||
this.partitionListeners = partitionListeners;
|
||||
}
|
||||
|
||||
public void setPartitionListeners(List<PartitionListener> listeners) {
|
||||
this.listeners = listeners;
|
||||
public void setPartitionResolver(PartitionResolver resolver) {
|
||||
partitionAttributesFactory.setPartitionResolver(resolver);
|
||||
}
|
||||
|
||||
public void setRecoveryDelay(long recoveryDelay) {
|
||||
@@ -97,15 +132,4 @@ public class PartitionAttributesFactoryBean implements FactoryBean<PartitionAttr
|
||||
public void setTotalNumBuckets(int 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 Class<K> keyConstraint;
|
||||
private Class<V> valueConstraint;
|
||||
|
||||
private DataPolicy dataPolicy;
|
||||
|
||||
private EvictionAttributes evictionAttributes;
|
||||
@@ -146,10 +149,18 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
regionFactory.setEvictionAttributes(evictionAttributes);
|
||||
}
|
||||
|
||||
if (keyConstraint != null) {
|
||||
regionFactory.setKeyConstraint(keyConstraint);
|
||||
}
|
||||
|
||||
if (scope != null) {
|
||||
regionFactory.setScope(scope);
|
||||
}
|
||||
|
||||
if (valueConstraint != null) {
|
||||
regionFactory.setValueConstraint(valueConstraint);
|
||||
}
|
||||
|
||||
if (attributes != null) {
|
||||
Assert.state(!attributes.isLockGrantor() || (scope == null) || scope.isGlobal(),
|
||||
"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;
|
||||
}
|
||||
|
||||
public void setKeyConstraint(Class<K> keyConstraint) {
|
||||
this.keyConstraint = keyConstraint;
|
||||
}
|
||||
|
||||
public void setPersistent(Boolean persistent) {
|
||||
this.persistent = persistent;
|
||||
}
|
||||
@@ -714,6 +729,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
public void setValueConstraint(Class<V> valueConstraint) {
|
||||
this.valueConstraint = valueConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -70,18 +70,17 @@ public abstract class RegionLookupFactoryBean<K, V>
|
||||
|
||||
synchronized (this.cache) {
|
||||
if (isLookupEnabled()) {
|
||||
if (getParent() != null) {
|
||||
this.region = getParent().getSubregion(regionName);
|
||||
}
|
||||
else {
|
||||
this.region = this.cache.getRegion(regionName);
|
||||
}
|
||||
this.region = (getParent() != null ? getParent().<K, V>getSubregion(regionName)
|
||||
: this.cache.<K, V>getRegion(regionName));
|
||||
}
|
||||
|
||||
if (region != null) {
|
||||
log.info(String.format("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName()));
|
||||
}
|
||||
else {
|
||||
log.info(String.format("Falling back to creating Region [%1$s] in Cache [%2$s]",
|
||||
regionName, cache.getName()));
|
||||
|
||||
region = lookupRegion(cache, regionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package org.springframework.data.gemfire;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* The RegionShortcutWrapper enum is a Java enumerated type that wraps GemFire's RegionShortcuts
|
||||
* with Spring Data GemFire RegionShortcutWrapper enumerated values.
|
||||
* The {@link RegionShortcutWrapper} enum is a Java enumerated type that wraps GemFire's {@link RegionShortcut RegionShortcuts}
|
||||
* with Spring Data GemFire {@link RegionShortcutWrapper} enumerated values.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.RegionShortcut
|
||||
@@ -29,38 +30,41 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public enum RegionShortcutWrapper {
|
||||
LOCAL(RegionShortcut.LOCAL),
|
||||
LOCAL_HEAP_LRU(RegionShortcut.LOCAL_HEAP_LRU),
|
||||
LOCAL_OVERFLOW(RegionShortcut.LOCAL_OVERFLOW),
|
||||
LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT),
|
||||
LOCAL_PERSISTENT_OVERFLOW(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW),
|
||||
PARTITION(RegionShortcut.PARTITION),
|
||||
PARTITION_HEAP_LRU(RegionShortcut.PARTITION_HEAP_LRU),
|
||||
PARTITION_OVERFLOW(RegionShortcut.PARTITION_OVERFLOW),
|
||||
PARTITION_PERSISTENT(RegionShortcut.PARTITION_PERSISTENT),
|
||||
PARTITION_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW),
|
||||
PARTITION_PROXY(RegionShortcut.PARTITION_PROXY),
|
||||
PARTITION_PROXY_REDUNDANT(RegionShortcut.PARTITION_PROXY_REDUNDANT),
|
||||
PARTITION_REDUNDANT(RegionShortcut.PARTITION_REDUNDANT),
|
||||
PARTITION_REDUNDANT_HEAP_LRU(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU),
|
||||
PARTITION_REDUNDANT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW),
|
||||
PARTITION_REDUNDANT_PERSISTENT(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT),
|
||||
PARTITION_REDUNDANT_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW),
|
||||
REPLICATE(RegionShortcut.REPLICATE),
|
||||
REPLICATE_HEAP_LRU(RegionShortcut.REPLICATE_HEAP_LRU),
|
||||
REPLICATE_OVERFLOW(RegionShortcut.REPLICATE_OVERFLOW),
|
||||
REPLICATE_PERSISTENT(RegionShortcut.REPLICATE_PERSISTENT),
|
||||
REPLICATE_PERSISTENT_OVERFLOW(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW),
|
||||
REPLICATE_PROXY(RegionShortcut.REPLICATE_PROXY),
|
||||
UNSPECIFIED(null);
|
||||
LOCAL(RegionShortcut.LOCAL, DataPolicy.NORMAL),
|
||||
LOCAL_HEAP_LRU(RegionShortcut.LOCAL_HEAP_LRU, DataPolicy.NORMAL),
|
||||
LOCAL_OVERFLOW(RegionShortcut.LOCAL_OVERFLOW, DataPolicy.NORMAL),
|
||||
LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT, DataPolicy.NORMAL),
|
||||
LOCAL_PERSISTENT_OVERFLOW(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
|
||||
PARTITION(RegionShortcut.PARTITION, DataPolicy.PARTITION),
|
||||
PARTITION_HEAP_LRU(RegionShortcut.PARTITION_HEAP_LRU, DataPolicy.PARTITION),
|
||||
PARTITION_OVERFLOW(RegionShortcut.PARTITION_OVERFLOW, DataPolicy.PARTITION),
|
||||
PARTITION_PERSISTENT(RegionShortcut.PARTITION_PERSISTENT, DataPolicy.PERSISTENT_PARTITION),
|
||||
PARTITION_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_PARTITION),
|
||||
PARTITION_PROXY(RegionShortcut.PARTITION_PROXY, DataPolicy.PARTITION),
|
||||
PARTITION_PROXY_REDUNDANT(RegionShortcut.PARTITION_PROXY_REDUNDANT, DataPolicy.PARTITION),
|
||||
PARTITION_REDUNDANT(RegionShortcut.PARTITION_REDUNDANT, DataPolicy.PARTITION),
|
||||
PARTITION_REDUNDANT_HEAP_LRU(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU, DataPolicy.PARTITION),
|
||||
PARTITION_REDUNDANT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW, DataPolicy.PARTITION),
|
||||
PARTITION_REDUNDANT_PERSISTENT(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT, DataPolicy.PERSISTENT_PARTITION),
|
||||
PARTITION_REDUNDANT_PERSISTENT_OVERFLOW(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_PARTITION),
|
||||
REPLICATE(RegionShortcut.REPLICATE, DataPolicy.REPLICATE),
|
||||
REPLICATE_HEAP_LRU(RegionShortcut.REPLICATE_HEAP_LRU, DataPolicy.REPLICATE),
|
||||
REPLICATE_OVERFLOW(RegionShortcut.REPLICATE_OVERFLOW, DataPolicy.REPLICATE),
|
||||
REPLICATE_PERSISTENT(RegionShortcut.REPLICATE_PERSISTENT, DataPolicy.PERSISTENT_REPLICATE),
|
||||
REPLICATE_PERSISTENT_OVERFLOW(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
|
||||
REPLICATE_PROXY(RegionShortcut.REPLICATE_PROXY, DataPolicy.EMPTY),
|
||||
UNSPECIFIED(null, null);
|
||||
|
||||
private final DataPolicy dataPolicy;
|
||||
|
||||
private final RegionShortcut regionShortcut;
|
||||
|
||||
RegionShortcutWrapper(final RegionShortcut regionShortcut) {
|
||||
RegionShortcutWrapper(RegionShortcut regionShortcut, DataPolicy dataPolicy) {
|
||||
this.regionShortcut = regionShortcut;
|
||||
this.dataPolicy = dataPolicy;
|
||||
}
|
||||
|
||||
public static RegionShortcutWrapper valueOf(final RegionShortcut regionShortcut) {
|
||||
public static RegionShortcutWrapper valueOf(RegionShortcut regionShortcut) {
|
||||
for (RegionShortcutWrapper wrapper : values()) {
|
||||
if (ObjectUtils.nullSafeEquals(wrapper.getRegionShortcut(), regionShortcut)) {
|
||||
return wrapper;
|
||||
@@ -70,6 +74,14 @@ public enum RegionShortcutWrapper {
|
||||
return RegionShortcutWrapper.UNSPECIFIED;
|
||||
}
|
||||
|
||||
public DataPolicy getDataPolicy() {
|
||||
return this.dataPolicy;
|
||||
}
|
||||
|
||||
public RegionShortcut getRegionShortcut() {
|
||||
return this.regionShortcut;
|
||||
}
|
||||
|
||||
public boolean isHeapLru() {
|
||||
return name().contains("HEAP_LRU");
|
||||
}
|
||||
@@ -105,9 +117,4 @@ public enum RegionShortcutWrapper {
|
||||
public boolean isReplicate() {
|
||||
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 Class<K> keyConstraint;
|
||||
private Class<V> valueConstraint;
|
||||
|
||||
private ClientRegionShortcut shortcut = null;
|
||||
|
||||
private DataPolicy dataPolicy;
|
||||
@@ -125,6 +128,14 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
setEvictionAttributes(clientRegionFactory);
|
||||
setPoolName(clientRegionFactory);
|
||||
|
||||
if (keyConstraint != null) {
|
||||
clientRegionFactory.setKeyConstraint(keyConstraint);
|
||||
}
|
||||
|
||||
if (valueConstraint != null) {
|
||||
clientRegionFactory.setValueConstraint(valueConstraint);
|
||||
}
|
||||
|
||||
return logCreateRegionEvent(create(clientRegionFactory, regionName));
|
||||
}
|
||||
|
||||
@@ -562,6 +573,10 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
return this.interests;
|
||||
}
|
||||
|
||||
public void setKeyConstraint(Class<K> keyConstraint) {
|
||||
this.keyConstraint = keyConstraint;
|
||||
}
|
||||
|
||||
protected boolean isPersistentUnspecified() {
|
||||
return (persistent == null);
|
||||
}
|
||||
@@ -619,4 +634,8 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
public void setSnapshot(Resource snapshot) {
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
public void setValueConstraint(Class<V> valueConstraint) {
|
||||
this.valueConstraint = valueConstraint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package org.springframework.data.gemfire.client;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* The ClientRegionShortcutWrapper enum is a Java enumerated type that wraps GemFire's ClientRegionShortcuts
|
||||
* with Spring Data GemFire ClientRegionShortcutWrapper enumerated values.
|
||||
* The {@link ClientRegionShortcutWrapper} enum is a Java enumerated type that wraps GemFire's {@link ClientRegionShortcut ClientRegionShortcuts}
|
||||
* with Spring Data GemFire {@link ClientRegionShortcutWrapper} enumerated values.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.client.ClientRegionShortcut
|
||||
@@ -29,24 +30,27 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public enum ClientRegionShortcutWrapper {
|
||||
CACHING_PROXY(ClientRegionShortcut.CACHING_PROXY),
|
||||
CACHING_PROXY_HEAP_LRU(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU),
|
||||
CACHING_PROXY_OVERFLOW(ClientRegionShortcut.CACHING_PROXY_OVERFLOW),
|
||||
LOCAL(ClientRegionShortcut.LOCAL),
|
||||
LOCAL_HEAP_LRU(ClientRegionShortcut.LOCAL_HEAP_LRU),
|
||||
LOCAL_OVERFLOW(ClientRegionShortcut.LOCAL_OVERFLOW),
|
||||
LOCAL_PERSISTENT(ClientRegionShortcut.LOCAL_PERSISTENT),
|
||||
LOCAL_PERSISTENT_OVERFLOW(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW),
|
||||
PROXY(ClientRegionShortcut.PROXY),
|
||||
UNSPECIFIED(null);
|
||||
CACHING_PROXY(ClientRegionShortcut.CACHING_PROXY, DataPolicy.NORMAL),
|
||||
CACHING_PROXY_HEAP_LRU(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU, DataPolicy.NORMAL),
|
||||
CACHING_PROXY_OVERFLOW(ClientRegionShortcut.CACHING_PROXY_OVERFLOW, DataPolicy.NORMAL),
|
||||
LOCAL(ClientRegionShortcut.LOCAL, DataPolicy.NORMAL),
|
||||
LOCAL_HEAP_LRU(ClientRegionShortcut.LOCAL_HEAP_LRU, DataPolicy.NORMAL),
|
||||
LOCAL_OVERFLOW(ClientRegionShortcut.LOCAL_OVERFLOW, DataPolicy.NORMAL),
|
||||
LOCAL_PERSISTENT(ClientRegionShortcut.LOCAL_PERSISTENT, DataPolicy.PERSISTENT_REPLICATE),
|
||||
LOCAL_PERSISTENT_OVERFLOW(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
|
||||
PROXY(ClientRegionShortcut.PROXY, DataPolicy.EMPTY),
|
||||
UNSPECIFIED(null, null);
|
||||
|
||||
private final ClientRegionShortcut clientRegionShortcut;
|
||||
|
||||
ClientRegionShortcutWrapper(final ClientRegionShortcut clientRegionShortcut) {
|
||||
private final DataPolicy dataPolicy;
|
||||
|
||||
ClientRegionShortcutWrapper(ClientRegionShortcut clientRegionShortcut, DataPolicy dataPolicy) {
|
||||
this.clientRegionShortcut = clientRegionShortcut;
|
||||
this.dataPolicy = dataPolicy;
|
||||
}
|
||||
|
||||
public static ClientRegionShortcutWrapper valueOf(final ClientRegionShortcut clientRegionShortcut) {
|
||||
public static ClientRegionShortcutWrapper valueOf(ClientRegionShortcut clientRegionShortcut) {
|
||||
for (ClientRegionShortcutWrapper wrapper : values()) {
|
||||
if (ObjectUtils.nullSafeEquals(wrapper.getClientRegionShortcut(), clientRegionShortcut)) {
|
||||
return wrapper;
|
||||
@@ -57,7 +61,11 @@ public enum ClientRegionShortcutWrapper {
|
||||
}
|
||||
|
||||
public ClientRegionShortcut getClientRegionShortcut() {
|
||||
return clientRegionShortcut;
|
||||
return this.clientRegionShortcut;
|
||||
}
|
||||
|
||||
public DataPolicy getDataPolicy() {
|
||||
return this.dataPolicy;
|
||||
}
|
||||
|
||||
public boolean isCaching() {
|
||||
@@ -87,5 +95,4 @@ public enum ClientRegionShortcutWrapper {
|
||||
public boolean isProxy() {
|
||||
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;
|
||||
|
||||
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.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link PersistentEntity} implementation adding custom Gemfire related metadata, such as the region the entity is
|
||||
* mapped to etc.
|
||||
*
|
||||
* {@link PersistentEntity} implementation adding custom GemFire persistent entity related metadata, such as the
|
||||
* {@link org.apache.geode.cache.Region} to which the entity is mapped, etc.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @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> {
|
||||
|
||||
private final Annotation regionAnnotation;
|
||||
|
||||
private final String regionName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public GemfirePersistentEntity(TypeInformation<T> information) {
|
||||
/* (non-Javadoc) */
|
||||
protected static Annotation resolveRegionAnnotation(Class<?> persistentEntityType) {
|
||||
|
||||
super(information);
|
||||
for (Class<? extends Annotation> regionAnnotationType : Region.REGION_ANNOTATION_TYPES) {
|
||||
Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation(
|
||||
persistentEntityType, regionAnnotationType);
|
||||
|
||||
Class<T> rawType = information.getType();
|
||||
Region region = rawType.getAnnotation(Region.class);
|
||||
String defaultRegionName = rawType.getSimpleName();
|
||||
if (regionAnnotation != null) {
|
||||
return regionAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
this.regionName = (region != null && StringUtils.hasText(region.value()) ? region.value() : defaultRegionName);
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the region the entity shall be stored in.
|
||||
*
|
||||
* @return the name of the region the entity shall be stored in.
|
||||
* Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public GemfirePersistentEntity(TypeInformation<T> information) {
|
||||
super(information);
|
||||
|
||||
Class<T> rawType = information.getType();
|
||||
|
||||
this.regionAnnotation = resolveRegionAnnotation(rawType);
|
||||
this.regionName = resolveRegionName(rawType, this.regionAnnotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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() {
|
||||
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
|
||||
* 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 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 John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@SuppressWarnings("unused")
|
||||
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
|
||||
* shall be stored in (e.g. "Users", or "/Local/Admin/Users").
|
||||
* 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").
|
||||
*
|
||||
* @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 "";
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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.util.Arrays;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* The ArrayUtils class is a utility class for working with Object arrays.
|
||||
*
|
||||
@@ -37,6 +39,18 @@ public abstract class ArrayUtils {
|
||||
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}
|
||||
* if the array is {@literal null} or empty.
|
||||
|
||||
@@ -46,6 +46,28 @@ import org.springframework.util.Assert;
|
||||
@SuppressWarnings("unused")
|
||||
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.
|
||||
*
|
||||
@@ -60,6 +82,32 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
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.
|
||||
*
|
||||
@@ -140,6 +188,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Collections#emptyMap()
|
||||
* @see java.util.Map
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public static <K, V> Map<K, V> nullSafeMap(Map<K, V> map) {
|
||||
return (map != null ? map : Collections.emptyMap());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user