SGF-583 - Provide InterestBuilder class to appropriately and flexibly express interests in keys/values between client/server.
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.data.gemfire.client;
|
||||
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.geode.cache.CacheListener;
|
||||
@@ -40,13 +42,11 @@ import org.springframework.data.gemfire.DataPolicyConverter;
|
||||
import org.springframework.data.gemfire.GemfireUtils;
|
||||
import org.springframework.data.gemfire.RegionLookupFactoryBean;
|
||||
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring {@link FactoryBean} used to create a GemFire client {@link Region}.
|
||||
* Spring {@link FactoryBean} used to create a GemFire client cache {@link Region}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author David Turanski
|
||||
@@ -55,16 +55,15 @@ import org.springframework.util.StringUtils;
|
||||
* @see org.springframework.beans.factory.BeanFactoryAware
|
||||
* @see org.springframework.beans.factory.DisposableBean
|
||||
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
|
||||
* @see org.apache.geode.cache.CacheListener
|
||||
* @see org.apache.geode.cache.CacheLoader
|
||||
* @see org.apache.geode.cache.CacheWriter
|
||||
* @see org.apache.geode.cache.DataPolicy
|
||||
* @see org.apache.geode.cache.EvictionAttributes
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.RegionAttributes
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.ClientRegionFactory
|
||||
* @see org.apache.geode.cache.client.ClientRegionShortcut
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
@@ -284,7 +283,7 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
clientRegionFactory.addCacheListener(cacheListener);
|
||||
}
|
||||
|
||||
for (CacheListener<K, V> cacheListener : ArrayUtils.nullSafeArray(this.cacheListeners, CacheListener.class)) {
|
||||
for (CacheListener<K, V> cacheListener : nullSafeArray(this.cacheListeners, CacheListener.class)) {
|
||||
clientRegionFactory.addCacheListener(cacheListener);
|
||||
}
|
||||
|
||||
@@ -295,7 +294,7 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, V> CacheListener<K, V>[] attributesCacheListeners() {
|
||||
CacheListener[] cacheListeners = (this.attributes != null ? this.attributes.getCacheListeners() : null);
|
||||
return ArrayUtils.nullSafeArray(cacheListeners, CacheListener.class);
|
||||
return nullSafeArray(cacheListeners, CacheListener.class);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@@ -375,17 +374,16 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
private Region<K, V> registerInterests(Region<K, V> region) {
|
||||
if (!ObjectUtils.isEmpty(interests)) {
|
||||
for (Interest<K> interest : interests) {
|
||||
if (interest instanceof RegexInterest) {
|
||||
region.registerInterestRegex((String) interest.getKey(), interest.getPolicy(),
|
||||
interest.isDurable(), interest.isReceiveValues());
|
||||
}
|
||||
else {
|
||||
region.registerInterest(interest.getKey(), interest.getPolicy(), interest.isDurable(),
|
||||
interest.isReceiveValues());
|
||||
}
|
||||
for (Interest<K> interest : nullSafeArray(interests, Interest.class)) {
|
||||
if (interest.isRegexType()) {
|
||||
region.registerInterestRegex((String) interest.getKey(), interest.getPolicy(),
|
||||
interest.isDurable(), interest.isReceiveValues());
|
||||
}
|
||||
else {
|
||||
region.registerInterest(interest.getKey(), interest.getPolicy(), interest.isDurable(),
|
||||
interest.isReceiveValues());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
|
||||
package org.springframework.data.gemfire.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.geode.cache.InterestResultPolicy;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
@@ -26,15 +32,24 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
* @see java.util.regex.Pattern
|
||||
* @see org.apache.geode.cache.InterestResultPolicy
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
* @see org.springframework.core.Constants
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class Interest<K> implements InitializingBean {
|
||||
|
||||
public static final String ALL_KEYS = "ALL_KEYS";
|
||||
|
||||
protected static final boolean DEFAULT_DURABLE = false;
|
||||
protected static final boolean DEFAULT_RECEIVE_VALUES = true;
|
||||
|
||||
private static final Constants constants = new Constants(InterestResultPolicy.class);
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private boolean durable = false;
|
||||
private boolean receiveValues = true;
|
||||
|
||||
@@ -42,33 +57,69 @@ public class Interest<K> implements InitializingBean {
|
||||
|
||||
private K key;
|
||||
|
||||
public Interest() {
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* Factory method to construct a new instance of {@link Interest} initialized with the given key.
|
||||
*
|
||||
* @param <K> {@link Class} type of the key.
|
||||
* @param key key of interest.
|
||||
* @return a new instance of {@link Interest} initialized with the given key.
|
||||
* @see #Interest(Object)
|
||||
*/
|
||||
public static <K> Interest newInterest(K key) {
|
||||
return new Interest<>(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of non-durable {@link Interest} initialized with the given key to register interest in,
|
||||
* using the {@link InterestResultPolicy#DEFAULT} to initialize the client cache and receiving values by default.
|
||||
*
|
||||
* @param key key(s) of interest.
|
||||
* @see #Interest(Object, InterestResultPolicy, boolean, boolean)
|
||||
*/
|
||||
public Interest(K key) {
|
||||
this(key, InterestResultPolicy.DEFAULT, false);
|
||||
}
|
||||
|
||||
public Interest(K key, String policy) {
|
||||
this(key, policy, false);
|
||||
}
|
||||
|
||||
public Interest(K key, String policy, boolean durable) {
|
||||
this(key, policy, false, true);
|
||||
}
|
||||
|
||||
public Interest(K key, String policy, boolean durable, boolean receiveValues) {
|
||||
this(key, (InterestResultPolicy) constants.asObject(policy), durable, receiveValues);
|
||||
this(key, InterestResultPolicy.DEFAULT, DEFAULT_DURABLE, DEFAULT_RECEIVE_VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of non-durable {@link Interest} initialized with the given key to register interest in,
|
||||
* the given {@link InterestResultPolicy} used to initialize the client cache, receiving values by default.
|
||||
*
|
||||
* @param key key(s) of interest.
|
||||
* @param policy initial {@link InterestResultPolicy} used to initialize the client cache.
|
||||
* @see #Interest(Object, InterestResultPolicy, boolean, boolean)
|
||||
*/
|
||||
public Interest(K key, InterestResultPolicy policy) {
|
||||
this(key, policy, false);
|
||||
this(key, policy, DEFAULT_DURABLE, DEFAULT_RECEIVE_VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link Interest} initialized with the given key to register interest in,
|
||||
* the given {@link InterestResultPolicy} used to initialize the client cache, the given boolean value
|
||||
* to indicate whether interest registration should be durable, receiving values by default.
|
||||
*
|
||||
* @param key key(s) of interest.
|
||||
* @param policy initial {@link InterestResultPolicy} used to initialize the client cache.
|
||||
* @param durable boolean value to indicate whether the interest registration should be durable.
|
||||
* @see #Interest(Object, InterestResultPolicy, boolean, boolean)
|
||||
*/
|
||||
public Interest(K key, InterestResultPolicy policy, boolean durable) {
|
||||
this(key, policy, durable, true);
|
||||
this(key, policy, durable, DEFAULT_RECEIVE_VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link Interest} initialized with the given key to register interest in,
|
||||
* the given {@link InterestResultPolicy} used to initialize the client cache and the given boolean values
|
||||
* indicating whether interest registration should be durable and whether to receive values during notifications.
|
||||
*
|
||||
* @param key key(s) of interest.
|
||||
* @param policy initial {@link InterestResultPolicy} used to initialize the client cache.
|
||||
* @param durable boolean value to indicate whether the interest registration should be durable.
|
||||
* @param receiveValues boolean value to indicate whether to receive value in notifications.
|
||||
* @see #Interest(Object, InterestResultPolicy, boolean, boolean)
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public Interest(K key, InterestResultPolicy policy, boolean durable, boolean receiveValues) {
|
||||
this.key = key;
|
||||
this.policy = policy;
|
||||
@@ -78,43 +129,189 @@ public class Interest<K> implements InitializingBean {
|
||||
afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(key, "a non-null key is required");
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #Interest(Object, InterestResultPolicy)
|
||||
*/
|
||||
@Deprecated
|
||||
public Interest(K key, String policy) {
|
||||
this(key, policy, DEFAULT_DURABLE, DEFAULT_RECEIVE_VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of interest.
|
||||
* @deprecated
|
||||
* @see #Interest(Object, InterestResultPolicy, boolean)
|
||||
*/
|
||||
@Deprecated
|
||||
public Interest(K key, String policy, boolean durable) {
|
||||
this(key, policy, durable, DEFAULT_RECEIVE_VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #Interest(Object, InterestResultPolicy, boolean, boolean)
|
||||
*/
|
||||
@Deprecated
|
||||
public Interest(K key, String policy, boolean durable, boolean receiveValues) {
|
||||
this(key, (InterestResultPolicy) constants.asObject(policy), durable, receiveValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(key, "Key is required");
|
||||
setType(resolveType(getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the {@link Interest.Type} based on the configured {@link #getKey()}.
|
||||
*
|
||||
* @return the key
|
||||
* @param type provided {@link Interest.Type} used if {@literal non-null}.
|
||||
* @return the resolved {@link Interest.Type}.
|
||||
* @see #isRegularExpression(Object)
|
||||
*/
|
||||
protected Type resolveType(Type type) {
|
||||
return (type != null ? type : (isRegularExpression(getKey()) ? Type.REGEX : Type.KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code key} is a Regular Expression (Regex).
|
||||
*
|
||||
* If the given {@code key} is {@literal "ALL_KEYS"}, a {@link List} or only contains letters, numbers and spaces,
|
||||
* then the {@code key} is not considered a Regular Expression by GemFire, and can be handled with normal
|
||||
* interest registration using {@link org.apache.geode.cache.Region#registerInterest(Object)}.
|
||||
*
|
||||
* @param key {@link Object} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@link Object} {@code key} is a Regular Expression.
|
||||
* @see #isRegularExpression(String)
|
||||
*/
|
||||
protected boolean isRegularExpression(Object key) {
|
||||
return (!(ALL_KEYS.equals(key) || key instanceof List) && isRegularExpression(String.valueOf(key)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code key} is a Regular Expression (Regex).
|
||||
*
|
||||
* If the given {@code value} contains at least 1 special character (e.g. *) and can be compiled
|
||||
* using {@link Pattern#compile(String)}, then the {@code key} is considered a Regular Expression
|
||||
* and interest will be registered using {@link org.apache.geode.cache.Region#registerInterestRegex(String)}.
|
||||
*
|
||||
* @param key {@link String} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@link String} {@code value} is a Regular Expression.
|
||||
* @see #containsNonAlphaNumericWhitespace(String)
|
||||
* @see java.util.regex.Pattern#compile(String)
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
protected boolean isRegularExpression(String value) {
|
||||
try {
|
||||
return (containsNonAlphaNumericWhitespace(value) && Pattern.compile(value) != null);
|
||||
}
|
||||
catch (PatternSyntaxException ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@link String} value contains at least 1 special character.
|
||||
*
|
||||
* @param value {@link String} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@link String} contains at least 1 special character,
|
||||
* a non-alphanumeric, non-whitespace character.
|
||||
* @see #isAlphaNumericWhitespace(char)
|
||||
* @see #isNotAlphaNumericWhitespace(char)
|
||||
*/
|
||||
protected boolean containsNonAlphaNumericWhitespace(String value) {
|
||||
for (char character : String.valueOf(value).toCharArray()) {
|
||||
if (isNotAlphaNumericWhitespace(character)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code character} is a special character (non-alphanumeric, non-whitespace).
|
||||
*
|
||||
* @param character {@link Character} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@code character} is a special character.
|
||||
* @see #isAlphaNumericWhitespace(char)
|
||||
*/
|
||||
protected boolean isNotAlphaNumericWhitespace(char character) {
|
||||
return !isAlphaNumericWhitespace(character);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@code character} is an alphanumeric or whitespace character.
|
||||
*
|
||||
* @param character {@link Character} to evaluate.
|
||||
* @return a boolean value indicating whether the given {@code character} is an alphanumeric
|
||||
* or whitespace character.
|
||||
* @see java.lang.Character#isDigit(char)
|
||||
* @see java.lang.Character#isLetter(char)
|
||||
* @see java.lang.Character#isWhitespace(char)
|
||||
*/
|
||||
protected boolean isAlphaNumericWhitespace(char character) {
|
||||
return (Character.isDigit(character) || Character.isLetter(character) || Character.isWhitespace(character));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the interest registration is durable and persists between cache client sessions.
|
||||
*
|
||||
* @return a boolean value indicating whether this interest registration is durable.
|
||||
*/
|
||||
public boolean isDurable() {
|
||||
return this.durable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether interest registration is durable and persists between cache client sessions.
|
||||
*
|
||||
* @param durable boolean value to indicate whether this interest registration is durable.
|
||||
*/
|
||||
public void setDurable(boolean durable) {
|
||||
this.durable = durable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key on which interest is registered.
|
||||
*
|
||||
* @return the key of interest.
|
||||
*/
|
||||
public K getKey() {
|
||||
return key;
|
||||
return this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key of interest.
|
||||
* Sets the key on which interest is registered.
|
||||
*
|
||||
* @param key the key to set
|
||||
* @param key the key of interest.
|
||||
*/
|
||||
public void setKey(K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interest policy.
|
||||
* Returns the {@link InterestResultPolicy} used when interest is registered and determines whether KEYS,
|
||||
* KEYS_VALUES or nothing (NONE) is initially fetched on initial registration.
|
||||
*
|
||||
* @return the policy
|
||||
*/
|
||||
public InterestResultPolicy getPolicy() {
|
||||
return policy;
|
||||
return this.policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interest policy. The argument is set as an Object
|
||||
* to be able to accept both InterestResultType instances but also
|
||||
* Strings (for XML configurations).
|
||||
* Sets the initial {@link InterestResultPolicy} used when interest is first registered and determines whether KEYS,
|
||||
* KEYS_VALUE or nothing (NONE) is initially fetched.
|
||||
*
|
||||
* @param policy the policy to set
|
||||
* The argument is set as an {@link Object} to be able to accept both {@link InterestResultPolicy}
|
||||
* and {@link String Strings}, used in XML configuration meta-data.
|
||||
*
|
||||
* @param policy initial {@link InterestResultPolicy} to set.
|
||||
* @throws IllegalArgumentException if the given {@code policy} is not a valid type.
|
||||
* @see org.apache.geode.cache.InterestResultPolicy
|
||||
*/
|
||||
public void setPolicy(Object policy) {
|
||||
if (policy instanceof InterestResultPolicy) {
|
||||
@@ -124,36 +321,18 @@ public class Interest<K> implements InitializingBean {
|
||||
this.policy = (InterestResultPolicy) constants.asObject(String.valueOf(policy));
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(String.format("Unknown argument type (%1$s) for property 'policy'!",
|
||||
policy));
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unknown argument type [%s] for property 'policy'", policy));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interest durability.
|
||||
*
|
||||
* @return the durable
|
||||
*/
|
||||
public boolean isDurable() {
|
||||
return durable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interest durability.
|
||||
*
|
||||
* @param durable the durable to set
|
||||
*/
|
||||
public void setDurable(boolean durable) {
|
||||
this.durable = durable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of values received by the listener.
|
||||
*
|
||||
* @return the receiveValues
|
||||
*/
|
||||
public boolean isReceiveValues() {
|
||||
return receiveValues;
|
||||
return this.receiveValues;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,4 +344,128 @@ public class Interest<K> implements InitializingBean {
|
||||
this.receiveValues = receiveValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of interest registration (e.g. based on KEY or Regex).
|
||||
*
|
||||
* @return a {@link Interest.Type} determining the type of interest.
|
||||
* @see Interest.Type
|
||||
*/
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of interest registration (e.g. based on KEY or Regex).
|
||||
*
|
||||
* @param type {@link Interest.Type} qualifying the type of interest.
|
||||
* @see Interest.Type
|
||||
*/
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this {@link Interest} is a KEY interest registration.
|
||||
*
|
||||
* @return a boolean value indicating whether this is KEY interest.
|
||||
* @see Interest.Type#KEY
|
||||
* @see #getType()
|
||||
*/
|
||||
public boolean isKeyType() {
|
||||
return Type.KEY.equals(getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this {@link Interest} is a REGEX interest registration.
|
||||
*
|
||||
* @return a boolean value indicating whether this is REGEX interest.
|
||||
* @see Interest.Type#REGEX
|
||||
* @see #getType()
|
||||
*/
|
||||
public boolean isRegexType() {
|
||||
return Type.REGEX.equals(getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{ @type = %1$s, key = %2$s, durable = %3$s, policy = %4$s, receiveValues = %5$s, type = %6$s }",
|
||||
getClass().getName(), getKey(), isDurable(), getPolicy(), isReceiveValues(), getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method to specify the type of interest registration.
|
||||
*
|
||||
* @param type {@link Interest.Type} of interest registration.
|
||||
* @return this {@link Interest}.
|
||||
* @see Interest.Type
|
||||
* @see #resolveType(Type)
|
||||
* @see #setType(Type)
|
||||
*/
|
||||
public Interest asType(Type type) {
|
||||
setType(resolveType(type));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method to mark this {@link Interest} as durable.
|
||||
*
|
||||
* @return this {@link Interest}.
|
||||
* @see #setDurable(boolean)
|
||||
*/
|
||||
public Interest makeDurable() {
|
||||
setDurable(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method to set whether the interest event notifications will receive values along with keys.
|
||||
*
|
||||
* @param receiveValues boolean to indicate that value should be sent along with keys
|
||||
* on interest event notifications.
|
||||
* @return this {@link Interest}.
|
||||
* @see #setReceiveValues(boolean)
|
||||
*/
|
||||
public Interest receivesValues(boolean receiveValues) {
|
||||
setReceiveValues(receiveValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method to set the {@link InterestResultPolicy} used to initialize the cache.
|
||||
*
|
||||
* @param policy {@link InterestResultPolicy}.
|
||||
* @return this {@link Interest}.
|
||||
* @see org.apache.geode.cache.InterestResultPolicy
|
||||
* @see #setPolicy(Object)
|
||||
*/
|
||||
public Interest usingPolicy(InterestResultPolicy policy) {
|
||||
setPolicy(policy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder method to express the key of interest.
|
||||
*
|
||||
* @param key key of interests.
|
||||
* @return this {@link Interest}.
|
||||
* @see #setKey(Object)
|
||||
* @see #getType()
|
||||
* @see #resolveType(Type)
|
||||
* @see #setType(Type)
|
||||
*/
|
||||
public Interest withKey(K key) {
|
||||
setKey(key);
|
||||
setType(resolveType(getType()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of interest registration.
|
||||
*/
|
||||
public enum Type {
|
||||
KEY, REGEX
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.client;
|
||||
|
||||
import org.apache.geode.cache.InterestResultPolicy;
|
||||
|
||||
/**
|
||||
* Cache Region interest based on individual keys.
|
||||
*
|
||||
* @author John Blum
|
||||
* @param <K> {@link Class} type of the key.
|
||||
* @see org.springframework.data.gemfire.client.Interest
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class KeyInterest<K> extends Interest<K> {
|
||||
|
||||
public KeyInterest(K key) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
public KeyInterest(K key, InterestResultPolicy policy) {
|
||||
super(key, policy);
|
||||
}
|
||||
|
||||
public KeyInterest(K key, InterestResultPolicy policy, boolean durable) {
|
||||
super(key, policy, durable);
|
||||
}
|
||||
|
||||
public KeyInterest(K key, InterestResultPolicy policy, boolean durable, boolean recieveValues) {
|
||||
super(key, policy, durable, recieveValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
logger.warn(String.format("Setting the Type [%1$s] of interest on [%2$s] is ignored",
|
||||
type, getClass().getName()));
|
||||
}
|
||||
}
|
||||
@@ -16,29 +16,69 @@
|
||||
|
||||
package org.springframework.data.gemfire.client;
|
||||
|
||||
import org.apache.geode.cache.InterestResultPolicy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Cache interest based on regular expression rather then individual key types.
|
||||
*
|
||||
* Cache interest based on regular expression rather then individual key types.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.client.Interest
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RegexInterest extends Interest<String> {
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
Assert.hasText(getKey(), "A non-empty regex is required");
|
||||
public RegexInterest(String regex) {
|
||||
super(regex);
|
||||
}
|
||||
|
||||
public RegexInterest(String regex, InterestResultPolicy policy) {
|
||||
super(regex, policy);
|
||||
}
|
||||
|
||||
public RegexInterest(String regex, InterestResultPolicy policy, boolean durable) {
|
||||
super(regex, policy, durable);
|
||||
}
|
||||
|
||||
public RegexInterest(String regex, InterestResultPolicy policy, boolean durable, boolean receiveValues) {
|
||||
super(regex, policy, durable, receiveValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the regex backing this interest.
|
||||
* Similar to {@link #getKey()}.
|
||||
*
|
||||
* @return interest regex
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.hasText(getKey(), "Regex is required");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Regular Expression sent to the cache server to express interests in keys matching Regex pattern.
|
||||
*
|
||||
* Alias for {@link #getKey()}.
|
||||
*
|
||||
* @return the Regex pattern used in the interest registration.
|
||||
* @see org.apache.geode.cache.Region#registerInterestRegex(String)
|
||||
*/
|
||||
//TODO: is this really required
|
||||
public String getRegex() {
|
||||
return getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.REGEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
logger.warn(String.format("Setting the Type [%1$s] of interest on [%2$s] is ignored",
|
||||
type, getClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.Interest;
|
||||
import org.springframework.data.gemfire.client.KeyInterest;
|
||||
import org.springframework.data.gemfire.client.RegexInterest;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -139,18 +141,19 @@ class ClientRegionParser extends AbstractRegionParser {
|
||||
/* (non-Javadoc) */
|
||||
private void parseCommonInterestAttributes(Element element, BeanDefinitionBuilder builder) {
|
||||
ParsingUtils.setPropertyValue(element, builder, "durable", "durable");
|
||||
ParsingUtils.setPropertyValue(element, builder, "result-policy", "policy");
|
||||
ParsingUtils.setPropertyValue(element, builder, "receive-values", "receiveValues");
|
||||
ParsingUtils.setPropertyValue(element, builder, "result-policy", "policy");
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private Object parseKeyInterest(Element keyInterestElement, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder keyInterestBuilder = BeanDefinitionBuilder.genericBeanDefinition(Interest.class);
|
||||
BeanDefinitionBuilder keyInterestBuilder = BeanDefinitionBuilder.genericBeanDefinition(KeyInterest.class);
|
||||
|
||||
parseCommonInterestAttributes(keyInterestElement, keyInterestBuilder);
|
||||
keyInterestBuilder.addConstructorArgValue(ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext,
|
||||
keyInterestElement, keyInterestBuilder, "key-ref"));
|
||||
|
||||
parseCommonInterestAttributes(keyInterestElement, keyInterestBuilder);
|
||||
|
||||
return keyInterestBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@@ -158,8 +161,9 @@ class ClientRegionParser extends AbstractRegionParser {
|
||||
private Object parseRegexInterest(Element regexInterestElement) {
|
||||
BeanDefinitionBuilder regexInterestBuilder = BeanDefinitionBuilder.genericBeanDefinition(RegexInterest.class);
|
||||
|
||||
regexInterestBuilder.addConstructorArgValue(regexInterestElement.getAttribute("pattern"));
|
||||
|
||||
parseCommonInterestAttributes(regexInterestElement, regexInterestBuilder);
|
||||
ParsingUtils.setPropertyValue(regexInterestElement, regexInterestBuilder, "pattern", "key");
|
||||
|
||||
return regexInterestBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see java.lang.reflect.Array
|
||||
* @see java.util.Arrays
|
||||
*/
|
||||
public abstract class ArrayUtils {
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
|
||||
* @see java.util.Enumeration
|
||||
*/
|
||||
public static <T> Iterable<T> iterable(Enumeration<T> enumeration) {
|
||||
return () -> org.springframework.util.CollectionUtils.toIterator(enumeration);
|
||||
return () -> toIterator(enumeration);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package org.springframework.data.gemfire.util;
|
||||
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -37,11 +39,9 @@ public abstract class SpringUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static BeanDefinition addDependsOn(BeanDefinition bean, String beanName) {
|
||||
String[] dependsOn = bean.getDependsOn();
|
||||
List<String> dependsOnList = new ArrayList<String>();
|
||||
|
||||
Collections.addAll(dependsOnList, ArrayUtils.nullSafeArray(dependsOn, String.class));
|
||||
List<String> dependsOnList = new ArrayList<>();
|
||||
|
||||
Collections.addAll(dependsOnList, nullSafeArray(bean.getDependsOn(), String.class));
|
||||
dependsOnList.add(beanName);
|
||||
bean.setDependsOn(dependsOnList.toArray(new String[dependsOnList.size()]));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user