From fa00bd68449f6119ee40bb3eea759ebc61267d0f Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 5 Jan 2017 20:54:59 -0800 Subject: [PATCH] SGF-583 - Provide InterestBuilder class to appropriately and flexibly express interests in keys/values between client/server. (cherry picked from commit 734fab75b0a33f3fa80dc95ca3f6dceb132e78a9) Signed-off-by: John Blum --- .../client/ClientRegionFactoryBean.java | 35 +- .../data/gemfire/client/Interest.java | 405 ++- .../data/gemfire/client/KeyInterest.java | 64 + .../data/gemfire/client/RegexInterest.java | 62 +- .../config/xml/ClientRegionParser.java | 12 +- .../data/gemfire/util/ArrayUtils.java | 1 + .../data/gemfire/util/CollectionUtils.java | 48 +- .../data/gemfire/util/SpringUtils.java | 8 +- src/main/resources/META-INF/spring.schemas | 8 +- ...re-1.8.xsd => spring-data-gemfire-2.0.xsd} | 5 +- ...gemfire-1.8.xsd => spring-gemfire-2.0.xsd} | 2169 ++++++++--------- .../data/gemfire/config/spring-geode-1.0.xsd | 2 +- .../data/gemfire/client/InterestTest.java | 104 - .../gemfire/client/InterestUnitTests.java | 353 +++ .../config/xml/ClientRegionNamespaceTest.java | 6 +- .../util/CollectionUtilsUnitTests.java | 10 +- 16 files changed, 1831 insertions(+), 1461 deletions(-) create mode 100644 src/main/java/org/springframework/data/gemfire/client/KeyInterest.java rename src/main/resources/org/springframework/data/gemfire/config/{spring-data-gemfire-1.8.xsd => spring-data-gemfire-2.0.xsd} (99%) rename src/main/resources/org/springframework/data/gemfire/config/{spring-gemfire-1.8.xsd => spring-gemfire-2.0.xsd} (88%) delete mode 100644 src/test/java/org/springframework/data/gemfire/client/InterestTest.java create mode 100644 src/test/java/org/springframework/data/gemfire/client/InterestUnitTests.java diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java index 49ffd5f6..1cf137f5 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java @@ -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 extends RegionLookupFactoryBean @@ -284,7 +283,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean clientRegionFactory.addCacheListener(cacheListener); } - for (CacheListener cacheListener : ArrayUtils.nullSafeArray(this.cacheListeners, CacheListener.class)) { + for (CacheListener cacheListener : nullSafeArray(this.cacheListeners, CacheListener.class)) { clientRegionFactory.addCacheListener(cacheListener); } @@ -295,8 +294,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean @SuppressWarnings("unchecked") private CacheListener[] attributesCacheListeners() { CacheListener[] cacheListeners = (this.attributes != null ? this.attributes.getCacheListeners() : null); - - return ArrayUtils.nullSafeArray(cacheListeners, CacheListener.class); + return nullSafeArray(cacheListeners, CacheListener.class); } /* (non-Javadoc) */ @@ -376,17 +374,16 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean } /* (non-Javadoc) */ + @SuppressWarnings("unchecked") private Region registerInterests(Region region) { - if (!ObjectUtils.isEmpty(interests)) { - for (Interest 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 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()); } } diff --git a/src/main/java/org/springframework/data/gemfire/client/Interest.java b/src/main/java/org/springframework/data/gemfire/client/Interest.java index 885cf193..88718afe 100644 --- a/src/main/java/org/springframework/data/gemfire/client/Interest.java +++ b/src/main/java/org/springframework/data/gemfire/client/Interest.java @@ -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 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 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 {@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 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 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 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 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 + } } diff --git a/src/main/java/org/springframework/data/gemfire/client/KeyInterest.java b/src/main/java/org/springframework/data/gemfire/client/KeyInterest.java new file mode 100644 index 00000000..81abe1e9 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/client/KeyInterest.java @@ -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 {@link Class} type of the key. + * @see org.springframework.data.gemfire.client.Interest + */ +@SuppressWarnings("unused") +public class KeyInterest extends Interest { + + 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())); + } +} diff --git a/src/main/java/org/springframework/data/gemfire/client/RegexInterest.java b/src/main/java/org/springframework/data/gemfire/client/RegexInterest.java index a7bd0cad..8e8595de 100644 --- a/src/main/java/org/springframework/data/gemfire/client/RegexInterest.java +++ b/src/main/java/org/springframework/data/gemfire/client/RegexInterest.java @@ -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 { - @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())); + } } diff --git a/src/main/java/org/springframework/data/gemfire/config/xml/ClientRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/xml/ClientRegionParser.java index 115815bc..62d7fd5b 100644 --- a/src/main/java/org/springframework/data/gemfire/config/xml/ClientRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/xml/ClientRegionParser.java @@ -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(); } diff --git a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java index cdd27d18..f071d107 100644 --- a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java @@ -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 { diff --git a/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java b/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java index 65d59a2f..8e69ec3c 100644 --- a/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java @@ -24,7 +24,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeMap; @@ -78,7 +77,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio */ @SafeVarargs public static Set asSet(T... elements) { - Set set = new HashSet(elements.length); + Set set = new HashSet<>(elements.length); Collections.addAll(set, elements); return Collections.unmodifiableSet(set); } @@ -118,12 +117,8 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @see java.lang.Iterable * @see java.util.Enumeration */ - public static Iterable iterable(final Enumeration enumeration) { - return new Iterable() { - @Override public Iterator iterator() { - return org.springframework.util.CollectionUtils.toIterator(enumeration); - } - }; + public static Iterable iterable(Enumeration enumeration) { + return () -> toIterator(enumeration); } /** @@ -135,12 +130,8 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @see java.lang.Iterable * @see java.util.Iterator */ - public static Iterable iterable(final Iterator iterator) { - return new Iterable() { - @Override public Iterator iterator() { - return iterator; - } - }; + public static Iterable iterable(Iterator iterator) { + return () -> iterator; } /** @@ -155,7 +146,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @see java.util.Collection */ public static Collection nullSafeCollection(Collection collection) { - return (collection != null ? collection : Collections.emptyList()); + return (collection != null ? collection : Collections.emptyList()); } /** @@ -169,26 +160,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @see java.util.Iterator */ public static Iterable nullSafeIterable(Iterable iterable) { - return (iterable != null ? iterable : new Iterable() { - @Override public Iterator iterator() { - return new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public T next() { - throw new NoSuchElementException("No more elements"); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("Operation not supported"); - } - }; - } - }); + return (iterable != null ? iterable : Collections::emptyIterator); } /** @@ -202,7 +174,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @see java.util.List */ public static List nullSafeList(List list) { - return (list != null ? list : Collections.emptyList()); + return (list != null ? list : Collections.emptyList()); } /** @@ -232,7 +204,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @see java.util.Set */ public static Set nullSafeSet(Set set) { - return (set != null ? set : Collections.emptySet()); + return (set != null ? set : Collections.emptySet()); } /** @@ -265,7 +237,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio public static List subList(List source, int... indices) { Assert.notNull(source, "List must not be null"); - List result = new ArrayList(indices.length); + List result = new ArrayList<>(indices.length); for (int index : indices) { result.add(source.get(index)); diff --git a/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java b/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java index 67a982ab..1de6f58d 100644 --- a/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java @@ -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 dependsOnList = new ArrayList(); - - Collections.addAll(dependsOnList, ArrayUtils.nullSafeArray(dependsOn, String.class)); + List dependsOnList = new ArrayList<>(); + Collections.addAll(dependsOnList, nullSafeArray(bean.getDependsOn(), String.class)); dependsOnList.add(beanName); bean.setDependsOn(dependsOnList.toArray(new String[dependsOnList.size()])); diff --git a/src/main/resources/META-INF/spring.schemas b/src/main/resources/META-INF/spring.schemas index b88d182a..694dae05 100644 --- a/src/main/resources/META-INF/spring.schemas +++ b/src/main/resources/META-INF/spring.schemas @@ -1,8 +1,8 @@ -http\://www.springframework.org/schema/gemfire/spring-gemfire-1.8.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.8.xsd +http\://www.springframework.org/schema/gemfire/spring-gemfire-2.0.xsd=org/springframework/data/gemfire/config/spring-gemfire-2.0.xsd http\://www.springframework.org/schema/geode/spring-geode-1.0.xsd=org/springframework/data/gemfire/config/spring-geode-1.0.xsd -http\://www.springframework.org/schema/gemfire/spring-gemfire.xsd=org/springframework/data/gemfire/config/spring-gemfire-1.8.xsd +http\://www.springframework.org/schema/gemfire/spring-gemfire.xsd=org/springframework/data/gemfire/config/spring-gemfire-2.0.xsd http\://www.springframework.org/schema/geode/spring-geode.xsd=org/springframework/data/gemfire/config/spring-geode-1.0.xsd -http\://www.springframework.org/schema/data/gemfire/spring-data-gemfire-1.8.xsd=org/springframework/data/gemfire/config/spring-data-gemfire-1.8.xsd +http\://www.springframework.org/schema/data/gemfire/spring-data-gemfire-2.0.xsd=org/springframework/data/gemfire/config/spring-data-gemfire-2.0.xsd http\://www.springframework.org/schema/data/geode/spring-data-geode-1.0.xsd=org/springframework/data/gemfire/config/spring-data-geode-1.0.xsd -http\://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd=org/springframework/data/gemfire/config/spring-data-gemfire-1.8.xsd +http\://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd=org/springframework/data/gemfire/config/spring-data-gemfire-2.0.xsd http\://www.springframework.org/schema/data/geode/spring-data-geode.xsd=org/springframework/data/gemfire/config/spring-data-geode-1.0.xsd diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.8.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-2.0.xsd similarity index 99% rename from src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.8.xsd rename to src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-2.0.xsd index 2fb6b92f..8ddd8729 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.8.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-2.0.xsd @@ -1,6 +1,5 @@ + version="2.0"> @@ -175,6 +174,7 @@ native GemFire PdxInstance type. True, by default but will incur significant ove + + + version="2.0"> @@ -18,13 +15,33 @@ Namespace support for the Spring GemFire project. ]]> - + + + + + + + + + + + + + + + + @@ -32,7 +49,7 @@ and may be nested or referenced. @@ -40,14 +57,14 @@ and may be nested or referenced. + type="org.apache.geode.cache.util.GatewayConflictResolver" /> @@ -162,21 +179,21 @@ or copies of the objects (true). @@ -232,7 +249,7 @@ do not need to pay the cost of preserving the unread fields since you will never - + - + @@ -325,7 +342,7 @@ with Spring configuration meta-data that is specific to the application's needs. - + - + @@ -387,62 +404,30 @@ Notifies the server that this durable client is ready to receive updates. - - + + - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - + @@ -469,7 +454,7 @@ Defines a lookup Subregion - - + @@ -505,19 +490,19 @@ use inner bean declarations. - - + - - + @@ -557,7 +542,7 @@ Time to live configuration for the region entries. Default: no expiration. - + - + - - - - - - - - - - - - - - - - - - - - - - - - + @@ -727,13 +689,13 @@ use inner bean declarations. - - + @@ -764,7 +726,7 @@ Time to live configuration for the region entries. Default: no expiration. - + - + + + + + + - - + - - + @@ -1071,15 +1042,6 @@ Specifies if WAN Gateway hub id if enable-gateway is true. (Deprecated since Gem ]]> - - - - - - - - - - @@ -1130,7 +1083,7 @@ Defines a template for creating multiple GemFire Regions that all share a common ]]> - + @@ -1198,46 +1151,114 @@ distributed system with the mcast-port gemfire.properties setting. - - + + - + - + - + - + - + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Eviction policy for the partitioned region. + ]]> - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Specifies the data policy for this region (NORMAL or PRELOADED). Setting 'data-policy' is not stictly necessary, +but if set, then the value must agree with the 'persistent' attribute if also specified. + ]]> - - - + + - - - - - - - - - - - - - - - - + + + + + @@ -1315,17 +1466,17 @@ The RegionShortcut for this region. Allows easy initialization of the region bas - + - + - + - + - + - - + - - + + - + @@ -1372,13 +1523,13 @@ in different members, for high availability in case of an application failure. - - + @@ -1386,13 +1537,13 @@ colocate data based on custom criterias (such as colocating trades by month and - + @@ -1419,7 +1570,7 @@ use inner bean declarations. @@ -1428,7 +1579,7 @@ use inner bean declarations. use="required"> @@ -1437,7 +1588,7 @@ Specifies the fixed partition name default="true"> @@ -1445,7 +1596,7 @@ Specifies if this member is primary for this partition @@ -1629,29 +1780,40 @@ Defines a template for creating multiple GemFire PARTITION Regions that all shar ]]> - + - - + + - - + - + + + + + + + + + - + - + + +Specifies the data policy for this region (EMPTY, REPLICATE, PERSISTENT_REPLICATE). Setting 'data-policy' is not +stictly necessary, but if set, then the value must agree with the 'persistent' attribute if also specified. + ]]> - - + + + + + + + + + + + + + - - - - - + + + + + + @@ -1722,17 +1904,17 @@ The RegionShortcut for this region. Allows easy initialization of the region bas - + - + - + - + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -1845,7 +1954,7 @@ Note: the directory must already exist. ]]> - + @@ -1961,348 +2070,312 @@ The name of the bean defining the GemFire cache (by default 'gemfireCache'). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The name of the remote function bean referred by this declaration. Used as a convenience method. If no reference exists, +use inner bean declarations. + ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The name of the transaction manager definition (by default "gemfireTransactionManager").]]> - - - - - + - - - - - - - - - + - - - - - - - - + - + @@ -2380,6 +2453,118 @@ The name of the bean defining the CacheServer Load Probe. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -2502,227 +2687,7 @@ Whether the resulting GemFire continuous query is durable or not. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -2815,14 +2780,95 @@ Boolean value that determines whether GemFire persists the Gateway Queue or Asyn - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -2898,62 +2944,84 @@ Specifies the socket buffer size in bytes - + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2980,87 +3048,14 @@ The id of the cache - default is gemfireCache - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -3085,12 +3080,12 @@ Used for convenience. If no reference exists, use inner bean declarations. - - + @@ -3115,12 +3110,12 @@ Used for convenience. If no reference exists, use inner bean declarations. - - + @@ -3142,254 +3137,4 @@ Used for convenience. If no reference exists, use inner bean declarations. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-geode-1.0.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-geode-1.0.xsd index 0360861f..fd20d754 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-geode-1.0.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-geode-1.0.xsd @@ -2048,7 +2048,7 @@ Regular expression based interest. If the pattern is '.*' then all keys of any t - + diff --git a/src/test/java/org/springframework/data/gemfire/client/InterestTest.java b/src/test/java/org/springframework/data/gemfire/client/InterestTest.java deleted file mode 100644 index f5deb352..00000000 --- a/src/test/java/org/springframework/data/gemfire/client/InterestTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2010-2013 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 static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.apache.geode.cache.InterestResultPolicy; -import org.junit.Test; -import org.springframework.core.ConstantException; - -/** - * The InterestTest class is a test suite of test cases testing the contract and functionality of the Interest class. - * - * @author John Blum - * @see org.junit.Test - * @see org.springframework.data.gemfire.client.Interest - * @since 1.6.0 - */ -public class InterestTest { - - @Test - public void testConstruct() { - Interest interest = new Interest("aKey", "keys", true, false); - - assertEquals("aKey", interest.getKey()); - assertEquals(InterestResultPolicy.KEYS, interest.getPolicy()); - assertTrue(interest.isDurable()); - assertFalse(interest.isReceiveValues()); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructWithNullKey() { - try { - new Interest(null); - } - catch (IllegalArgumentException expected) { - assertEquals("a non-null key is required", expected.getMessage()); - throw expected; - } - } - - @Test(expected = ConstantException.class) - public void testConstructWithInvalidPolicy() { - new Interest("aKey", "INVALID"); - } - - @Test - public void testSetAndGetState() { - Interest interest = new Interest(); - - assertNull(interest.getKey()); - assertEquals(InterestResultPolicy.DEFAULT, interest.getPolicy()); - assertFalse(interest.isDurable()); - assertTrue(interest.isReceiveValues()); - - interest.setDurable(true); - interest.setKey("testKey"); - interest.setPolicy(InterestResultPolicy.KEYS_VALUES); - interest.setReceiveValues(false); - - assertEquals("testKey", interest.getKey()); - assertEquals(InterestResultPolicy.KEYS_VALUES, interest.getPolicy()); - assertTrue(interest.isDurable()); - assertFalse(interest.isReceiveValues()); - } - - @Test - public void testSetAndGetPolicy() { - Interest interest = new Interest(); - - assertEquals(InterestResultPolicy.DEFAULT, interest.getPolicy()); - - interest.setPolicy(InterestResultPolicy.NONE); - - assertEquals(InterestResultPolicy.NONE, interest.getPolicy()); - - interest.setPolicy("keys"); - - assertEquals(InterestResultPolicy.KEYS, interest.getPolicy()); - } - - @Test(expected = ConstantException.class) - public void testSetPolicyWithIllegalValue() { - new Interest().setPolicy("ILLEGAL"); - } - -} diff --git a/src/test/java/org/springframework/data/gemfire/client/InterestUnitTests.java b/src/test/java/org/springframework/data/gemfire/client/InterestUnitTests.java new file mode 100644 index 00000000..868acc3c --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/client/InterestUnitTests.java @@ -0,0 +1,353 @@ +/* + * Copyright 2010-2013 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 static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.springframework.data.gemfire.client.Interest.Type.KEY; +import static org.springframework.data.gemfire.client.Interest.Type.REGEX; +import static org.springframework.data.gemfire.client.Interest.newInterest; + +import java.util.List; + +import org.apache.geode.cache.InterestResultPolicy; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.springframework.core.ConstantException; + +/** + * Unit tests for {@link Interest}. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.InterestResultPolicy + * @see org.springframework.data.gemfire.client.Interest + * @since 1.6.0 + */ +public class InterestUnitTests { + + protected static final boolean DURABLE = true; + protected static final boolean DO_NOT_RECEIVE_VALUES = false; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Test + public void constructInterestWithKey() { + Interest interest = new Interest<>("testKey"); + + assertThat(interest.getKey()).isEqualTo("testKey"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.KEYS_VALUES); + assertThat(interest.isDurable()).isFalse(); + assertThat(interest.isReceiveValues()).isTrue(); + assertThat(interest.getType()).isEqualTo(KEY); + + String expectedString = String.format( + "{ @type = %s, key = testKey, durable = false, policy = KEYS_VALUES, receiveValues = true, type = KEY }", + interest.getClass().getName()); + + assertThat(interest.toString()).isEqualTo(expectedString); + } + + @Test + public void constructInterestWithKeyAndPolicy() { + Interest interest = new Interest<>("mockKey", InterestResultPolicy.KEYS); + + assertThat(interest.getKey()).isEqualTo("mockKey"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.KEYS); + assertThat(interest.isDurable()).isFalse(); + assertThat(interest.isReceiveValues()).isTrue(); + assertThat(interest.getType()).isEqualTo(KEY); + + String expectedString = String.format( + "{ @type = %s, key = mockKey, durable = false, policy = KEYS, receiveValues = true, type = KEY }", + interest.getClass().getName()); + + assertThat(interest.toString()).isEqualTo(expectedString); + } + + @Test + public void constructInterestWithKeyPolicyAndDurability() { + Interest interest = new Interest<>(".*Key", InterestResultPolicy.NONE, DURABLE); + + assertThat(interest.getKey()).isEqualTo(".*Key"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.NONE); + assertThat(interest.isDurable()).isTrue(); + assertThat(interest.isReceiveValues()).isTrue(); + assertThat(interest.getType()).isEqualTo(REGEX); + + String expectedString = String.format( + "{ @type = %s, key = .*Key, durable = true, policy = NONE, receiveValues = true, type = REGEX }", + interest.getClass().getName()); + + assertThat(interest.toString()).isEqualTo(expectedString); + } + + @Test + public void constructInterestWithKeyPolicyDurabilityAndReceiveValues() { + List keys = asList("KeyOne", "KeyTwo", "KeyThree"); + + Interest interest = new Interest<>(keys, InterestResultPolicy.KEYS_VALUES, + DURABLE, DO_NOT_RECEIVE_VALUES); + + assertThat(interest.getKey()).isEqualTo(keys); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.KEYS_VALUES); + assertThat(interest.isDurable()).isTrue(); + assertThat(interest.isReceiveValues()).isFalse(); + assertThat(interest.getType()).isEqualTo(Interest.Type.KEY); + + String expectedString = String.format( + "{ @type = %s, key = [KeyOne, KeyTwo, KeyThree], durable = true, policy = KEYS_VALUES, receiveValues = false, type = KEY }", + interest.getClass().getName()); + + assertThat(interest.toString()).isEqualTo(expectedString); + } + + @Test + public void constructInterestWithNullKey() { + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("Key is required"); + + new Interest<>(null); + } + + @Test + @SuppressWarnings("deprecation") + public void constructInterestWithStringPolicy() { + Interest interest = new Interest<>("mockKey", "nOnE"); + + assertThat(interest.getKey()).isEqualTo("mockKey"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.NONE); + assertThat(interest.getType()).isEqualTo(KEY); + } + + @Test(expected = ConstantException.class) + @SuppressWarnings("deprecation") + public void constructInterestWithInvalidStringPolicy() { + new Interest<>("testKey", "INVALID"); + } + + @Test + public void isAlphanumericWhitespace() { + Interest interest = newInterest("key"); + + assertThat(interest.isAlphaNumericWhitespace('a')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('X')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('0')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('1')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('2')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('4')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('8')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace('9')).isTrue(); + assertThat(interest.isAlphaNumericWhitespace(' ')).isTrue(); + } + + @Test + public void isNonAlphanumericWhitespace() { + Interest interest = newInterest("key"); + + assertThat(interest.isNotAlphaNumericWhitespace('@')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('$')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('.')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('_')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('-')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('+')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('*')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('?')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('\\')).isTrue(); + assertThat(interest.isNotAlphaNumericWhitespace('[')).isTrue(); + } + + @Test + public void containsNonAlphanumericWhitespace() { + Interest interest = newInterest("key"); + + assertThat(interest.containsNonAlphaNumericWhitespace(".*")).isTrue(); + assertThat(interest.containsNonAlphaNumericWhitespace(".*Key")).isTrue(); + assertThat(interest.containsNonAlphaNumericWhitespace("\\d")).isTrue(); + assertThat(interest.containsNonAlphaNumericWhitespace("\\s")).isTrue(); + assertThat(interest.containsNonAlphaNumericWhitespace("p\\{Alnum}")).isTrue(); + assertThat(interest.containsNonAlphaNumericWhitespace("p\\{Space}")).isTrue(); + } + + @Test + public void containsOnlyAlphanumericWhitespace() { + Interest interest = newInterest("key"); + + assertThat(interest.containsNonAlphaNumericWhitespace("0")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("123")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("123 456")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("key")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("keyOne")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("Key One")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("key0")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("key1")).isFalse(); + assertThat(interest.containsNonAlphaNumericWhitespace("key123")).isFalse(); + } + + @Test + public void isRegularExpression() { + Interest interest = newInterest("key"); + + assertThat(interest.isRegularExpression(".?")).isTrue(); + assertThat(interest.isRegularExpression(".+")).isTrue(); + assertThat(interest.isRegularExpression(".*")).isTrue(); + assertThat(interest.isRegularExpression(".*Key")).isTrue(); + assertThat(interest.isRegularExpression("\\d")).isTrue(); + assertThat(interest.isRegularExpression("\\n")).isTrue(); + assertThat(interest.isRegularExpression("\\s")).isTrue(); + assertThat(interest.isRegularExpression("p\\{Alnum}")).isTrue(); + assertThat(interest.isRegularExpression("p\\{Space}")).isTrue(); + assertThat(interest.isRegularExpression("^abc$")).isTrue(); + assertThat(interest.isRegularExpression(" [abc] ")).isTrue(); + assertThat(interest.isRegularExpression("a{0,}bc")).isTrue(); + assertThat(interest.isRegularExpression("a{1,10} bc*")).isTrue(); + } + + @Test + public void isNotRegularExpression() { + Interest interest = newInterest("key"); + + assertThat(interest.isRegularExpression("abc")).isFalse(); + assertThat(interest.isRegularExpression("123")).isFalse(); + assertThat(interest.isRegularExpression("abc123")).isFalse(); + assertThat(interest.isRegularExpression(" abc 123 ")).isFalse(); + assertThat(interest.isRegularExpression("lOlO")).isFalse(); + assertThat(interest.isRegularExpression((Object) "ALL_KEYS")).isFalse(); + assertThat(interest.isRegularExpression(asList("a", "b", "c"))).isFalse(); + } + + @Test + public void resolveTypeIsCorrect() { + assertThat(newInterest(".*").resolveType(KEY)).isEqualTo(KEY); + assertThat(newInterest("key").resolveType(REGEX)).isEqualTo(REGEX); + assertThat(newInterest("key").resolveType(null)).isEqualTo(KEY); + assertThat(newInterest(asList("a", "b", "c")).resolveType(null)).isEqualTo(KEY); + assertThat(newInterest(".*").resolveType(null)).isEqualTo(REGEX); + } + + @Test + @SuppressWarnings("unchecked") + public void setAndGetStateIsCorrect() { + Interest interest = newInterest("key"); + + assertThat(interest.isDurable()).isFalse(); + assertThat(interest.getKey()).isEqualTo("key"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.DEFAULT); + assertThat(interest.isReceiveValues()).isTrue(); + assertThat(interest.getType()).isEqualTo(KEY); + + interest.setDurable(true); + interest.setKey("testKey"); + interest.setPolicy(InterestResultPolicy.KEYS); + interest.setReceiveValues(false); + interest.setType(Interest.Type.REGEX); + + assertThat(interest.isDurable()).isTrue(); + assertThat(interest.getKey()).isEqualTo("testKey"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.KEYS); + assertThat(interest.isReceiveValues()).isFalse(); + assertThat(interest.getType()).isEqualTo(REGEX); + } + + @Test + public void setAndGetPolicy() { + Interest interest = newInterest("key"); + + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.DEFAULT); + + interest.setPolicy(InterestResultPolicy.NONE); + + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.NONE); + + interest.setPolicy("keys"); + + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.KEYS); + } + + @Test(expected = ConstantException.class) + public void setPolicyWithIllegalValueThrowsException() { + newInterest("key").setPolicy("ILLEGAL"); + } + + @Test + public void isKeyTypeIsCorrect() { + Interest interest = newInterest("key"); + + assertThat(interest.getType()).isEqualTo(KEY); + assertThat(interest.isKeyType()).isTrue(); + + interest.setType(REGEX); + + assertThat(interest.getType()).isEqualTo(REGEX); + assertThat(interest.isKeyType()).isFalse(); + + interest.setType(KEY); + + assertThat(interest.getType()).isEqualTo(KEY); + assertThat(interest.isKeyType()).isTrue(); + } + + @Test + public void isRegexTypeIsCorrect() { + Interest interest = newInterest("key"); + + assertThat(interest.getType()).isEqualTo(KEY); + assertThat(interest.isRegexType()).isFalse(); + + interest.setType(KEY); + + assertThat(interest.getType()).isEqualTo(KEY); + assertThat(interest.isRegexType()).isFalse(); + + interest.setType(REGEX); + + assertThat(interest.getType()).isEqualTo(REGEX); + assertThat(interest.isRegexType()).isTrue(); + } + + @Test + public void newInterestWithBuilder() { + Interest interest = newInterest(".*").makeDurable().receivesValues(false) + .usingPolicy(InterestResultPolicy.KEYS); + + assertThat(interest).isNotNull(); + assertThat(interest.isDurable()).isTrue(); + assertThat(interest.getKey()).isEqualTo(".*"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.KEYS); + assertThat(interest.isReceiveValues()).isFalse(); + assertThat(interest.getType()).isEqualTo(REGEX); + } + + @Test + @SuppressWarnings("unchecked") + public void newInterestWithBuilderHonorsType() { + Interest interest = newInterest(".*").asType(KEY).withKey("^.+Key\\p{Digit}$") + .usingPolicy(InterestResultPolicy.NONE); + + assertThat(interest).isNotNull(); + assertThat(interest.isDurable()).isFalse(); + assertThat(interest.getKey()).isEqualTo("^.+Key\\p{Digit}$"); + assertThat(interest.getPolicy()).isEqualTo(InterestResultPolicy.NONE); + assertThat(interest.isReceiveValues()).isTrue(); + assertThat(interest.getType()).isEqualTo(KEY); + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/xml/ClientRegionNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/xml/ClientRegionNamespaceTest.java index 6eaccd69..5e242159 100644 --- a/src/test/java/org/springframework/data/gemfire/config/xml/ClientRegionNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/xml/ClientRegionNamespaceTest.java @@ -260,11 +260,11 @@ public class ClientRegionNamespaceTest { public void testClientRegionWithRegisteredInterests() throws Exception { assertTrue(context.containsBean("client-with-interests")); - ClientRegionFactoryBean factory = context.getBean("&client-with-interests", ClientRegionFactoryBean.class); + ClientRegionFactoryBean factoryBean = context.getBean("&client-with-interests", ClientRegionFactoryBean.class); - assertNotNull(factory); + assertNotNull(factoryBean); - Interest[] interests = TestUtils.readField("interests", factory); + Interest[] interests = TestUtils.readField("interests", factoryBean); assertNotNull(interests); assertEquals(2, interests.length); diff --git a/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsUnitTests.java b/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsUnitTests.java index f54d6c4b..4497658e 100644 --- a/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsUnitTests.java @@ -275,7 +275,7 @@ public class CollectionUtilsUnitTests { assertThat(iterable.iterator().hasNext()).isFalse(); } - @Test(expected = UnsupportedOperationException.class) + @Test(expected = IllegalStateException.class) public void nullSafeIterableIterator() { Iterable iterable = CollectionUtils.nullSafeIterable(null); @@ -290,16 +290,10 @@ public class CollectionUtilsUnitTests { iterator.next(); } catch (NoSuchElementException ignore) { - assertThat(ignore.getMessage()).isEqualTo("No more elements"); - assertThat(ignore.getCause()).isNull(); - try { iterator.remove(); } - catch (UnsupportedOperationException expected) { - assertThat(expected.getMessage()).isEqualTo("Operation not supported"); - assertThat(expected.getCause()).isNull(); - + catch (IllegalStateException expected) { throw expected; } }