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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
151
src/main/java/org/springframework/data/gemfire/IndexType.java
Normal file
151
src/main/java/org/springframework/data/gemfire/IndexType.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user