SGF-366 - Unable to create local-only, client-based Region Indexes using SDG's <gfe:index> and corresponding IndexFactoryBean functionality.

This commit is contained in:
John Blum
2015-01-14 16:08:05 -08:00
parent 8532441fac
commit 138e8d9827
10 changed files with 1386 additions and 63 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.data.gemfire;
import java.util.Collection;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
@@ -30,103 +32,131 @@ import com.gemstone.gemfire.cache.query.IndexExistsException;
import com.gemstone.gemfire.cache.query.QueryService;
/**
* Factory bean for easy declarative creation of GemFire Indexes.
* Spring FactoryBean for easy declarative creation of GemFire Indexes.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.FactoryBean
* @see com.gemstone.gemfire.cache.RegionService
* @see com.gemstone.gemfire.cache.query.Index
* @see com.gemstone.gemfire.cache.query.QueryService
* @since 1.0.0
*/
public class IndexFactoryBean implements InitializingBean, BeanNameAware, FactoryBean<Index> {
public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, BeanNameAware {
private boolean override = true;
private Index index;
private IndexType indexType;
private QueryService queryService;
private RegionService cache;
private String beanName;
private String name;
private String expression;
private String from;
private String imports;
private String type;
private boolean override = true;
private String name;
public void afterPropertiesSet() throws Exception {
if (queryService == null) {
if (cache != null) {
queryService = cache.getQueryService();
}
Assert.notNull(cache, "The GemFire Cache reference must not be null!");
queryService = lookupQueryService();
Assert.notNull(queryService, "A QueryService is required for Index creation!");
Assert.hasText(expression, "The Index 'expression' is required!");
Assert.hasText(from, "The Index 'from' clause (a Region's full-path) is required!");
if (IndexType.isKey(indexType)) {
Assert.isNull(imports, "The 'imports' property is not supported for a Key Index.");
}
Assert.notNull(queryService, "Query service required for index creation");
Assert.hasText(expression, "Index expression is required");
Assert.hasText(from, "Index from clause (regionPath) is required");
String indexName = (StringUtils.hasText(name) ? name : beanName);
if (StringUtils.hasText(type)) {
if (type.equalsIgnoreCase("KEY") || type.equalsIgnoreCase("PRIMARY_KEY")) {
Assert.isNull(imports, "The imports property is not supported for a key index");
}
}
String indexName = StringUtils.hasText(name) ? name : beanName;
Assert.hasText(indexName, "Index bean id or name is required");
Assert.hasText(indexName, "The Index bean id or name is required!");
index = createIndex(queryService, indexName);
}
private Index createIndex(QueryService queryService, String indexName) throws Exception {
QueryService lookupQueryService() {
return (queryService != null ? queryService
: (cache instanceof ClientCache ? ((ClientCache) cache).getLocalQueryService()
: cache.getQueryService()));
}
Index createIndex(QueryService queryService, String indexName) throws Exception {
Index existingIndex = getExistingIndex(queryService, indexName);
Index existingIndex = null;
for (Index idx : queryService.getIndexes()) {
if (idx.getName().equals(indexName)) {
existingIndex = idx;
break;
}
}
if (existingIndex != null) {
if (!override) {
return existingIndex;
} else {
if (override) {
queryService.removeIndex(existingIndex);
}
else {
return existingIndex;
}
}
Index index = null;
try {
if ("KEY".equalsIgnoreCase(type) || "PRIMARY_KEY".equalsIgnoreCase(type)) {
index = queryService.createKeyIndex(indexName, expression, from);
} else if ("HASH".equalsIgnoreCase(type)) {
if (StringUtils.hasText(imports)) {
index = queryService.createHashIndex(indexName, expression, from, imports);
} else {
index = queryService.createHashIndex(indexName, expression, from);
}
} else {
if (StringUtils.hasText(imports)) {
index = queryService.createIndex(indexName, expression, from, imports);
} else {
index = queryService.createIndex(indexName, expression, from);
}
if (IndexType.isKey(indexType)) {
return queryService.createKeyIndex(indexName, expression, from);
}
return index;
} catch (IndexExistsException e) {
for (Index idx : queryService.getIndexes()) {
if (idx.getName().equals(indexName)) {
return idx;
}
else if (IndexType.isHash(indexType)) {
return createHashIndex(queryService, indexName, expression, from, imports);
}
} catch (Exception e) {
else {
return createFunctionalIndex(queryService, indexName, expression, from, imports);
}
}
catch (IndexExistsException e) {
return getExistingIndex(queryService, indexName);
}
catch (Exception e) {
if (existingIndex != null) {
if (CollectionUtils.isEmpty(queryService.getIndexes())
|| !queryService.getIndexes().contains(existingIndex)) {
Collection<Index> indexes = queryService.getIndexes();
if (CollectionUtils.isEmpty(indexes) || !indexes.contains(existingIndex)) {
queryService.getIndexes().add(existingIndex);
return existingIndex;
}
}
throw e;
}
}
Index createFunctionalIndex(QueryService queryService, String indexName, String expression, String from,
String imports) throws Exception {
if (StringUtils.hasText(imports)) {
return queryService.createIndex(indexName, expression, from, imports);
}
else {
return queryService.createIndex(indexName, expression, from);
}
}
Index createHashIndex(QueryService queryService, String indexName, String expression, String from,
String imports) throws Exception {
if (StringUtils.hasText(imports)) {
return queryService.createHashIndex(indexName, expression, from, imports);
}
else {
return queryService.createHashIndex(indexName, expression, from);
}
}
Index getExistingIndex(QueryService queryService, String indexName) {
for (Index index : queryService.getIndexes()) {
if (index.getName().equalsIgnoreCase(indexName)) {
return index;
}
}
return index;
return null;
}
public Index getObject() {
@@ -195,7 +225,18 @@ public class IndexFactoryBean implements InitializingBean, BeanNameAware, Factor
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
setType(IndexType.valueOfIgnoreCase(type));
}
/**
* Sets the type of GemFire Index to create.
*
* @param indexType the IndexType enumerated value indicating the type of GemFire Index
* that will be created by this Spring FactoryBean.
* @see org.springframework.data.gemfire.IndexType
*/
public void setType(IndexType indexType) {
this.indexType = indexType;
}
/**
@@ -204,4 +245,5 @@ public class IndexFactoryBean implements InitializingBean, BeanNameAware, Factor
public void setOverride(boolean override) {
this.override = override;
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* 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;
/**
* The IndexType class is an enumerated type of GemFire Index Types.
*
* @author John Blum
* @see com.gemstone.gemfire.cache.query.IndexType
* @since 1.5.2
*/
@SuppressWarnings({ "deprecation", "unused" })
public enum IndexType {
FUNCTIONAL(com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL),
HASH(com.gemstone.gemfire.cache.query.IndexType.HASH),
PRIMARY_KEY(com.gemstone.gemfire.cache.query.IndexType.PRIMARY_KEY),
KEY(com.gemstone.gemfire.cache.query.IndexType.PRIMARY_KEY);
private final com.gemstone.gemfire.cache.query.IndexType gemfireIndexType;
/**
* Constructs an instance of the IndexType enum initialized with the given GemFire IndexType.
*
* @param gemfireIndexType the corresponding GemFire IndexType
* @see com.gemstone.gemfire.cache.query.IndexType
*/
IndexType(final com.gemstone.gemfire.cache.query.IndexType gemfireIndexType) {
this.gemfireIndexType = gemfireIndexType;
}
/**
* Null-safe operation to determine if the IndexType is a "FUNCTIONAL" Index.
*
* @param indexType the IndexType to evaluate.
* @return a boolean value indicating whether the IndexType is a "FUNCTIONAL" Index.
* @see #isFunctional()
*/
public static boolean isFunctional(final IndexType indexType) {
return (indexType != null && indexType.isFunctional());
}
/**
* Null-safe operation to determine if the IndexType is a "HASH" Index.
*
* @param indexType the IndexType to evaluate.
* @return a boolean value indicating whether the IndexType is a "HASH" Index.
* @see #isHash()
*/
public static boolean isHash(final IndexType indexType) {
return (indexType != null && indexType.isHash());
}
/**
* Null-safe operation to determine if the IndexType is a "KEY" Index.
*
* @param indexType the IndexType to evaluate.
* @return a boolean value indicating whether the IndexType is a "KEY" Index.
* @see #isFunctional()
*/
public static boolean isKey(final IndexType indexType) {
return (indexType != null && indexType.isKey());
}
/**
* Returns an IndexType given the corresponding GemFire IndexType or null if no SDG IndexType
* corresponds to the GemFire IndexType.
*
* @param gemfireIndexType the GemFire IndexType.
* @return a IndexType matching the GemFire IndexType or null if the GemFire IndexType does not match
* any IndexType in this enumeration.
* @see com.gemstone.gemfire.cache.query.IndexType
*/
public static IndexType valueOf(final com.gemstone.gemfire.cache.query.IndexType gemfireIndexType) {
for (IndexType indexType : values()) {
if (indexType.getGemfireIndexType().equals(gemfireIndexType)) {
return indexType;
}
}
return null;
}
/**
* Returns an IndexType matching the given String.
*
* @param value the String value describing the matching IndexType.
* @return an IndexType matching the given String.
* @see java.lang.String#equalsIgnoreCase(String)
*/
public static IndexType valueOfIgnoreCase(final String value) {
for (IndexType indexType : values()) {
if (indexType.name().equalsIgnoreCase(value)) {
return indexType;
}
}
return null;
}
/**
* Gets the matching GemFire IndexType for this IndexType enumerated value.
*
* @return the matching GemFire IndexType.
* @see com.gemstone.gemfire.cache.query.IndexType
*/
public com.gemstone.gemfire.cache.query.IndexType getGemfireIndexType() {
return gemfireIndexType;
}
/**
* Determines whether this IndexType is "FUNCTIONAL".
*
* @return a boolean value indicating whether this IndexType is "FUNCTIONAL".
*/
public boolean isFunctional() {
return this.equals(FUNCTIONAL);
}
/**
* Determines whether this IndexType is a "HASH" Index.
*
* @return a boolean value indicating whether this IndexType is a "HASH" Index.
*/
public boolean isHash() {
return this.equals(HASH);
}
/**
* Determines whether this IndexType is a "KEY" Index.
*
* @return a boolean value indicating whether this IndexType is a "KEY" Index.
*/
public boolean isKey() {
return (this.equals(KEY) || this.equals(PRIMARY_KEY));
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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;
import java.beans.PropertyEditorSupport;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The IndexTypeConverter class is a Spring Converter implementation as well as a JavaBeans PropertyEditor
* that converts a given String value into a proper IndexType.
*
* @author John Blum
* @see java.beans.PropertyEditorSupport
* @see org.springframework.core.convert.converter.Converter
* @see org.springframework.data.gemfire.IndexType
* @since 1.5.2
*/
@SuppressWarnings("unused")
public class IndexTypeConverter extends PropertyEditorSupport implements Converter<String, IndexType> {
/**
* Asserts that the given String value was successfully converted into a IndexType.
*
* @param value the String value to convert into an appropriate IndexType.
* @param indexType the converted IndexType.
* @return the IndexType is non-null.
* @throws java.lang.IllegalArgumentException if the IndexType argument was null, indicating that
* the given String value could not be converted into an appropriate IndexType.
* @see org.springframework.data.gemfire.IndexType
*/
private IndexType assertConverted(final String value, final IndexType indexType) {
Assert.notNull(indexType, String.format("Failed to convert String (%1$s) into an IndexType!", value));
return indexType;
}
/**
* Converts the given String value into an appropriate IndexType
*
* @param value the String to convert into a corresponding IndexType enumerated value.
* @return an IndexType converted from the given String value.
* @throws java.lang.IllegalArgumentException if the given String could not be converted into
* an appropriate IndexType enumerated value.
* @see #assertConverted(String, IndexType)
* @see org.springframework.data.gemfire.IndexType#valueOfIgnoreCase(String)
* @see org.springframework.util.StringUtils#trimWhitespace(String)
*/
@Override
public IndexType convert(final String value) {
return assertConverted(value, IndexType.valueOfIgnoreCase(StringUtils.trimWhitespace(value)));
}
/**
* Sets the value of this PropertyEditor as a IndexType enumerated value converted from the given String text.
*
* @param text the String to convert into a corresponding IndexType enumerated value.
* @throws java.lang.IllegalArgumentException if the given String could not be converted into
* an appropriate IndexType enumerated value.
* @see #convert(String)
* @see #setValue(Object)
*/
@Override
public void setAsText(final String text) throws IllegalArgumentException {
setValue(convert(text));
}
}