SGF-674 - Add EnableClusterConfiguration annotation to push cluster configuration meta-data from the client to the server.
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -89,6 +89,11 @@
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Data Commons -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
|
||||
@@ -21,23 +21,23 @@ import java.util.concurrent.ConcurrentMap;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.internal.GemFireVersion;
|
||||
import org.springframework.data.gemfire.util.CacheUtils;
|
||||
import org.springframework.data.gemfire.util.RegionUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* GemfireUtils is an abstract utility class encapsulating common functionality to access features and capabilities
|
||||
* of GemFire based on version and other configuration meta-data.
|
||||
* {@link GemfireUtils} is an abstract utility class encapsulating common functionality to access features
|
||||
* and capabilities of GemFire based on version and other configuration meta-data.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.util.DistributedSystemUtils
|
||||
* @see org.apache.geode.cache.CacheFactory
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.data.gemfire.util.RegionUtils
|
||||
* @since 1.3.3
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class GemfireUtils extends CacheUtils {
|
||||
public abstract class GemfireUtils extends RegionUtils {
|
||||
|
||||
public final static String APACHE_GEODE_NAME = "Aache Geode";
|
||||
public final static String APACHE_GEODE_NAME = "Apache Geode";
|
||||
public final static String GEMFIRE_NAME = apacheGeodeProductName();
|
||||
public final static String GEMFIRE_VERSION = apacheGeodeVersion();
|
||||
public final static String UNKNOWN = "unknown";
|
||||
|
||||
@@ -78,6 +78,7 @@ public class GemfireDataSourcePostProcessor implements BeanFactoryPostProcessor
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
// TODO remove this logic and delegate to o.s.d.g.config.remote.GemfireAdminOperations
|
||||
Iterable<String> regionNames() {
|
||||
try {
|
||||
return execute(new ListRegionsOnServerFunction());
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin;
|
||||
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.lucene.LuceneIndex;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
|
||||
/**
|
||||
* {@link AbstractGemfireAdminOperations} is an abstract base class encapsulating common functionality
|
||||
* supporting administrative (management) operations against a Pivotal GemFire or Apache Geode cluster.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class AbstractGemfireAdminOperations implements GemfireAdminOperations {
|
||||
|
||||
protected static final String NOT_IMPLEMENTED = "Not Implemented";
|
||||
|
||||
/**
|
||||
* Returns a {@link Iterable collection} of {@link Region} names defined on the GemFire Servers in the cluster.
|
||||
*
|
||||
* @return an {@link Iterable} of {@link Region} names defined on the GemFire Servers in the cluster.
|
||||
* @see org.apache.geode.cache.Region#getName()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
@Override
|
||||
public Iterable<String> getAvailableServerRegions() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Iterable} of all the server {@link Region} {@link Index Indexes}.
|
||||
*
|
||||
* @return an {@link Iterable} of all the server {@link Region} {@link Index Indexes}.
|
||||
* @see org.apache.geode.cache.query.Index#getName()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
@Override
|
||||
public Iterable<String> getAvailableServerRegionIndexes() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache {@link Region} based on the given {@link RegionDefinition schema object definition}.
|
||||
*
|
||||
* @param regionDefinition {@link RegionDefinition} encapsulating configuration meta-data defining
|
||||
* a cache {@link Region}.
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
@Override
|
||||
public void createRegion(RegionDefinition regionDefinition) {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Region} {@link LuceneIndex} based on the given
|
||||
* {@link SchemaObjectDefinition schema object definition}.
|
||||
*
|
||||
* @param luceneIndexDefinition {@link SchemaObjectDefinition} encapsulating the configuration meta-data
|
||||
* defining a {@link Region} {@link LuceneIndex}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.apache.geode.cache.lucene.LuceneIndex
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
@Override
|
||||
public void createLuceneIndex(SchemaObjectDefinition luceneIndexDefinition) {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Region} OQL {@link Index} based on the given {@link IndexDefinition schema object definition}.
|
||||
*
|
||||
* @param indexDefinition {@link IndexDefinition} encapsulating the configuration meta-data
|
||||
* defining a {@link Region} OQL {@link Index}.
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
@Override
|
||||
public void createIndex(IndexDefinition indexDefinition) {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DiskStore} based on the given {@link SchemaObjectDefinition schema object definition}.
|
||||
*
|
||||
* @param diskStoreDefinition {@link SchemaObjectDefinition} encapsulating the configuration meta-data
|
||||
* defining a {@link DiskStore}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
*/
|
||||
@Override
|
||||
public void createDiskStore(SchemaObjectDefinition diskStoreDefinition) {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
|
||||
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.lucene.LuceneIndex;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
|
||||
/**
|
||||
* The {@link GemfireAdminOperations} interface defines a set of operations to define schema objects in a remote
|
||||
* Apache Geode or Pivotal GemFire cluster.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.lucene.LuceneIndex
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface GemfireAdminOperations {
|
||||
|
||||
/**
|
||||
* Returns a {@link Iterable collection} of {@link Region} names defined on the GemFire Servers in the cluster.
|
||||
*
|
||||
* @return an {@link Iterable} of {@link Region} names defined on the GemFire Servers in the cluster.
|
||||
* @see org.apache.geode.cache.Region#getName()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
Iterable<String> getAvailableServerRegions();
|
||||
|
||||
/**
|
||||
* Returns an {@link Iterable} of all the server {@link Region} {@link Index Indexes}.
|
||||
*
|
||||
* @return an {@link Iterable} of all the server {@link Region} {@link Index Indexes}.
|
||||
* @see org.apache.geode.cache.query.Index#getName()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
Iterable<String> getAvailableServerRegionIndexes();
|
||||
|
||||
/**
|
||||
* Creates a cache {@link Region} based on the given {@link RegionDefinition schema object definition}.
|
||||
*
|
||||
* @param regionDefinition {@link RegionDefinition} encapsulating configuration meta-data defining
|
||||
* a cache {@link Region}.
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
void createRegion(RegionDefinition regionDefinition);
|
||||
|
||||
default void createRegions(RegionDefinition... regionDefinitions) {
|
||||
stream(nullSafeArray(regionDefinitions, RegionDefinition.class)).forEach(this::createRegion);
|
||||
}
|
||||
|
||||
default void createRegions(Iterable<RegionDefinition> regionDefinitions) {
|
||||
nullSafeIterable(regionDefinitions).forEach(this::createRegion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Region} {@link LuceneIndex} based on the given
|
||||
* {@link SchemaObjectDefinition schema object definition}.
|
||||
*
|
||||
* @param luceneIndexDefinition {@link SchemaObjectDefinition} encapsulating the configuration meta-data
|
||||
* defining a {@link Region} {@link LuceneIndex}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.apache.geode.cache.lucene.LuceneIndex
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
void createLuceneIndex(SchemaObjectDefinition luceneIndexDefinition);
|
||||
|
||||
default void createLuceneIndexes(SchemaObjectDefinition... luceneIndexDefinitions) {
|
||||
stream(nullSafeArray(luceneIndexDefinitions, SchemaObjectDefinition.class)).forEach(this::createLuceneIndex);
|
||||
}
|
||||
|
||||
default void createLuceneIndexes(Iterable<SchemaObjectDefinition> luceneIndexDefinitions) {
|
||||
nullSafeIterable(luceneIndexDefinitions).forEach(this::createLuceneIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Region} OQL {@link Index} based on the given {@link IndexDefinition schema object definition}.
|
||||
*
|
||||
* @param indexDefinition {@link IndexDefinition} encapsulating the configuration meta-data
|
||||
* defining a {@link Region} OQL {@link Index}.
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
void createIndex(IndexDefinition indexDefinition);
|
||||
|
||||
default void createIndexes(IndexDefinition... indexDefinitions) {
|
||||
stream(nullSafeArray(indexDefinitions, IndexDefinition.class)).forEach(this::createIndex);
|
||||
}
|
||||
|
||||
default void createIndexes(Iterable<IndexDefinition> indexDefinitions) {
|
||||
nullSafeIterable(indexDefinitions).forEach(this::createIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DiskStore} based on the given {@link SchemaObjectDefinition schema object definition}.
|
||||
*
|
||||
* @param diskStoreDefinition {@link SchemaObjectDefinition} encapsulating the configuration meta-data
|
||||
* defining a {@link DiskStore}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
*/
|
||||
void createDiskStore(SchemaObjectDefinition diskStoreDefinition);
|
||||
|
||||
default void createDiskStores(SchemaObjectDefinition... diskStoreDefinitions) {
|
||||
stream(nullSafeArray(diskStoreDefinitions, SchemaObjectDefinition.class)).forEach(this::createDiskStore);
|
||||
}
|
||||
|
||||
default void createDiskStores(Iterable<SchemaObjectDefinition> diskStoreDefinitions) {
|
||||
nullSafeIterable(diskStoreDefinitions).forEach(this::createDiskStore);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.functions;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.query.QueryException;
|
||||
import org.apache.geode.cache.query.QueryService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.gemfire.GemfireCacheUtils;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
|
||||
/**
|
||||
* The CreateIndexFunction class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class CreateIndexFunction {
|
||||
|
||||
public static final String CREATE_INDEX_FUNCTION_ID = "CreateOqlIndexFunction";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@GemfireFunction(id = CREATE_INDEX_FUNCTION_ID)
|
||||
public boolean createIndex(IndexDefinition indexDefinition) {
|
||||
|
||||
Cache gemfireCache = resolveCache();
|
||||
|
||||
if (isNonExistingIndex(gemfireCache, indexDefinition)) {
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Creating Index with name [{}] having expression [{}] on Region [{}] with type [{}]",
|
||||
indexDefinition.getName(), indexDefinition.getExpression(), indexDefinition.getFromClause(),
|
||||
indexDefinition.getIndexType());
|
||||
}
|
||||
|
||||
QueryService queryService = gemfireCache.getQueryService();
|
||||
|
||||
try {
|
||||
switch (indexDefinition.getIndexType()) {
|
||||
case KEY:
|
||||
case PRIMARY_KEY:
|
||||
queryService.createKeyIndex(indexDefinition.getName(),
|
||||
indexDefinition.getExpression(), indexDefinition.getFromClause());
|
||||
return true;
|
||||
case HASH:
|
||||
queryService.createHashIndex(indexDefinition.getName(),
|
||||
indexDefinition.getExpression(), indexDefinition.getFromClause());
|
||||
return true;
|
||||
case FUNCTIONAL:
|
||||
queryService.createIndex(indexDefinition.getName(),
|
||||
indexDefinition.getExpression(), indexDefinition.getFromClause());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (QueryException cause) {
|
||||
throw GemfireCacheUtils.convertGemfireAccessException(cause);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Index with name [{}] already exists", indexDefinition.getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected Cache resolveCache() {
|
||||
return CacheFactory.getAnyInstance();
|
||||
}
|
||||
|
||||
protected boolean isNonExistingIndex(GemFireCache gemfireCache, IndexDefinition indexDefinition) {
|
||||
return !nullSafeCollection(gemfireCache.getQueryService().getIndexes()).stream()
|
||||
.anyMatch(index -> index.getName().equals(indexDefinition.getName()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.functions;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
|
||||
/**
|
||||
* The CreateRegionFunction class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class CreateRegionFunction {
|
||||
|
||||
public static final String CREATE_REGION_FUNCTION_ID = "CreateRegionFunction";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@GemfireFunction(id = CREATE_REGION_FUNCTION_ID)
|
||||
public boolean createRegion(RegionDefinition regionDefinition) {
|
||||
|
||||
Cache gemfireCache = resolveCache();
|
||||
|
||||
if (isNonExistingRegion(gemfireCache, regionDefinition)) {
|
||||
|
||||
RegionFactory regionFactory = gemfireCache.createRegionFactory(regionDefinition.getRegionShortcut());
|
||||
|
||||
Region region = regionFactory.create(regionDefinition.getName());
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Created Region [{}] of type [{}]", region.getName(), region.getAttributes().getDataPolicy());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.info("Region with name [{}] already exists", regionDefinition.getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected Cache resolveCache() {
|
||||
return CacheFactory.getAnyInstance();
|
||||
}
|
||||
|
||||
private boolean isNonExistingRegion(Cache gemfireCache, RegionDefinition regionDefinition) {
|
||||
return (gemfireCache.getRegion(regionDefinition.getName()) == null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.functions;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.CacheFactory;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
|
||||
/**
|
||||
* The ListIndexesFunction class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ListIndexesFunction {
|
||||
|
||||
public static final String LIST_INDEXES_FUNCTION_ID = "ListQqlIndexesFunction";
|
||||
|
||||
@GemfireFunction(id = LIST_INDEXES_FUNCTION_ID)
|
||||
public Set<String> listIndexes() {
|
||||
|
||||
return Optional.ofNullable(resolveCache())
|
||||
.map(cache -> cache.getQueryService())
|
||||
.map(queryService ->
|
||||
nullSafeCollection(queryService.getIndexes()).stream().map(Index::getName).collect(Collectors.toSet()))
|
||||
.orElseGet(Collections::emptySet);
|
||||
}
|
||||
|
||||
protected Cache resolveCache() {
|
||||
return CacheFactory.getAnyInstance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.remote;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.management.internal.cli.domain.RegionInformation;
|
||||
import org.apache.geode.management.internal.cli.functions.GetRegionsFunction;
|
||||
import org.springframework.data.gemfire.client.function.ListRegionsOnServerFunction;
|
||||
import org.springframework.data.gemfire.config.admin.AbstractGemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.admin.functions.CreateIndexFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.CreateRegionFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.ListIndexesFunction;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.data.gemfire.function.execution.GemfireFunctionOperations;
|
||||
import org.springframework.data.gemfire.function.execution.GemfireOnServersFunctionTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@link FunctionGemfireAdminTemplate} class is an implementation of the {@link GemfireAdminOperations} interface
|
||||
* supporting the Pivotal GemFire / Apache Geode administrative functions/operations via {@link Function} execution
|
||||
* in the cluster.
|
||||
*
|
||||
* Note: any schema changing functionality (e.g. {@link #createRegion(RegionDefinition)}) does not get recorded by
|
||||
* the GemFire/Geode Cluster Configuration Service using this strategy.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @see org.springframework.data.gemfire.client.function.ListRegionsOnServerFunction
|
||||
* @see org.springframework.data.gemfire.config.admin.AbstractGemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.function.execution.GemfireOnServersFunctionTemplate
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class FunctionGemfireAdminTemplate extends AbstractGemfireAdminOperations {
|
||||
|
||||
private final ClientCache clientCache;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link FunctionGemfireAdminTemplate} initialized with
|
||||
* a {@link ClientCache} instance.
|
||||
*
|
||||
* @param clientCache reference to a {@link ClientCache} instance.
|
||||
* @throws IllegalArgumentException if {@link ClientCache} is {@literal null}.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
*/
|
||||
public FunctionGemfireAdminTemplate(ClientCache clientCache) {
|
||||
|
||||
Assert.notNull(clientCache, "ClientCache is required");
|
||||
|
||||
this.clientCache = clientCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured {@link ClientCache} instance.
|
||||
*
|
||||
* @return a reference to the configured {@link ClientCache} instance.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
*/
|
||||
protected ClientCache getClientCache() {
|
||||
return this.clientCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all available {@link Region Regions} configured for all servers in the remote Pivotal GemFire
|
||||
* / Apache Geode cluster.
|
||||
*
|
||||
* @return an {@link Iterable} of servers-side {@link Region} names for all {@link Region Regions} defined
|
||||
* across all servers in the remote GemFire/Geode cluster.
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
@Override
|
||||
public Iterable<String> getAvailableServerRegions() {
|
||||
|
||||
try {
|
||||
return execute(new ListRegionsOnServerFunction());
|
||||
}
|
||||
catch (Exception cause) {
|
||||
try {
|
||||
return Optional.ofNullable(execute(new GetRegionsFunction()))
|
||||
.filter(this::containsRegionInformation)
|
||||
.map(regionInformationArray ->
|
||||
stream(nullSafeArray((Object[]) regionInformationArray, Object.class))
|
||||
.map(regionInformation -> ((RegionInformation) regionInformation).getName())
|
||||
.collect(Collectors.toSet())
|
||||
)
|
||||
.orElse(Collections.emptySet());
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Iterable} of all the server {@link Region} {@link Index Indexes}.
|
||||
*
|
||||
* @return an {@link Iterable} of all the server {@link Region} {@link Index Indexes}.
|
||||
* @see org.apache.geode.cache.query.Index#getName()
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
@Override
|
||||
public Iterable<String> getAvailableServerRegionIndexes() {
|
||||
return execute(ListIndexesFunction.LIST_INDEXES_FUNCTION_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRegion(RegionDefinition regionDefinition) {
|
||||
execute(CreateRegionFunction.CREATE_REGION_FUNCTION_ID, regionDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createIndex(IndexDefinition indexDefinition) {
|
||||
execute(CreateIndexFunction.CREATE_INDEX_FUNCTION_ID, indexDefinition);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
<T> T execute(Function gemfireFunction, Object... arguments) {
|
||||
return newGemfireFunctionOperations().executeAndExtract(gemfireFunction, arguments);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
<T> T execute(String gemfireFunctionId, Object... arguments) {
|
||||
return newGemfireFunctionOperations().executeAndExtract(gemfireFunctionId, arguments);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected GemfireFunctionOperations newGemfireFunctionOperations() {
|
||||
return newGemfireFunctionOperations(getClientCache());
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected GemfireFunctionOperations newGemfireFunctionOperations(ClientCache clientCache) {
|
||||
return new GemfireOnServersFunctionTemplate(clientCache);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
boolean containsRegionInformation(Object results) {
|
||||
|
||||
return Optional.ofNullable(results)
|
||||
.filter(it -> it instanceof Object[])
|
||||
.filter(it -> ((Object[]) it).length > 0)
|
||||
.filter(it -> ((Object[]) it)[0] instanceof RegionInformation)
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.remote;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* {@link RestHttpGemfireAdminTemplate} is class implementing the {@link GemfireAdminOperations} interface,
|
||||
* extending the {@link FunctionGemfireAdminTemplate} to support administrative (management) operations
|
||||
* on a Pivotal GemFire or Apache Geode cluster using the Management REST API interface over HTTP.
|
||||
*
|
||||
* The fallback is using {@link Function} execution if the a particular administrative (management) operation
|
||||
* is not supported or has not been implemented against the Management REST API interface over HTTP.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.admin.remote.FunctionGemfireAdminTemplate
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
|
||||
|
||||
protected static final boolean CREATE_REGION_SKIP_IF_EXISTS_DEFAULT = true;
|
||||
|
||||
protected static final int DEFAULT_PORT = 7070;
|
||||
|
||||
protected static final String DEFAULT_HOST = "localhost";
|
||||
|
||||
protected static final String MANAGEMENT_REST_API_URL_TEMPLATE = "http://%1$s:%2$d/gemfire/v1/";
|
||||
|
||||
private final RestOperations restTemplate;
|
||||
|
||||
private final String managementRestApiUrl;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link RestHttpGemfireAdminTemplate} initialized with
|
||||
* the given {@link ClientCache} and configured with the default host and port when accessing
|
||||
* the GemFire or Geode Management REST API interface.
|
||||
*
|
||||
* @param clientCache reference to the {@link ClientCache}
|
||||
* @throws IllegalArgumentException if the {@link ClientCache} reference is {@literal null}.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
*/
|
||||
public RestHttpGemfireAdminTemplate(ClientCache clientCache) {
|
||||
this(clientCache, DEFAULT_HOST, DEFAULT_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link RestHttpGemfireAdminTemplate} initialized with
|
||||
* the given {@link ClientCache} and configured with the specified host and port when accessing
|
||||
* the GemFire or Geode Management REST API interface.
|
||||
*
|
||||
* @param clientCache reference to the {@link ClientCache}
|
||||
* @param host {@link String} containing the hostname of the GemFire/Geode Manager.
|
||||
* @param port integer value specifying the port on which the GemFire/Geode Manager HTTP Service is listening
|
||||
* for HTTP clients.
|
||||
* @throws IllegalArgumentException if the {@link ClientCache} reference is {@literal null}.
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
*/
|
||||
public RestHttpGemfireAdminTemplate(ClientCache clientCache, String host, int port) {
|
||||
|
||||
super(clientCache);
|
||||
|
||||
this.restTemplate = newRestOperations();
|
||||
this.managementRestApiUrl = resolveManagementRestApiUrl(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the Spring {@link RestTemplate} to perform REST API operations over HTTP.
|
||||
*
|
||||
* @return a new instance of Spring's {@link RestTemplate}.
|
||||
* @see org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||
* @see org.springframework.web.client.RestOperations
|
||||
* @see org.springframework.web.client.RestTemplate
|
||||
*/
|
||||
RestOperations newRestOperations() {
|
||||
return new RestTemplate(new SimpleClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the Pivotal GemFire or Apache Geode Management REST API URL given the host and port
|
||||
* of the GemFire/Geode Manager's embedded HTTP service.
|
||||
*
|
||||
* @param host {@link String} containing the hostname of the Manager running the embedded HTTP service
|
||||
* and Management REST API.
|
||||
* @param port integer specifying the port that the embedded Manager's HTTP service is listening on.
|
||||
* @return the resolved URL.
|
||||
*/
|
||||
private String resolveManagementRestApiUrl(String host, int port) {
|
||||
return String.format(MANAGEMENT_REST_API_URL_TEMPLATE, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the resolved GemFire/Geode Management REST API URL.
|
||||
*
|
||||
* @return a {@link String} containing the resolved GemFire/Geode Management REST API URL.
|
||||
*/
|
||||
protected String getManagementRestApiUrl() {
|
||||
return this.managementRestApiUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link RestOperations} used to perform REST API calls.
|
||||
*
|
||||
* @return a reference to the {@link RestOperations} used to perform REST API calls.
|
||||
* @see org.springframework.web.client.RestOperations
|
||||
*/
|
||||
protected RestOperations getRestOperations() {
|
||||
return this.restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createIndex(IndexDefinition indexDefinition) {
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
// HTTP Message Body
|
||||
MultiValueMap<String, Object> requestParameters = new LinkedMultiValueMap<>();
|
||||
|
||||
requestParameters.add("name", indexDefinition.getName());
|
||||
requestParameters.add("expression", indexDefinition.getExpression());
|
||||
requestParameters.add("region", indexDefinition.getFromClause());
|
||||
requestParameters.add("type", indexDefinition.getIndexType().toString());
|
||||
|
||||
RequestEntity<MultiValueMap<String, Object>> requestEntity =
|
||||
new RequestEntity<>(requestParameters, httpHeaders, HttpMethod.POST, resolveCreateIndexUri());
|
||||
|
||||
ResponseEntity<String> response = getRestOperations().exchange(requestEntity, String.class);
|
||||
|
||||
// TODO do something with result; e.g. log when failure (or when not "OK")
|
||||
HttpStatus.OK.equals(response.getStatusCode());
|
||||
}
|
||||
|
||||
protected URI resolveCreateIndexUri() {
|
||||
return URI.create(getManagementRestApiUrl().concat("indexes"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRegion(RegionDefinition regionDefinition) {
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
// HTTP Message Body
|
||||
MultiValueMap<String, Object> requestParameters = new LinkedMultiValueMap<>();
|
||||
|
||||
requestParameters.add("name", regionDefinition.getName());
|
||||
requestParameters.add("type", regionDefinition.getRegionShortcut().toString());
|
||||
requestParameters.add("skip-if-exists", String.valueOf(CREATE_REGION_SKIP_IF_EXISTS_DEFAULT));
|
||||
|
||||
RequestEntity<MultiValueMap<String, Object>> requestEntity =
|
||||
new RequestEntity<>(requestParameters, httpHeaders, HttpMethod.POST, resolveCreateRegionUri());
|
||||
|
||||
ResponseEntity<String> response = getRestOperations().exchange(requestEntity, String.class);
|
||||
|
||||
// TODO do something with result; e.g. log when failure (or when not "OK")
|
||||
HttpStatus.OK.equals(response.getStatusCode());
|
||||
}
|
||||
|
||||
protected URI resolveCreateRegionUri() {
|
||||
return URI.create(getManagementRestApiUrl().concat("regions"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static java.util.stream.StreamSupport.stream;
|
||||
import static org.springframework.data.gemfire.util.CacheUtils.isClient;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.context.event.ApplicationContextEvent;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.gemfire.GemfireUtils;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.admin.remote.FunctionGemfireAdminTemplate;
|
||||
import org.springframework.data.gemfire.config.admin.remote.RestHttpGemfireAdminTemplate;
|
||||
import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectCollector;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.support.ClientRegionCollector;
|
||||
import org.springframework.data.gemfire.config.schema.support.ComposableSchemaObjectCollector;
|
||||
import org.springframework.data.gemfire.config.schema.support.ComposableSchemaObjectDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.support.IndexCollector;
|
||||
import org.springframework.data.gemfire.config.schema.support.IndexDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.support.RegionDefiner;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration @Configuration} class defining Spring beans that will record the creation of
|
||||
* Apache Geode / Pivotal GemFire {@link Region Regions} defined in Spring config (i.e. XML, Java or by Annotations)
|
||||
* as Spring beans in the Spring container.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.ImportAware
|
||||
* @see org.springframework.context.event.EventListener
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@SuppressWarnings("unused")
|
||||
public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
|
||||
|
||||
protected static final boolean DEFAULT_MANAGEMENT_USE_HTTP = false;
|
||||
|
||||
protected static final int DEFAULT_MANAGEMENT_HTTP_PORT = HttpServiceConfiguration.DEFAULT_HTTP_SERVICE_PORT;
|
||||
|
||||
protected static final String DEFAULT_MANAGEMENT_HTTP_HOST = "localhost";
|
||||
|
||||
private static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionDefinition.DEFAULT_REGION_SHORTCUT;
|
||||
|
||||
private Boolean useHttp = DEFAULT_MANAGEMENT_USE_HTTP;
|
||||
|
||||
private Integer managementHttpPort = DEFAULT_MANAGEMENT_HTTP_PORT;
|
||||
|
||||
private RegionShortcut serverRegionShortcut;
|
||||
|
||||
private String managementHttpHost = DEFAULT_MANAGEMENT_HTTP_HOST;
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotationType() {
|
||||
return EnableClusterConfiguration.class;
|
||||
}
|
||||
|
||||
protected void setManagementHttpHost(String hostname) {
|
||||
this.managementHttpHost = hostname;
|
||||
}
|
||||
|
||||
protected Optional<String> getManagementHttpHost() {
|
||||
return Optional.ofNullable(this.managementHttpHost);
|
||||
}
|
||||
|
||||
protected String resolveManagementHttpHost() {
|
||||
return getManagementHttpHost().orElse(DEFAULT_MANAGEMENT_HTTP_HOST);
|
||||
}
|
||||
|
||||
protected void setManagementHttpPort(Integer managementHttpPort) {
|
||||
this.managementHttpPort = managementHttpPort;
|
||||
}
|
||||
|
||||
protected Optional<Integer> getManagementHttpPort() {
|
||||
return Optional.ofNullable(this.managementHttpPort);
|
||||
}
|
||||
|
||||
protected int resolveManagementHttpPort() {
|
||||
return getManagementHttpPort().orElse(DEFAULT_MANAGEMENT_HTTP_PORT);
|
||||
}
|
||||
|
||||
protected void setManagementUseHttp(Boolean useHttp) {
|
||||
this.useHttp = useHttp;
|
||||
}
|
||||
|
||||
protected Optional<Boolean> getManagementUseHttp() {
|
||||
return Optional.ofNullable(this.useHttp);
|
||||
}
|
||||
|
||||
protected boolean resolveManagementUseHttp() {
|
||||
return getManagementUseHttp().orElse(DEFAULT_MANAGEMENT_USE_HTTP);
|
||||
}
|
||||
|
||||
protected void setServerRegionShortcut(RegionShortcut regionShortcut) {
|
||||
this.serverRegionShortcut = regionShortcut;
|
||||
}
|
||||
|
||||
protected Optional<RegionShortcut> getServerRegionShortcut() {
|
||||
return Optional.ofNullable(this.serverRegionShortcut);
|
||||
}
|
||||
|
||||
protected RegionShortcut resolveServerRegionShortcut() {
|
||||
return getServerRegionShortcut().orElse(DEFAULT_SERVER_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
|
||||
if (isAnnotationPresent(importMetadata)) {
|
||||
|
||||
AnnotationAttributes enableClusterConfigurationAttributes = getAnnotationAttributes(importMetadata);
|
||||
|
||||
setManagementHttpHost(resolveProperty(managementProperty("http.hostname"),
|
||||
DEFAULT_MANAGEMENT_HTTP_HOST));
|
||||
|
||||
setManagementHttpPort(resolveProperty(managementProperty("http.port"),
|
||||
DEFAULT_MANAGEMENT_HTTP_PORT));
|
||||
|
||||
setManagementUseHttp(resolveProperty(managementProperty("use-http"),
|
||||
DEFAULT_MANAGEMENT_USE_HTTP));
|
||||
|
||||
setServerRegionShortcut(resolveProperty(clusterProperty("region.type"),
|
||||
RegionShortcut.class, DEFAULT_SERVER_REGION_SHORTCUT));
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void gemfireClusterSchemaCreationHandler(ContextRefreshedEvent event) {
|
||||
|
||||
GemFireCache gemfireCache = resolveGemFireCache(event);
|
||||
|
||||
if (isClient(gemfireCache)) {
|
||||
|
||||
GemfireAdminOperations gemfireAdminOperations = newGemfireAdminOperations((ClientCache) gemfireCache);
|
||||
|
||||
SchemaObjectDefiner schemaObjectDefiner = newSchemaObjectDefiner();
|
||||
|
||||
Iterable<?> schemaObjects = newSchemaObjectCollector().collectFrom(resolveApplicationContext(event));
|
||||
|
||||
stream(schemaObjects.spliterator(), false)
|
||||
.map(schemaObjectDefiner::define)
|
||||
.sorted(OrderComparator.INSTANCE)
|
||||
.forEach(schemaObjectDefinition ->
|
||||
schemaObjectDefinition.ifPresent(it -> it.create(gemfireAdminOperations)));
|
||||
}
|
||||
/*
|
||||
else if (isPeer(gemfireCache)) {
|
||||
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(new CreateRegionFunction(),
|
||||
CreateRegionFunction.CREATE_REGION_FUNCTION_ID);
|
||||
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(new CreateIndexFunction(),
|
||||
CreateIndexFunction.CREATE_INDEX_FUNCTION_ID);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a reference to the Spring {@link ApplicationContext} from the given {@link ApplicationContextEvent}.
|
||||
*
|
||||
* @param event {@link ApplicationContextEvent} from which to resolve the Spring {@link ApplicationContext}.
|
||||
* @return the resolved Spring {@link ApplicationContext}.
|
||||
* @see org.springframework.context.event.ApplicationContextEvent
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
*/
|
||||
private ApplicationContext resolveApplicationContext(ApplicationContextEvent event) {
|
||||
return event.getApplicationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to resolve the {@link GemFireCache} from the Spring {@link ApplicationContext}.
|
||||
* The {@link GemFireCache} will be resolvable from the Spring {@link ApplicationContext} if the cache
|
||||
* was registered a managed bean in the Spring container.
|
||||
*
|
||||
* If the {@link GemFireCache} cannot be resolved from the {@link ApplicationContext}, this method will attempt
|
||||
* to resolve the cache reference from GemFire's global context using the GemFire API.
|
||||
*
|
||||
* @param event Spring {@link ApplicationContextEvent} encapsulating the details of the Spring container event.
|
||||
* @return the resolved {@link GemFireCache} if available.
|
||||
* @see org.springframework.context.event.ApplicationContextEvent
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
*/
|
||||
private GemFireCache resolveGemFireCache(ApplicationContextEvent event) {
|
||||
|
||||
try {
|
||||
return resolveApplicationContext(event).getBean(GemFireCache.class);
|
||||
}
|
||||
catch (BeansException ignore) {
|
||||
return GemfireUtils.resolveGemFireCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link GemfireAdminOperations} to perform administrative, schema functions
|
||||
* on a GemFire cache cluster as well as a client cache from a cache client.
|
||||
*
|
||||
* @param clientCache {@link ClientCache} instance used by the {@link GemfireAdminOperations} interface
|
||||
* to access the GemFire system.
|
||||
* @return an implementation of the {@link GemfireAdminOperations} interface to perform administrative functions
|
||||
* on a GemFire system.
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
*/
|
||||
private GemfireAdminOperations newGemfireAdminOperations(ClientCache clientCache) {
|
||||
|
||||
if (resolveManagementUseHttp()) {
|
||||
|
||||
String host = resolveManagementHttpHost();
|
||||
int port = resolveManagementHttpPort();
|
||||
|
||||
return new RestHttpGemfireAdminTemplate(clientCache, host, port);
|
||||
}
|
||||
else {
|
||||
return new FunctionGemfireAdminTemplate(clientCache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link SchemaObjectCollector} to inspect the application's context
|
||||
* and find all the GemFire schema objects declared of a particular type or types.
|
||||
*
|
||||
* @return a new instance of {@link SchemaObjectCollector} to inspect a GemFire system schema
|
||||
* in search of specific GemFire schema objects (e.g. {@link Region} or {@link Index}).
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectCollector
|
||||
*/
|
||||
private SchemaObjectCollector<?> newSchemaObjectCollector() {
|
||||
|
||||
return ComposableSchemaObjectCollector.compose(
|
||||
new ClientRegionCollector(),
|
||||
new IndexCollector()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link SchemaObjectDefiner} used to reverse engineer a GemFire schema object instance
|
||||
* to build a definition.
|
||||
*
|
||||
* @return a new instance of {@link SchemaObjectDefiner}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefiner
|
||||
*/
|
||||
private SchemaObjectDefiner newSchemaObjectDefiner() {
|
||||
|
||||
return ComposableSchemaObjectDefiner.compose(
|
||||
new RegionDefiner(resolveServerRegionShortcut()),
|
||||
new IndexDefiner()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* The {@link EnableClusterConfiguration} annotation enables Apache Geode / Pivotal GemFire schema-like definitions
|
||||
* defined in a Spring [Boot], Geode/GemFire cache client application using Spring config to be pushed to
|
||||
* a Geode/GemFire cluster, similar to how schema commands (e.g. `create region`) in Gfsh are processed by
|
||||
* an Geode/GemFire Manager.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.annotation.Documented
|
||||
* @see java.lang.annotation.Inherited
|
||||
* @see java.lang.annotation.Retention
|
||||
* @see java.lang.annotation.Target
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClusterConfigurationConfiguration
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Import(ClusterConfigurationConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public @interface EnableClusterConfiguration {
|
||||
|
||||
/**
|
||||
* Configures the bind address used by the Spring, GemFire/Geode cache client application to locate
|
||||
* the Manager's HTTP Service and access the Management REST API. This configuration setting is only used
|
||||
* when {@link #useHttp()} is set to {@literal true}.
|
||||
*
|
||||
* Alternatively, you can configure this setting using the {@literal spring.data.gemfire.management.http.host}
|
||||
* property in {@literal application.properties}.
|
||||
*
|
||||
* Defaults to {@literal localhost}.
|
||||
*/
|
||||
String host() default ClusterConfigurationConfiguration.DEFAULT_MANAGEMENT_HTTP_HOST;
|
||||
|
||||
/**
|
||||
* Configures the port used by the Spring, GemFire/Geode cache client application to locate
|
||||
* the Manager's HTTP Service and access the Management REST API. This configuration setting is only used
|
||||
* when {@link #useHttp()} is set to {@literal true}.
|
||||
*
|
||||
* Alternatively, you can configure this setting using the {@literal spring.data.gemfire.management.http.port}
|
||||
* property in {@literal application.properties}.
|
||||
*
|
||||
* Defaults to {@literal 7070}.
|
||||
*/
|
||||
int port() default ClusterConfigurationConfiguration.DEFAULT_MANAGEMENT_HTTP_PORT;
|
||||
|
||||
/**
|
||||
* Configuration setting used to specify the data management policy used when creating {@link Region Regions}
|
||||
* on the servers in the Geode/GemFire cluster.
|
||||
*
|
||||
* The data management policy is expressed with a {@link RegionShortcut}, but corresponds to the various
|
||||
* different {@link DataPolicy DataPolicies} available.
|
||||
*
|
||||
* Alternatively, you can configure this setting using the {@literal spring.data.gemfire.cluster.region.type}
|
||||
* property in {@literal application.properties}.
|
||||
*
|
||||
* Defaults to {@link RegionShortcut#PARTITION}.
|
||||
*/
|
||||
RegionShortcut serverRegionShortcut() default RegionShortcut.PARTITION;
|
||||
|
||||
/**
|
||||
* Configures whether connectivity between the Spring, GemFire/Geode application should be established using HTTP.
|
||||
*
|
||||
* Alternatively, you can configure this setting using the {@literal spring.data.gemfire.management.use-http}
|
||||
* property in {@literal application.properties}.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean useHttp() default ClusterConfigurationConfiguration.DEFAULT_MANAGEMENT_USE_HTTP;
|
||||
|
||||
}
|
||||
@@ -541,6 +541,11 @@ public abstract class AbstractAnnotationConfigSupport
|
||||
return String.format("%1$s%2$s.%3$s", propertyName("cache.server."), name, propertyNameSuffix);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected String clusterProperty(String propertyNameSuffix) {
|
||||
return String.format("%1$s%2$s", propertyName("cluster."), propertyNameSuffix);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected String diskStoreProperty(String propertyNameSuffix) {
|
||||
return String.format("%1$s%2$s", propertyName("disk.store."), propertyNameSuffix);
|
||||
@@ -561,6 +566,11 @@ public abstract class AbstractAnnotationConfigSupport
|
||||
return String.format("%1$s%2$s", propertyName("logging."), propertyNameSuffix);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected String managementProperty(String propertyNameSuffix) {
|
||||
return String.format("%1$s%2$s", propertyName("management."), propertyNameSuffix);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected String managerProperty(String propertyNameSuffix) {
|
||||
return String.format("%1$s%2$s", propertyName("manager."), propertyNameSuffix);
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* The {@link SchemaObjectCollector} interface defines a contract for implementing objects to search for
|
||||
* and find all schema objects of a particular type in a given context.
|
||||
*
|
||||
* Implementations of this interface know how to inspect the given context and find all references
|
||||
* to the schema object instances of a particular type.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public interface SchemaObjectCollector<T> {
|
||||
|
||||
/**
|
||||
* Collects all schema objects of type {@link T} declared in the given {@link ApplicationContext}.
|
||||
*
|
||||
* @param applicationContext Spring {@link ApplicationContext} from which to collect schema objects
|
||||
* of type {@link T}.
|
||||
* @return a {@link Set} of all schema objects of type {@link T} declared in the {@link ApplicationContext};
|
||||
* returns an empty {@link Set} if no schema object of type {@link T} could be found.
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
default Iterable<T> collectFrom(ApplicationContext applicationContext) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all schema objects of type {@link T} defined in the {@link GemFireCache}.
|
||||
*
|
||||
* @param gemfireCache {@link GemFireCache} from which to collect schema objects of type {@link T}.
|
||||
* @return a {@link Set} of all schema objects of type {@link T} defined in the {@link GemFireCache};
|
||||
* returns an empty {@link Set} if no schema object of type {@link T} could be found.
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
default Iterable<T> collectFrom(GemFireCache gemfireCache) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The {@link SchemaObjectDefiner} interface defines a contract for implementing objects
|
||||
* that can reverse engineer a schema object instance back into a definition of the schema object.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public interface SchemaObjectDefiner {
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} of {@link SchemaObjectType schema object types} definable by this definer.
|
||||
*
|
||||
* @return a {@link Set} of {@link SchemaObjectType schema object types} definable by this definer.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @see java.util.Set
|
||||
*/
|
||||
default Set<SchemaObjectType> getSchemaObjectTypes() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this definer is able to define the given {@link Object schema object} instance.
|
||||
*
|
||||
* @param schemaObject {@link Object} to evaluate.
|
||||
* @return a boolean value indicating whether this definer is able to define
|
||||
* the given {@link Object schema object} instance.
|
||||
* @see java.lang.Object#getClass()
|
||||
* @see #canDefine(Class)
|
||||
*/
|
||||
default boolean canDefine(Object schemaObject) {
|
||||
return Optional.ofNullable(schemaObject).map(Object::getClass).filter(this::canDefine).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this definer is able to define schema objects of the given {@link Class type}.
|
||||
*
|
||||
* @param schemaObjectType {@link Class type} of the {@link Object schema object} instance to evaluate.
|
||||
* @return a boolean value indicating whether this definer is able to define {@link Object schema objects}
|
||||
* of the given {@link Class type}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType#from(Class)
|
||||
* @see #canDefine(SchemaObjectType)
|
||||
*/
|
||||
default boolean canDefine(Class<?> schemaObjectType) {
|
||||
return canDefine(SchemaObjectType.from(schemaObjectType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this definer is able to define schema objects of the given
|
||||
* {@link SchemaObjectType enumerated schema object type}.
|
||||
*
|
||||
* @param schemaObjectType {@link SchemaObjectType} to evaluate.
|
||||
* @return a boolean value indicating whether this handler is able to handle schema objects
|
||||
* of the given {@link SchemaObjectType enumerated schema object type}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
*/
|
||||
default boolean canDefine(SchemaObjectType schemaObjectType) {
|
||||
return getSchemaObjectTypes().contains(schemaObjectType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} {@link SchemaObjectDefinition definition} for the given
|
||||
* {@link Object schema object} instance.
|
||||
*
|
||||
* @param schemaObject {@link Object schema object} to define.
|
||||
* @return an {@link Optional} {@link SchemaObjectDefinition definition} for the given
|
||||
* {@link Object schema object} instance.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
*/
|
||||
Optional<? extends SchemaObjectDefinition> define(Object schemaObject);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema;
|
||||
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link SchemaObjectDefinition} is an Abstract Data Type (ADT) encapsulating the definition of a single Apache Geode
|
||||
* or Pivotal GemFire schema object (e.g. {@link Region} or {@link Index}).
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.io.Serializable
|
||||
* @see org.springframework.core.Ordered
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefiner
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class SchemaObjectDefinition implements Serializable, Ordered {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link SchemaObjectDefinition} initialized with the specified {@link String name}.
|
||||
*
|
||||
* @param name {@link String name} given to the GemFire/Geode schema object; must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if name is not specified.
|
||||
*/
|
||||
public SchemaObjectDefinition(String name) {
|
||||
this.name = Optional.ofNullable(name).filter(StringUtils::hasText)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Name [%s] is required", name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link String name} assigned to the schema object.
|
||||
*
|
||||
* @return the {@link String name} assigned to the schema object; name is never {@literal null}.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SchemaObjectType type} of schema object defined by this {@link SchemaObjectDefinition}.
|
||||
*
|
||||
* @return the {@link SchemaObjectType type} of schema object defined by this {@link SchemaObjectDefinition}.
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
*/
|
||||
public abstract SchemaObjectType getType();
|
||||
|
||||
/**
|
||||
* Creates an actual schema object from this {@link SchemaObjectDefinition}.
|
||||
*
|
||||
* @param gemfireAdminOperations {@link GemfireAdminOperations} used to create an actual schema object from this
|
||||
* {@link SchemaObjectDefinition}.
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
*/
|
||||
public void create(GemfireAdminOperations gemfireAdminOperations) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof SchemaObjectDefinition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SchemaObjectDefinition that = (SchemaObjectDefinition) obj;
|
||||
|
||||
return this.getName().equals(that.getName())
|
||||
&& this.getType().equals(that.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int hashValue = 17;
|
||||
|
||||
hashValue = 37 * hashValue + this.getName().hashCode();
|
||||
hashValue = 37 * hashValue + this.getType().hashCode();
|
||||
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%1$s[%2$s]", getType(), getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.lucene.LuceneIndex;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.wan.GatewayReceiver;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
|
||||
/**
|
||||
* {@link SchemaObjectType} defines an enumeration of all the types of Apache Geode or Pivotal GemFire schema objects
|
||||
* (e.g. {@link Region}) that may possibly be handled by Spring Data Geode / Spring Data GemFire
|
||||
* and that can be created remotely, from a client application.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.asyncqueue.AsyncEventQueue
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.DiskStore
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @see org.apache.geode.cache.lucene.LuceneIndex
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.apache.geode.cache.wan.GatewayReceiver
|
||||
* @see org.apache.geode.cache.wan.GatewaySender
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum SchemaObjectType {
|
||||
|
||||
ASYNC_EVENT_QUEUE(AsyncEventQueue.class),
|
||||
CACHE(Cache.class),
|
||||
CLIENT_CACHE(ClientCache.class),
|
||||
DISK_STORE(DiskStore.class),
|
||||
FUNCTION(Function.class),
|
||||
GATEWAY_RECEIVER(GatewayReceiver.class),
|
||||
GATEWAY_SENDER(GatewaySender.class),
|
||||
INDEX(Index.class),
|
||||
LUCENE_INDEX(LuceneIndex.class),
|
||||
POOL(Pool.class),
|
||||
REGION(Region.class),
|
||||
UNKNOWN(Void.class);
|
||||
|
||||
private final Class<?> objectType;
|
||||
|
||||
/**
|
||||
* Constructs an instance of an {@link SchemaObjectType} enumerated value initialized with
|
||||
* the actual GemFire {@link Class schema object instance type}.
|
||||
*
|
||||
* @param objectType actual {@link Class interface type} of the GemFire schema object instance.
|
||||
* @see java.lang.Class
|
||||
*/
|
||||
SchemaObjectType(Class<?> objectType) {
|
||||
this.objectType = objectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe factory method used to look up and resolve the corresponding {@link SchemaObjectType}
|
||||
* given an instance of a GemFire schema object.
|
||||
*
|
||||
* For example, given an instance of {@link Region}, this factory method will return
|
||||
* {@link SchemaObjectType#REGION}.
|
||||
*
|
||||
* @param obj actual instance of a GemFire schema object, e.g. reference to a {@link Region}.
|
||||
* @return a corresponding {@link SchemaObjectType} for a given instance of a GemFire schema object.
|
||||
* If the type cannot be determined, then {@link SchemaObjectType#UNKNOWN} is returned.
|
||||
* @see #from(Class)
|
||||
*/
|
||||
public static SchemaObjectType from(Object obj) {
|
||||
return stream(SchemaObjectType.values())
|
||||
.filter(it -> it.getObjectType().isInstance(obj))
|
||||
.findFirst().orElse(UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe factory method used to look up and resolve the corresponding {@link SchemaObjectType}
|
||||
* given the type of GemFire schema object.
|
||||
*
|
||||
* For example, given the {@link Region} {@link Class interface} or any {@link Class sub-type} of {@link Region},
|
||||
* this factory method will return {@link SchemaObjectType#REGION}.
|
||||
*
|
||||
* @param type {@link Class type} of the GemFire schema object, e.g. the {@link Region} {@link Class interface}.
|
||||
* @return a corresponding {@link SchemaObjectType} for a given {@link Class type }of a GemFire schema object.
|
||||
* If the type cannot be determined, then {@link SchemaObjectType#UNKNOWN} is returned.
|
||||
* @see #from(Object)
|
||||
*/
|
||||
public static SchemaObjectType from(Class<?> type) {
|
||||
return stream(SchemaObjectType.values())
|
||||
.filter(it -> type != null && it.getObjectType().isAssignableFrom(type))
|
||||
.findFirst().orElse(UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Class class type} of the GemFire schema object represented by this enumerated value.
|
||||
*
|
||||
* @return the {@link Class class type} of the GemFire schema object represented by this enumerated value.
|
||||
* @see java.lang.Class
|
||||
*/
|
||||
public Class<?> getObjectType() {
|
||||
return this.objectType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.definitions;
|
||||
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.domain.support.AbstractIndexSupport;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link IndexDefinition} is an Abstract Data Type (ADT) encapsulating the configuration meta-data used to define
|
||||
* a new Apache Geode / Pivotal GemFire {@link Region} {@link Index}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.data.gemfire.IndexType
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class IndexDefinition extends SchemaObjectDefinition {
|
||||
|
||||
protected static final int ORDER = RegionDefinition.ORDER + 1;
|
||||
|
||||
/**
|
||||
* Factory method used to construct a new instance of {@link IndexDefinition} defined from the given {@link Index}.
|
||||
*
|
||||
* @param index {@link Index} on which the new {@link IndexDefinition} will be defined;
|
||||
* must not be {@literal null}.
|
||||
* @return a new instance of {@link IndexDefinition} defined from the given {@link Index}.
|
||||
* @throws IllegalArgumentException if {@link Index} is {@literal null}.
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
*/
|
||||
public static IndexDefinition from(Index index) {
|
||||
return new IndexDefinition(index);
|
||||
}
|
||||
|
||||
private transient Index index;
|
||||
|
||||
private IndexType indexType;
|
||||
|
||||
private String expression;
|
||||
private String fromClause;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link IndexDefinition} defined with the given {@link Index}.
|
||||
*
|
||||
* @param index {@link Index} on which this definition is defined; must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link Index} is {@literal null}.
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
*/
|
||||
protected IndexDefinition(Index index) {
|
||||
|
||||
super(Optional.ofNullable(index).map(Index::getName)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Index is required")));
|
||||
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link Index} on which this definition is defined.
|
||||
*
|
||||
* @return a reference to the {@link Index} on which this definition is defined.
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
*/
|
||||
protected Index getIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Optional.ofNullable(this.name).filter(StringUtils::hasText).orElseGet(super::getName);
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return Optional.ofNullable(this.expression).filter(StringUtils::hasText)
|
||||
.orElseGet(this.index::getIndexedExpression);
|
||||
}
|
||||
|
||||
public String getFromClause() {
|
||||
return Optional.ofNullable(this.fromClause).filter(StringUtils::hasText)
|
||||
.orElseGet(this.index::getFromClause);
|
||||
}
|
||||
|
||||
public IndexType getIndexType() {
|
||||
return Optional.ofNullable(this.indexType).orElseGet(() -> IndexType.valueOf(this.index.getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order value of this object.
|
||||
*
|
||||
* @return the order value of this object.
|
||||
* @see org.springframework.core.Ordered
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ORDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaObjectType getType() {
|
||||
return SchemaObjectType.INDEX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(GemfireAdminOperations gemfireAdminOperations) {
|
||||
gemfireAdminOperations.createIndex(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public IndexDefinition as(org.apache.geode.cache.query.IndexType gemfireGeodeIndexType) {
|
||||
return as(IndexType.valueOf(gemfireGeodeIndexType));
|
||||
}
|
||||
|
||||
public IndexDefinition as(IndexType indexType) {
|
||||
this.indexType = indexType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexDefinition having(String expression) {
|
||||
|
||||
this.expression = Optional.ofNullable(expression).filter(StringUtils::hasText)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Expression is required"));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexDefinition on(Region<?, ?> region) {
|
||||
return on(Optional.ofNullable(region).map(Region::getFullPath)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Region is required")));
|
||||
}
|
||||
|
||||
public IndexDefinition on(String fromClause) {
|
||||
|
||||
this.fromClause = Optional.ofNullable(fromClause).filter(StringUtils::hasText)
|
||||
.orElseThrow(() -> newIllegalArgumentException("From Clause is required"));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexDefinition with(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream outputStream) throws IOException {
|
||||
outputStream.writeUTF(getName());
|
||||
outputStream.writeUTF(getExpression());
|
||||
outputStream.writeUTF(getFromClause());
|
||||
outputStream.writeObject(getIndexType());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException {
|
||||
|
||||
String name = inputStream.readUTF();
|
||||
String expression = inputStream.readUTF();
|
||||
String fromClause = inputStream.readUTF();
|
||||
|
||||
IndexType indexType = (IndexType) inputStream.readObject();
|
||||
|
||||
this.index = IndexWrapper.from(name, expression, fromClause, indexType);
|
||||
}
|
||||
|
||||
protected static final class IndexWrapper extends AbstractIndexSupport {
|
||||
|
||||
private IndexType indexType;
|
||||
|
||||
private final String name;
|
||||
private final String expression;
|
||||
private final String fromClause;
|
||||
|
||||
protected static Index from(String name, String expression, String fromClause, IndexType indexType) {
|
||||
return new IndexWrapper(name, expression, fromClause, indexType);
|
||||
}
|
||||
|
||||
protected IndexWrapper(String name, String expression, String fromClause, IndexType indexType) {
|
||||
this.name = name;
|
||||
this.expression = expression;
|
||||
this.fromClause = fromClause;
|
||||
this.indexType = indexType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromClause() {
|
||||
return this.fromClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexedExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public org.apache.geode.cache.query.IndexType getType() {
|
||||
return Optional.ofNullable(this.indexType).map(IndexType::getGemfireIndexType).orElse(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.definitions;
|
||||
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link RegionDefinition} is an Abstract Data Type (ADT) encapsulating the configuration meta-data used to
|
||||
* define a new Apache Geode / Pivotal GemFire cache {@link Region}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.RegionShortcut
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class RegionDefinition extends SchemaObjectDefinition {
|
||||
|
||||
protected static final int ORDER = 1;
|
||||
|
||||
public static final RegionShortcut DEFAULT_REGION_SHORTCUT = RegionShortcut.PARTITION;
|
||||
|
||||
/**
|
||||
* Factory method used to construct a new instance of {@link RegionDefinition} defined from
|
||||
* the given {@link Region}.
|
||||
*
|
||||
* @param region {@link Region} from which the new definition will be defined.
|
||||
* @return a new instance of {@link RegionDefinition} defined from the given {@link Region}.
|
||||
* @throws IllegalArgumentException if {@link Region} is {@literal null}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see #RegionDefinition(Region)
|
||||
*/
|
||||
public static RegionDefinition from(Region<?, ?> region) {
|
||||
return Optional.ofNullable(region).map(RegionDefinition::new)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Region is required"));
|
||||
}
|
||||
|
||||
private final transient Region<?, ?> region;
|
||||
|
||||
private RegionShortcut regionShortcut;
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link RegionDefinition} defined with the given {@link Region}.
|
||||
*
|
||||
* @param region {@link Region} on which this definition is defined; must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link Region} is {@literal null}.
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
protected RegionDefinition(Region<?, ?> region) {
|
||||
|
||||
super(Optional.ofNullable(region).map(Region::getName)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Region is required")));
|
||||
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order value of this object.
|
||||
*
|
||||
* @return the order value of this object.
|
||||
* @see org.springframework.core.Ordered
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ORDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link Region} from which this definition is defined.
|
||||
*
|
||||
* @return a reference to the {@link Region} from which this definition is defined.
|
||||
* @see org.apache.geode.cache.Region
|
||||
*/
|
||||
protected Region<?, ?> getRegion() {
|
||||
return this.region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Optional.ofNullable(this.name).filter(StringUtils::hasText).orElseGet(super::getName);
|
||||
}
|
||||
|
||||
public RegionShortcut getRegionShortcut() {
|
||||
return Optional.ofNullable(this.regionShortcut).orElse(DEFAULT_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaObjectType getType() {
|
||||
return SchemaObjectType.REGION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(GemfireAdminOperations gemfireAdminOperations) {
|
||||
gemfireAdminOperations.createRegion(this);
|
||||
}
|
||||
|
||||
public RegionDefinition having(RegionShortcut regionShortcut) {
|
||||
this.regionShortcut = regionShortcut;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RegionDefinition with(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream outputStream) throws IOException {
|
||||
outputStream.writeUTF(getName());
|
||||
outputStream.writeObject(getRegionShortcut());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException {
|
||||
this.name = inputStream.readUTF();
|
||||
this.regionShortcut = (RegionShortcut) inputStream.readObject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeSet;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.util.RegionUtils;
|
||||
|
||||
/**
|
||||
* The {@link ClientRegionCollector} class is an extension of the {@link RegionCollector} which applies additional
|
||||
* filtering to find only client {@link Region Regions} in a given context.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ClientRegionCollector extends RegionCollector {
|
||||
|
||||
@Override
|
||||
public Set<Region> collectFrom(ApplicationContext applicationContext) {
|
||||
return onlyClientRegions(super.collectFrom(applicationContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Region> collectFrom(GemFireCache gemfireCache) {
|
||||
return onlyClientRegions(super.collectFrom(gemfireCache));
|
||||
}
|
||||
|
||||
private Set<Region> onlyClientRegions(Set<Region> regions) {
|
||||
return nullSafeSet(regions).stream().filter(RegionUtils::isClient).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static java.util.stream.StreamSupport.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectCollector;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link ComposableSchemaObjectCollector} class is a {@link SchemaObjectCollector} implementation composed of
|
||||
* multiple {@link SchemaObjectCollector} objects wrapped in a facade and treated like a single
|
||||
* {@link SchemaObjectCollector} using the Composite Software Design Pattern.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class ComposableSchemaObjectCollector
|
||||
implements SchemaObjectCollector<Object>, Iterable<SchemaObjectCollector<?>> {
|
||||
|
||||
private final List<SchemaObjectCollector<?>> schemaObjectCollectors;
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static SchemaObjectCollector<?> compose(SchemaObjectCollector<?>... schemaObjectCollectors) {
|
||||
return compose(Arrays.asList(nullSafeArray(schemaObjectCollectors, SchemaObjectCollector.class)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SchemaObjectCollector<?> compose(Iterable<SchemaObjectCollector<?>> schemaObjectCollectors) {
|
||||
|
||||
List<SchemaObjectCollector<?>> schemaObjectCollectorList =
|
||||
stream(nullSafeIterable(schemaObjectCollectors).spliterator(), false)
|
||||
.filter(Objects::nonNull).collect(Collectors.toList());
|
||||
|
||||
return (schemaObjectCollectorList.isEmpty() ? null
|
||||
: (schemaObjectCollectorList.size() == 1 ? schemaObjectCollectorList.iterator().next()
|
||||
: new ComposableSchemaObjectCollector(schemaObjectCollectorList)));
|
||||
}
|
||||
|
||||
private ComposableSchemaObjectCollector(List<SchemaObjectCollector<?>> schemaObjectCollectors) {
|
||||
this.schemaObjectCollectors = Collections.unmodifiableList(schemaObjectCollectors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Object> collectFrom(ApplicationContext applicationContext) {
|
||||
return collectFrom(collector -> collector.collectFrom(applicationContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Object> collectFrom(GemFireCache gemfireCache) {
|
||||
return collectFrom(collector -> collector.collectFrom(gemfireCache));
|
||||
}
|
||||
|
||||
private Iterable<Object> collectFrom(Function<SchemaObjectCollector<?>, Iterable<?>> schemaObjectSource) {
|
||||
|
||||
return this.schemaObjectCollectors.stream()
|
||||
.flatMap(collector -> stream(schemaObjectSource.apply(collector).spliterator(), false))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<SchemaObjectCollector<?>> iterator() {
|
||||
return Collections.unmodifiableList(this.schemaObjectCollectors).iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static java.util.stream.StreamSupport.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ComposableSchemaObjectDefiner} is an implementation of {@link SchemaObjectDefiner}
|
||||
* as well as a composition of {@link SchemaObjectDefiner SchemaObjectInstanceHandlers} composed
|
||||
* using the Composite Software Design Pattern.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.Iterable
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefiner
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class ComposableSchemaObjectDefiner
|
||||
implements SchemaObjectDefiner, Iterable<SchemaObjectDefiner> {
|
||||
|
||||
@Nullable
|
||||
public static SchemaObjectDefiner compose(SchemaObjectDefiner... schemaObjectDefiners) {
|
||||
return compose(Arrays.asList(nullSafeArray(schemaObjectDefiners, SchemaObjectDefiner.class)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SchemaObjectDefiner compose(Iterable<SchemaObjectDefiner> schemaObjectDefiners) {
|
||||
|
||||
Set<SchemaObjectDefiner> schemaObjectDefinerSet =
|
||||
stream(nullSafeIterable(schemaObjectDefiners).spliterator(), false)
|
||||
.filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
|
||||
return (schemaObjectDefinerSet.isEmpty() ? null
|
||||
: (schemaObjectDefinerSet.size() == 1 ? schemaObjectDefinerSet.iterator().next()
|
||||
: new ComposableSchemaObjectDefiner(schemaObjectDefinerSet)));
|
||||
}
|
||||
|
||||
private final Set<SchemaObjectDefiner> schemaObjectDefiners;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link ComposableSchemaObjectDefiner} initialized and compose of
|
||||
* the given {@link Set} of {@link SchemaObjectDefiner SchemaObjectInstanceHandlers}.
|
||||
*
|
||||
* @param schemaObjectDefiners {@link Set} of {@link SchemaObjectDefiner SchemaObjectInstanceHandlers}
|
||||
* from which this {@link ComposableSchemaObjectDefiner} is composed.
|
||||
* @see SchemaObjectDefiner
|
||||
*/
|
||||
private ComposableSchemaObjectDefiner(Set<SchemaObjectDefiner> schemaObjectDefiners) {
|
||||
this.schemaObjectDefiners = Collections.unmodifiableSet(schemaObjectDefiners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SchemaObjectType> getSchemaObjectTypes() {
|
||||
return this.schemaObjectDefiners.stream()
|
||||
.flatMap(it -> it.getSchemaObjectTypes().stream())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<? extends SchemaObjectDefinition> define(Object schemaObject) {
|
||||
|
||||
return this.schemaObjectDefiners.stream()
|
||||
.filter(it -> it.canDefine(schemaObject)).findAny()
|
||||
.map(it -> it.define(schemaObject).orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<SchemaObjectDefiner> iterator() {
|
||||
return Collections.unmodifiableSet(this.schemaObjectDefiners).iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectCollector;
|
||||
|
||||
/**
|
||||
* The {@link IndexCollector} class is an implementation of the {@link SchemaObjectCollector} that is capable of
|
||||
* inspecting a context and finding all {@link Index} schema object instances that have been declared in that context.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class IndexCollector implements SchemaObjectCollector<Index> {
|
||||
|
||||
@Override
|
||||
public Set<Index> collectFrom(ApplicationContext applicationContext) {
|
||||
return applicationContext.getBeansOfType(Index.class).values().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Index> collectFrom(GemFireCache gemfireCache) {
|
||||
return gemfireCache.getQueryService().getIndexes().stream().collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
|
||||
/**
|
||||
* The {@link {{@link IndexDefiner }} class is responsible for defining an {@link Index} given a reference to
|
||||
* an {@link Index} instance.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefiner
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class IndexDefiner implements SchemaObjectDefiner {
|
||||
|
||||
@Override
|
||||
public Set<SchemaObjectType> getSchemaObjectTypes() {
|
||||
return asSet(SchemaObjectType.INDEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IndexDefinition> define(Object schemaObject) {
|
||||
return Optional.ofNullable(schemaObject).filter(this::canDefine).map(it -> IndexDefinition.from((Index) it));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectCollector;
|
||||
|
||||
/**
|
||||
* The {@link RegionCollector} class is an implementation of the {@link SchemaObjectCollector} that is capable of
|
||||
* inspecting a context and finding all {@link Region} schema object instances that have been declared in that context.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class RegionCollector implements SchemaObjectCollector<Region> {
|
||||
|
||||
@Override
|
||||
public Set<Region> collectFrom(ApplicationContext applicationContext) {
|
||||
return applicationContext.getBeansOfType(Region.class).values().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Region> collectFrom(GemFireCache gemfireCache) {
|
||||
return gemfireCache.rootRegions().stream().collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.data.gemfire.util.RegionUtils;
|
||||
|
||||
/**
|
||||
* The {@link {RegionDefiner} class is responsible for defining a {@link Region}
|
||||
* given a reference to a {@link Region} instance.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.RegionAttributes
|
||||
* @see org.apache.geode.cache.RegionShortcut
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefiner
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class RegionDefiner implements SchemaObjectDefiner {
|
||||
|
||||
private final RegionShortcut regionShortcut;
|
||||
|
||||
public RegionDefiner() {
|
||||
this(RegionDefinition.DEFAULT_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
public RegionDefiner(RegionShortcut regionShortcut) {
|
||||
this.regionShortcut = regionShortcut;
|
||||
}
|
||||
|
||||
protected RegionShortcut getRegionShortcut() {
|
||||
return Optional.ofNullable(this.regionShortcut).orElse(RegionDefinition.DEFAULT_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SchemaObjectType> getSchemaObjectTypes() {
|
||||
return asSet(SchemaObjectType.REGION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RegionDefinition> define(Object schemaObject) {
|
||||
|
||||
return Optional.ofNullable(schemaObject)
|
||||
.filter(this::canDefine)
|
||||
.map(it -> (Region) it)
|
||||
.filter(RegionUtils::isClient)
|
||||
.map(it -> RegionDefinition.from(it).having(getRegionShortcut()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2017 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.domain.support;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.query.IndexStatistics;
|
||||
import org.apache.geode.cache.query.IndexType;
|
||||
|
||||
/**
|
||||
* {@link AbstractIndexSupport} is an abstract base class supporting the implementation
|
||||
* of the Pivotal GemFire / Apache Geode {@link Index} interface.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class AbstractIndexSupport implements Index {
|
||||
|
||||
private static final String NOT_IMPLEMENTED = "Not Implemented";
|
||||
|
||||
@Override
|
||||
public String getCanonicalizedFromClause() {
|
||||
return getFromClause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCanonicalizedIndexedExpression() {
|
||||
return getIndexedExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCanonicalizedProjectionAttributes() {
|
||||
return getProjectionAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromClause() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexedExpression() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectionAttributes() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region<?, ?> getRegion() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexStatistics getStatistics() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public IndexType getType() {
|
||||
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
||||
@@ -13,80 +13,269 @@
|
||||
|
||||
package org.springframework.data.gemfire.function;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.execute.FunctionService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility class for registering a POJO as a GemFire/Geode {@link Function}.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @see org.apache.geode.cache.execute.FunctionService
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public abstract class GemfireFunctionUtils {
|
||||
|
||||
private static Log log = LogFactory.getLog(GemfireFunctionUtils.class);
|
||||
|
||||
/**
|
||||
* Wrap a target object and method in a GemFire Function and register the function to the {@link FunctionService}
|
||||
* Determines whether the given {@link Method} is a POJO, {@link GemfireFunction} annotated {@link Method}.
|
||||
*
|
||||
* @param target the target object
|
||||
* @param method the method bound to the function
|
||||
* @param attributes function attributes
|
||||
* @param overwrite if true, will replace the existing function
|
||||
* @param method {@link Method} to evaluate.
|
||||
* @return a boolean value indicating whether the {@link Method} on a POJO represents a SDG {@link GemfireFunction}.
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see java.lang.reflect.Method
|
||||
*/
|
||||
public static void registerFunctionForPojoMethod(Object target, Method method, Map<String, Object> attributes,
|
||||
boolean overwrite) {
|
||||
public static boolean isGemfireFunction(Method method) {
|
||||
return (method != null && method.isAnnotationPresent(GemfireFunction.class));
|
||||
}
|
||||
|
||||
String id = attributes.containsKey("id") ? (String) attributes.get("id") : "";
|
||||
private static boolean isMatchingGemfireFunction(Method method, String functionId) {
|
||||
return getGemfireFunctionId(method).filter(methodFunctionId ->
|
||||
ObjectUtils.nullSafeEquals(methodFunctionId, functionId)).isPresent();
|
||||
}
|
||||
|
||||
private static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return AnnotationAttributes.fromMap(
|
||||
AnnotationUtils.getAnnotationAttributes(element, element.getAnnotation(annotationType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe operation used to determine the GemFire/Geode {@link Function#getId()} Function ID}
|
||||
* of a given {@link GemfireFunction} annotated POJO {@link Method}.
|
||||
*
|
||||
* If the {@link Method} is not {@literal null} and annotated with {@link GemfireFunction} then this method
|
||||
* tries to determine the {@link Function#getId()} from the {@link GemfireFunction#id()} attribute.
|
||||
*
|
||||
* If the {@link GemfireFunction#id()} attribute was not set, then the {@link Method#getName()}
|
||||
* is returned as the {@link Function#getId() Function ID}.
|
||||
*
|
||||
* @param method {@link GemfireFunction} annotated POJO {@link Method} containing the implementation
|
||||
* for a GemFire/Geode {@link Function}.
|
||||
* @return the GemFire/Geode Function ID of the given {@link Method}, or an empty {@link Optional}
|
||||
* if the {@link Method} is not a GemFire/Geode {@link Function}.
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see java.lang.reflect.Method
|
||||
* @see #isGemfireFunction(Method)
|
||||
*/
|
||||
private static Optional<String> getGemfireFunctionId(Method method) {
|
||||
|
||||
return Optional.ofNullable(method)
|
||||
.filter(GemfireFunctionUtils::isGemfireFunction)
|
||||
.map(it ->
|
||||
Optional.of(it.getAnnotation(GemfireFunction.class))
|
||||
.map(annotation -> getAnnotationAttributes(it, annotation.getClass()))
|
||||
.filter(annotationAttributes -> annotationAttributes.containsKey("id"))
|
||||
.map(annotationAttributes -> annotationAttributes.getString("id"))
|
||||
.filter(StringUtils::hasText)
|
||||
.orElseGet(() -> it.getName())
|
||||
);
|
||||
}
|
||||
|
||||
private static Object constructInstance(Class<?> type, Object... constructorArguments) {
|
||||
|
||||
return org.springframework.data.util.ReflectionUtils.findConstructor(type, constructorArguments)
|
||||
.map(constructor -> BeanUtils.instantiateClass(constructor, constructorArguments))
|
||||
.orElseThrow(() -> newIllegalArgumentException(
|
||||
"No suitable constructor was found for type [%s] having parameters [%s]", type.getName(),
|
||||
stream(nullSafeArray(constructorArguments, Object.class)).map(ObjectUtils::nullSafeClassName)
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
private static String nullSafeName(Method method) {
|
||||
|
||||
return Optional.ofNullable(method)
|
||||
.map(it -> String.format("%s.%s", method.getDeclaringClass().getName(), method.getName()))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a {@link Method method} with the given {@link Function#getId() Function ID} on an object
|
||||
* of the given {@link Class type} as a {@link Function} and register it with the {@link FunctionService}.
|
||||
*
|
||||
* @param type {@link Class target type} to evaluate; must not be {@literal null}.
|
||||
* @param functionId {@link String} containing the {@link Function#getId()} identifying the {@link Method}
|
||||
* on the {@link Class target type} to bind as a {@link Function}.
|
||||
* @throws IllegalArgumentException if {@link Class type} is {@literal null}.
|
||||
* @see #registerFunctionForPojoMethod(Object, Method, AnnotationAttributes, boolean)
|
||||
* @see #isMatchingGemfireFunction(Method, String)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void registerFunctionForPojoMethod(Class<?> type, String functionId) {
|
||||
|
||||
Assert.notNull(type, () -> String.format("Class type of POJO containing %s(s) is required",
|
||||
GemfireFunction.class.getName()));
|
||||
|
||||
ReflectionUtils.doWithMethods(type,
|
||||
method -> registerFunctionForPojoMethod(constructInstance(type), method,
|
||||
getAnnotationAttributes(method, GemfireFunction.class), true),
|
||||
method -> isMatchingGemfireFunction(method, functionId));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a {@link Method method} with the given {@link Function#getId() Function ID} on the given {@link Object target}
|
||||
* as a {@link Function} and register it with the {@link FunctionService}.
|
||||
*
|
||||
* @param target {@link Object target object} to evaluate; must not be {@literal null}.
|
||||
* @param functionId {@link String} containing the {@link Function#getId()} identifying the {@link Method}
|
||||
* on the {@link Object target object} to bind as a {@link Function}.
|
||||
* @throws IllegalArgumentException if {@link Object target} is {@literal null}.
|
||||
* @see #registerFunctionForPojoMethod(Object, Method, AnnotationAttributes, boolean)
|
||||
* @see #isMatchingGemfireFunction(Method, String)
|
||||
*/
|
||||
public static void registerFunctionForPojoMethod(Object target, String functionId) {
|
||||
|
||||
Assert.notNull(target, "Target object is required");
|
||||
|
||||
ReflectionUtils.doWithMethods(target.getClass(),
|
||||
method -> registerFunctionForPojoMethod(target, method,
|
||||
getAnnotationAttributes(method, GemfireFunction.class), true),
|
||||
method -> isMatchingGemfireFunction(method, functionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given {@link Method method} on the given {@link Object target} as a {@link Function}
|
||||
* and registers it with the {@link FunctionService}.
|
||||
*
|
||||
* @param target {@link Object target object} to evaluate; must not be {@literal null}.
|
||||
* @param method {@link Method} on {@link Object target} bound as a {@link Function}.
|
||||
* @param overwrite if {@literal true}, will replace any existing {@link Function}
|
||||
* having the same {@link Function#getId() ID}.
|
||||
* @throws IllegalArgumentException if {@link Object target} is {@literal null} or the given {@link Method}
|
||||
* is not a {@link GemfireFunction}.
|
||||
* @see #registerFunctionForPojoMethod(Object, Method, AnnotationAttributes, boolean)
|
||||
* @see #isGemfireFunction(Method)
|
||||
*/
|
||||
public static void registerFunctionForPojoMethod(Object target, Method method, boolean overwrite) {
|
||||
|
||||
Assert.notNull(target, "Target object is required");
|
||||
|
||||
Assert.isTrue(isGemfireFunction(method), () -> String.format("Method [%s] must be a %s",
|
||||
nullSafeName(method), GemfireFunction.class.getName()));
|
||||
|
||||
registerFunctionForPojoMethod(target, method, getAnnotationAttributes(method, GemfireFunction.class), overwrite);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the {@link Object target object} and {@link Method method} in a GemFire/Geode {@link Function}
|
||||
* and register the {@link Function} with the {@link FunctionService}.
|
||||
*
|
||||
* @param target {@link Object target object}.
|
||||
* @param method {@link Method} bound to a {@link Function}.
|
||||
* @param gemfireFunctionAttributes {@link GemfireFunction} annotation {@link Map attributes}.
|
||||
* @param overwrite if {@literal true}, will replace any existing {@link Function} having the same ID.
|
||||
* @deprecated use {@link #registerFunctionForPojoMethod(Object, Method, AnnotationAttributes, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void registerFunctionForPojoMethod(Object target, Method method,
|
||||
Map<String, Object> gemfireFunctionAttributes, boolean overwrite) {
|
||||
|
||||
registerFunctionForPojoMethod(target, method, AnnotationAttributes.fromMap(gemfireFunctionAttributes), overwrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the {@link Object target object} and {@link Method method} in a GemFire/Geode {@link Function}
|
||||
* and register the {@link Function} with the {@link FunctionService}.
|
||||
*
|
||||
* @param target {@link Object target object}.
|
||||
* @param method {@link Method} bound to a {@link Function}.
|
||||
* @param gemfireFunctionAttributes {@link GemfireFunction} {@link AnnotationAttributes annotation attributes}.
|
||||
* @param overwrite if {@literal true}, will replace any existing {@link Function} having the same ID.
|
||||
*/
|
||||
public static void registerFunctionForPojoMethod(Object target, Method method,
|
||||
AnnotationAttributes gemfireFunctionAttributes, boolean overwrite) {
|
||||
|
||||
String id = gemfireFunctionAttributes.containsKey("id")
|
||||
? gemfireFunctionAttributes.getString("id") : "";
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(target, method, id);
|
||||
|
||||
if (attributes.containsKey("HA")) {
|
||||
function.setHA((Boolean) attributes.get("HA"));
|
||||
}
|
||||
if (gemfireFunctionAttributes.containsKey("batchSize")) {
|
||||
|
||||
if (attributes.containsKey("optimizeForWrite")) {
|
||||
function.setOptimizeForWrite((Boolean) attributes.get("optimizeForWrite"));
|
||||
}
|
||||
int batchSize = gemfireFunctionAttributes.getNumber("batchSize");
|
||||
|
||||
Assert.isTrue(batchSize >= 0,
|
||||
String.format("batchSize [%1$d] specified on [%2$s.%3$s] must be a non-negative value",
|
||||
batchSize, target.getClass().getName(), method.getName()));
|
||||
|
||||
if (attributes.containsKey("batchSize")) {
|
||||
int batchSize = (Integer) attributes.get("batchSize");
|
||||
Assert.isTrue(batchSize >= 0, String.format("batchSize must be a non-negative value %1$s.%2$s",
|
||||
target.getClass().getName(), method.getName()));
|
||||
function.setBatchSize(batchSize);
|
||||
}
|
||||
|
||||
if (attributes.containsKey("hasResult")) {
|
||||
// only set if true TODO figure out why???
|
||||
if (Boolean.TRUE.equals(attributes.get("hasResult"))) {
|
||||
if (gemfireFunctionAttributes.containsKey("HA")) {
|
||||
function.setHA(gemfireFunctionAttributes.getBoolean("HA"));
|
||||
}
|
||||
|
||||
if (gemfireFunctionAttributes.containsKey("hasResult")) {
|
||||
if (Boolean.TRUE.equals(gemfireFunctionAttributes.getBoolean("hasResult"))) {
|
||||
function.setHasResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (gemfireFunctionAttributes.containsKey("optimizeForWrite")) {
|
||||
function.setOptimizeForWrite(gemfireFunctionAttributes.getBoolean("optimizeForWrite"));
|
||||
}
|
||||
|
||||
if (FunctionService.isRegistered(function.getId())) {
|
||||
if (overwrite) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("unregistering function definition " + function.getId());
|
||||
log.debug(String.format("Unregistering Function [%s]", function.getId()));
|
||||
}
|
||||
|
||||
FunctionService.unregisterFunction(function.getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (!FunctionService.isRegistered(function.getId())) {
|
||||
|
||||
FunctionService.registerFunction(function);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("registered function " + function.getId());
|
||||
log.debug(String.format("Registered Function [%s]", function.getId()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("function " + function.getId() + "is already registered");
|
||||
log.debug(String.format("Function [%s] is already registered", function.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,16 +296,19 @@ public abstract class GemfireFunctionUtils {
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
|
||||
if (parameterAnnotations.length > 0) {
|
||||
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
List<Class<?>> requiredTypesList = Arrays.asList(requiredTypes);
|
||||
|
||||
for (int index = 0; index < parameterAnnotations.length; index++) {
|
||||
|
||||
Annotation[] annotations = parameterAnnotations[index];
|
||||
|
||||
if (annotations.length > 0) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType().equals(targetAnnotationType)) {
|
||||
|
||||
Assert.state(position < 0, String.format(
|
||||
"Method %s signature cannot contain more than one parameter annotated with type %s",
|
||||
method.getName(), targetAnnotationType.getName()));
|
||||
@@ -144,5 +336,4 @@ public abstract class GemfireFunctionUtils {
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.execute.FunctionContext;
|
||||
import org.apache.geode.cache.execute.ResultSender;
|
||||
@@ -24,16 +25,22 @@ import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Invokes a POJO's given method as a Gemfire remote function.
|
||||
* If the POJO has a constructor that takes a Map, and the function context is Region, the
|
||||
* region will be injected. The delegate class name, the method name, and the method arguments
|
||||
* are part of a remote function invocation, therefore all arguments must be serializable
|
||||
* or an alternate serialization method must be used.
|
||||
* The delegate class must be the class path of the remote cache(s)
|
||||
* @author David Turanski
|
||||
* Invokes a given {@link Object POJO} {@link Method} as a (remote) GemFire/Geode {@link Function}.
|
||||
*
|
||||
* If the {@link Object POJO} has a constructor that takes a {@link java.util.Map}, and the {@link Function} context
|
||||
* is a {@link Region}, the {@link Region} will be injected.
|
||||
*
|
||||
* The delegate {@link Class#getName() class name}, the {@link Method#getName() method name},
|
||||
* and {@link Method} arguments are part of the {@link Function} invocation, therefore all arguments
|
||||
* must be {@link java.io.Serializable} or an alternate serialization strategy must be used.
|
||||
*
|
||||
* The delegate {@link Class} must be on the class path of the remote cache(s).
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @since 1.2.0
|
||||
*/
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class PojoFunctionWrapper implements Function {
|
||||
|
||||
@@ -59,7 +66,7 @@ public class PojoFunctionWrapper implements Function {
|
||||
this.method = method;
|
||||
this.id = (StringUtils.hasText(id) ? id : method.getName());
|
||||
this.HA = false;
|
||||
this.hasResult = !(method.getReturnType().equals(void.class));
|
||||
this.hasResult = !method.getReturnType().equals(void.class);
|
||||
this.optimizeForWrite = false;
|
||||
}
|
||||
|
||||
@@ -100,7 +107,9 @@ public class PojoFunctionWrapper implements Function {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute(final FunctionContext functionContext) {
|
||||
|
||||
Object[] args = this.functionArgumentResolver.resolveFunctionArguments(functionContext);
|
||||
|
||||
Object result = invokeTargetMethod(args);
|
||||
@@ -111,19 +120,22 @@ public class PojoFunctionWrapper implements Function {
|
||||
}
|
||||
|
||||
protected final Object invokeTargetMethod(Object[] args) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("about to invoke method %s on class %s as function %s", method.getName(),
|
||||
target.getClass().getName(), this.id));
|
||||
|
||||
logger.debug(String.format("About to invoke method [%s] on class [%s] as Function [%s]",
|
||||
this.method.getName(), this.target.getClass().getName(), getId()));
|
||||
|
||||
for (Object arg : args) {
|
||||
logger.debug("arg:" + arg.getClass().getName() + " " + arg.toString());
|
||||
logger.debug(String.format("Argument of type [%s] is [%s]", arg.getClass().getName(), arg.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
return ReflectionUtils.invokeMethod(method, target, (Object[]) args);
|
||||
return ReflectionUtils.invokeMethod(this.method, this.target, (Object[]) args);
|
||||
}
|
||||
|
||||
private void sendResults(ResultSender<Object> resultSender, Object result) {
|
||||
|
||||
if (result == null) {
|
||||
resultSender.lastResult(null);
|
||||
}
|
||||
@@ -139,5 +151,4 @@ public class PojoFunctionWrapper implements Function {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2002-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.
|
||||
@@ -22,17 +22,20 @@ import java.lang.annotation.Target;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
*
|
||||
* Enables Gemfire annotated function implementations. Causes the container to discover any beans that are annotated
|
||||
* with {code} @GemfireFunction {code}, wrap them in a
|
||||
* {@link org.springframework.data.gemfire.function.PojoFunctionWrapper}, and register them with the cache.
|
||||
*
|
||||
* Enables GemFire annotated Function implementations.
|
||||
*
|
||||
* Causes the container to discover any beans that are annotated with {code}@GemfireFunction{code},
|
||||
* wrap them in a {@link org.springframework.data.gemfire.function.PojoFunctionWrapper},
|
||||
* and register them with the cache.
|
||||
*
|
||||
* @author David Turanski
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@Import(GemfireFunctionPostBeanProcessorRegistrar.class)
|
||||
@Documented
|
||||
@Import(GemfireFunctionBeanPostProcessorRegistrar.class)
|
||||
@SuppressWarnings("unused")
|
||||
public @interface EnableGemfireFunctions {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
/*
|
||||
* Copyright 2002-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.function.config;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.gemfire.function.GemfireFunctionUtils;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
@@ -25,48 +28,44 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A {@link BeanPostProcessor} to discover components wired as function implementations. That is
|
||||
* beans that contain methods annotated with {code} @GemfireFunction {code}
|
||||
*
|
||||
* @author David Turanski
|
||||
* Spring {@link BeanPostProcessor} that discovers bean components wired as Function implementations,
|
||||
* i.e. beans containing methods annotated with {@link GemfireFunction}.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
*/
|
||||
public class GemfireFunctionBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private static final String GEMFIRE_FUNCTION_ANNOTATION_NAME = GemfireFunction.class.getName();
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
registerAnyDeclaredGemfireFunctionMethods(bean);
|
||||
|
||||
|
||||
registerAnyDeclaredGemfireFunctionAnnotatedMethods(bean);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void registerAnyDeclaredGemfireFunctionMethods (Object bean) {
|
||||
|
||||
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
|
||||
|
||||
for (Method method: methods) {
|
||||
GemfireFunction annotation = AnnotationUtils.getAnnotation(method, GemfireFunction.class);
|
||||
if (annotation != null) {
|
||||
Assert.isTrue(Modifier.isPublic(method.getModifiers()),"The method " + method.getName()+ " annotated with" + GEMFIRE_FUNCTION_ANNOTATION_NAME+ " must be public");
|
||||
Map<String,Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation,false,true);
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(bean, method, attributes, false);
|
||||
|
||||
private void registerAnyDeclaredGemfireFunctionAnnotatedMethods(Object bean) {
|
||||
|
||||
stream(nullSafeArray(ReflectionUtils.getAllDeclaredMethods(bean.getClass()), Method.class)).forEach(method -> {
|
||||
|
||||
GemfireFunction gemfireFunctionAnnotation = AnnotationUtils.getAnnotation(method, GemfireFunction.class);
|
||||
|
||||
if (gemfireFunctionAnnotation != null) {
|
||||
|
||||
Assert.isTrue(Modifier.isPublic(method.getModifiers()),
|
||||
String.format("The bean [%s] method [%s] annotated with [%s] must be public",
|
||||
bean.getClass().getName(), method.getName(), GemfireFunction.class.getName()));
|
||||
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(
|
||||
AnnotationUtils.getAnnotationAttributes(gemfireFunctionAnnotation,false,true));
|
||||
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(bean, method, annotationAttributes, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2002-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.
|
||||
@@ -19,12 +19,11 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* and {@link ImportBeanDefinitionRegistrar} to register the {@link GemfireFunctionBeanPostProcessor}
|
||||
*
|
||||
* @author David Turanski
|
||||
* Spring {@link ImportBeanDefinitionRegistrar} to register the {@link GemfireFunctionBeanPostProcessor}
|
||||
*
|
||||
* @author David Turanski
|
||||
*/
|
||||
public class GemfireFunctionPostBeanProcessorRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
public class GemfireFunctionBeanPostProcessorRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
@@ -34,5 +33,4 @@ public class GemfireFunctionPostBeanProcessorRegistrar implements ImportBeanDefi
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(GemfireFunctionBeanPostProcessor.class);
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
* 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.function.execution;
|
||||
|
||||
package org.springframework.data.gemfire.function.execution;
|
||||
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface GemfireFunctionOperations {
|
||||
* @param args an array of Object arguments to the Function call.
|
||||
* @return the contents of the ResultsCollector.
|
||||
*/
|
||||
public abstract <T> Iterable<T> execute(Function function, Object... args);
|
||||
<T> Iterable<T> execute(Function function, Object... args);
|
||||
|
||||
/**
|
||||
* Execute a GemFire Function registered with the given ID.
|
||||
@@ -41,7 +41,7 @@ public interface GemfireFunctionOperations {
|
||||
* @param args an array of Object arguments to the Function call.
|
||||
* @return the results
|
||||
*/
|
||||
public abstract <T> Iterable<T> execute(String functionId, Object... args);
|
||||
<T> Iterable<T> execute(String functionId, Object... args);
|
||||
|
||||
/**
|
||||
* Execute an unregistered GemFire Function with the expected singleton result.
|
||||
@@ -52,7 +52,7 @@ public interface GemfireFunctionOperations {
|
||||
* @return the first item in the ResultsCollector.
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
*/
|
||||
public abstract <T> T executeAndExtract(Function function, Object... args);
|
||||
<T> T executeAndExtract(Function function, Object... args);
|
||||
|
||||
/**
|
||||
* Execute a GemFire Function registered with an ID and with an expected singleton result
|
||||
@@ -62,7 +62,7 @@ public interface GemfireFunctionOperations {
|
||||
* @param args an array of Object arguments to the Function call.
|
||||
* @return the first item in the results collector
|
||||
*/
|
||||
public abstract <T> T executeAndExtract(String functionId, Object... args);
|
||||
<T> T executeAndExtract(String functionId, Object... args);
|
||||
|
||||
/**
|
||||
* Execute a GemFire Function registered with the given ID having no return value.
|
||||
@@ -70,7 +70,7 @@ public interface GemfireFunctionOperations {
|
||||
* @param functionId the ID under which the GemFire function is registered.
|
||||
* @param args an array of Object arguments to the Function call.
|
||||
*/
|
||||
public void executeWithNoResult(String functionId, Object... args);
|
||||
void executeWithNoResult(String functionId, Object... args);
|
||||
|
||||
/**
|
||||
* Execute a GemFire Function using a native GemFire {@link org.apache.geode.cache.execute.Execution} instance.
|
||||
@@ -80,6 +80,6 @@ public interface GemfireFunctionOperations {
|
||||
* @return the Function execution result.
|
||||
* @see org.springframework.data.gemfire.function.execution.GemfireFunctionCallback
|
||||
*/
|
||||
public abstract <T> T execute(GemfireFunctionCallback<T> callback);
|
||||
<T> T execute(GemfireFunctionCallback<T> callback);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2017 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.util;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The RegionUtils class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class RegionUtils extends CacheUtils {
|
||||
|
||||
public static boolean isClient(Region region) {
|
||||
|
||||
return Optional.ofNullable(region)
|
||||
.map(Region::getAttributes)
|
||||
.map(RegionAttributes::getPoolName)
|
||||
.filter(StringUtils::hasText)
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ public abstract class SpringUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static BeanDefinition addDependsOn(BeanDefinition bean, String... beanNames) {
|
||||
|
||||
List<String> dependsOnList = new ArrayList<>();
|
||||
|
||||
Collections.addAll(dependsOnList, nullSafeArray(bean.getDependsOn(), String.class));
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
|
||||
/**
|
||||
* The GemfireAdminOperationsUnitTests class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GemfireAdminOperationsUnitTests {
|
||||
|
||||
@Mock
|
||||
private GemfireAdminOperations adminOperations;
|
||||
|
||||
private Index mockIndex(String name) {
|
||||
|
||||
Index mockIndex = mock(Index.class, name);
|
||||
|
||||
when(mockIndex.getName()).thenReturn(name);
|
||||
|
||||
return mockIndex;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, V> Region<K, V> mockRegion(String name) {
|
||||
|
||||
Region<K, V> mockRegion = mock(Region.class, name);
|
||||
|
||||
when(mockRegion.getName()).thenReturn(name);
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
private SchemaObjectDefinition newGenericSchemaObjectDefinition(String name, SchemaObjectType type) {
|
||||
return mock(SchemaObjectDefinition.class, name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRegionsWithArrayCallsCreateRegion() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createRegions(ArgumentMatchers.<RegionDefinition[]>any());
|
||||
|
||||
RegionDefinition definitionOne = RegionDefinition.from(mockRegion("RegionOne"));
|
||||
RegionDefinition definitionTwo = RegionDefinition.from(mockRegion("RegionTwo"));
|
||||
|
||||
adminOperations.createRegions(definitionOne, definitionTwo);
|
||||
|
||||
verify(adminOperations, times(1)).createRegion(eq(definitionOne));
|
||||
verify(adminOperations, times(1)).createRegion(eq(definitionTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRegionsWithEmptyArray() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createRegions(ArgumentMatchers.<RegionDefinition[]>any());
|
||||
|
||||
adminOperations.createRegions();
|
||||
|
||||
verify(adminOperations, never()).createRegion(any(RegionDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRegionsWithNullArray() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createRegions(ArgumentMatchers.<RegionDefinition[]>any());
|
||||
|
||||
adminOperations.createRegions((RegionDefinition[]) null);
|
||||
|
||||
verify(adminOperations, never()).createRegion(any(RegionDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createRegionsWithIterableCallsCreateRegion() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createRegions(any(Iterable.class));
|
||||
|
||||
RegionDefinition definitionOne = RegionDefinition.from(mockRegion("RegionOne"));
|
||||
RegionDefinition definitionTwo = RegionDefinition.from(mockRegion("RegionTwo"));
|
||||
|
||||
adminOperations.createRegions(Arrays.asList(definitionOne, definitionTwo));
|
||||
|
||||
verify(adminOperations, times(1)).createRegion(eq(definitionOne));
|
||||
verify(adminOperations, times(1)).createRegion(eq(definitionTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createRegionsWithEmptyIterableCallsCreateRegion() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createRegions(any(Iterable.class));
|
||||
|
||||
adminOperations.createRegions(Collections.emptyList());
|
||||
|
||||
verify(adminOperations, never()).createRegion(any(RegionDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createRegionsWithNullIterableCallsCreateRegion() {
|
||||
|
||||
adminOperations.createRegions((Iterable) null);
|
||||
|
||||
verify(adminOperations, never()).createRegion(any(RegionDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createLuceneIndexesWithArrayCallsCreateLuceneIndex() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createLuceneIndexes(ArgumentMatchers.<SchemaObjectDefinition[]>any());
|
||||
|
||||
SchemaObjectDefinition definitionOne = newGenericSchemaObjectDefinition("LucenIndexOne",
|
||||
SchemaObjectType.LUCENE_INDEX);
|
||||
|
||||
SchemaObjectDefinition definitionTwo = newGenericSchemaObjectDefinition("LucenIndexOne",
|
||||
SchemaObjectType.LUCENE_INDEX);
|
||||
|
||||
adminOperations.createLuceneIndexes(definitionOne, definitionTwo);
|
||||
|
||||
verify(adminOperations, times(1)).createLuceneIndex(eq(definitionOne));
|
||||
verify(adminOperations, times(1)).createLuceneIndex(eq(definitionTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createLuceneIndexesWithEmptyArray() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createLuceneIndexes(ArgumentMatchers.<SchemaObjectDefinition[]>any());
|
||||
|
||||
adminOperations.createLuceneIndexes();
|
||||
|
||||
verify(adminOperations, never()).createLuceneIndex(any(SchemaObjectDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createLuceneIndexesWithNullArray() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createLuceneIndexes(ArgumentMatchers.<SchemaObjectDefinition[]>any());
|
||||
|
||||
adminOperations.createLuceneIndexes((SchemaObjectDefinition) null);
|
||||
|
||||
verify(adminOperations, never()).createLuceneIndex(any(SchemaObjectDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createLuceneIndexesWithIterableCallsCreateLuceneIndex() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createLuceneIndexes(any(Iterable.class));
|
||||
|
||||
SchemaObjectDefinition definitionOne = newGenericSchemaObjectDefinition("LucenIndexOne",
|
||||
SchemaObjectType.LUCENE_INDEX);
|
||||
|
||||
SchemaObjectDefinition definitionTwo = newGenericSchemaObjectDefinition("LucenIndexOne",
|
||||
SchemaObjectType.LUCENE_INDEX);
|
||||
|
||||
adminOperations.createLuceneIndexes(Arrays.asList(definitionOne, definitionTwo));
|
||||
|
||||
verify(adminOperations, times(1)).createLuceneIndex(eq(definitionOne));
|
||||
verify(adminOperations, times(1)).createLuceneIndex(eq(definitionTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createLuceneIndexesWithEmptyIterableCallsCreateLuceneIndex() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createLuceneIndexes(any(Iterable.class));
|
||||
|
||||
adminOperations.createLuceneIndexes(Collections.emptyList());
|
||||
|
||||
verify(adminOperations, never()).createLuceneIndex(any(SchemaObjectDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createLuceneIndexesWithNullIterableCallsCreateLuceneIndex() {
|
||||
|
||||
adminOperations.createLuceneIndexes((Iterable) null);
|
||||
|
||||
verify(adminOperations, never()).createLuceneIndex(any(SchemaObjectDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIndexesWithArrayCallsCreateIndex() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createIndexes(ArgumentMatchers.<IndexDefinition[]>any());
|
||||
|
||||
IndexDefinition definitionOne = IndexDefinition.from(mockIndex("IndexOne"));
|
||||
IndexDefinition definitionTwo = IndexDefinition.from(mockIndex("IndexTwo"));
|
||||
|
||||
adminOperations.createIndexes(definitionOne, definitionTwo);
|
||||
|
||||
verify(adminOperations, times(1)).createIndex(eq(definitionOne));
|
||||
verify(adminOperations, times(1)).createIndex(eq(definitionTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIndexesWithEmptyArray() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createIndexes(ArgumentMatchers.<IndexDefinition[]>any());
|
||||
|
||||
adminOperations.createIndexes();
|
||||
|
||||
verify(adminOperations, never()).createIndex(any(IndexDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIndexesWithNullArray() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createIndexes(ArgumentMatchers.<IndexDefinition[]>any());
|
||||
|
||||
adminOperations.createIndexes();
|
||||
|
||||
verify(adminOperations, never()).createIndex(any(IndexDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createIndexesWithIterableCallsCreateIndex() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createIndexes(any(Iterable.class));
|
||||
|
||||
IndexDefinition definitionOne = IndexDefinition.from(mockIndex("IndexOne"));
|
||||
IndexDefinition definitionTwo = IndexDefinition.from(mockIndex("IndexTwo"));
|
||||
|
||||
adminOperations.createIndexes(Arrays.asList(definitionOne, definitionTwo));
|
||||
|
||||
verify(adminOperations, times(1)).createIndex(eq(definitionOne));
|
||||
verify(adminOperations, times(1)).createIndex(eq(definitionTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createIndexesWithEmptyIterable() {
|
||||
|
||||
doCallRealMethod().when(adminOperations).createIndexes(any(Iterable.class));
|
||||
|
||||
adminOperations.createIndexes(Collections.emptyList());
|
||||
|
||||
verify(adminOperations, never()).createIndex(any(IndexDefinition.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createIndexesWithNullIterable() {
|
||||
|
||||
adminOperations.createIndexes((Iterable) null);
|
||||
|
||||
verify(adminOperations, never()).createIndex(any(IndexDefinition.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.functions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.query.QueryException;
|
||||
import org.apache.geode.cache.query.QueryService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CreateIndexFunction}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.apache.geode.cache.query.QueryService
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CreateIndexFunctionUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
private CreateIndexFunction createIndexFunction;
|
||||
|
||||
@Mock
|
||||
private Index mockIndex;
|
||||
|
||||
@Mock
|
||||
private QueryService mockQueryService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
this.createIndexFunction = spy(new CreateIndexFunction());
|
||||
|
||||
doReturn(this.mockCache).when(this.createIndexFunction).resolveCache();
|
||||
when(this.mockCache.getQueryService()).thenReturn(this.mockQueryService);
|
||||
when(this.mockIndex.getName()).thenReturn("MockIndex");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createsFunctionalIndex() throws QueryException {
|
||||
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("age");
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/Customers");
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.FUNCTIONAL.getGemfireIndexType());
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(null);
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(this.createIndexFunction.createIndex(indexDefinition)).isTrue();
|
||||
|
||||
verify(this.mockCache, times(2)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
verify(this.mockQueryService, times(1))
|
||||
.createIndex(eq("MockIndex"), eq("age"), eq("/Customers"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createsHashIndex() throws QueryException {
|
||||
|
||||
Index mockIndexTwo = mock(Index.class, "MockIndexTwo");
|
||||
|
||||
when(mockIndexTwo.getName()).thenReturn("MockIndexTwo");
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("name");
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/Customers");
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.HASH.getGemfireIndexType());
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(Collections.singleton(mockIndexTwo));
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(this.createIndexFunction.createIndex(indexDefinition)).isTrue();
|
||||
|
||||
verify(this.mockCache, times(2)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
verify(mockIndexTwo, times(1)).getName();
|
||||
verify(this.mockQueryService, times(1))
|
||||
.createHashIndex(eq("MockIndex"), eq("name"), eq("/Customers"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createsKeyIndex() throws QueryException {
|
||||
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("id");
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/Customers");
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.PRIMARY_KEY.getGemfireIndexType());
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(Collections.emptyList());
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(this.createIndexFunction.createIndex(indexDefinition)).isTrue();
|
||||
|
||||
verify(this.mockCache, times(2)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
verify(this.mockQueryService, times(1))
|
||||
.createKeyIndex(eq("MockIndex"), eq("id"), eq("/Customers"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotCreateIndexWhenIndexAlreadyExists() throws QueryException {
|
||||
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(Collections.singleton(this.mockIndex));
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(this.createIndexFunction.createIndex(indexDefinition)).isFalse();
|
||||
|
||||
verify(this.mockCache, times(1)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
verify(this.mockQueryService, never()).createIndex(anyString(), anyString(), anyString());
|
||||
verify(this.mockQueryService, never()).createIndex(anyString(), anyString(), anyString(), anyString());
|
||||
verify(this.mockQueryService, never()).createHashIndex(anyString(), anyString(), anyString());
|
||||
verify(this.mockQueryService, never()).createHashIndex(anyString(), anyString(), anyString(), anyString());
|
||||
verify(this.mockQueryService, never()).createKeyIndex(anyString(), anyString(), anyString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.functions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionFactory;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CreateRegionFunction}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CreateRegionFunctionUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
@Mock
|
||||
private Region<Object, Object> mockRegion;
|
||||
|
||||
private CreateRegionFunction createRegionFunction;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
this.createRegionFunction = spy(new CreateRegionFunction());
|
||||
|
||||
doReturn(this.mockCache).when(this.createRegionFunction).resolveCache();
|
||||
when(this.mockRegion.getName()).thenReturn("MockRegion");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createsRegionWhenRegionDoesNotExist() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
RegionFactory<Object, Object> mockRegionFactory = mock(RegionFactory.class);
|
||||
|
||||
when(this.mockCache.getRegion(anyString())).thenReturn(null);
|
||||
when(this.mockCache.createRegionFactory(any(RegionShortcut.class))).thenReturn(mockRegionFactory);
|
||||
|
||||
assertThat(this.createRegionFunction.createRegion(regionDefinition)).isTrue();
|
||||
|
||||
verify(this.mockCache, times(1)).getRegion(eq("MockRegion"));
|
||||
verify(this.mockCache, times(1)).createRegionFactory(eq(RegionShortcut.PARTITION));
|
||||
verify(mockRegionFactory, times(1)).create(eq("MockRegion"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotCreateRegionWhenRegionAlreadyExists() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
when(this.mockCache.getRegion(anyString())).thenReturn(this.mockRegion);
|
||||
|
||||
assertThat(this.createRegionFunction.createRegion(regionDefinition)).isFalse();
|
||||
|
||||
verify(this.mockCache, times(1)).getRegion(eq("MockRegion"));
|
||||
verify(this.mockCache, never()).createRegionFactory();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.functions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.query.QueryService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ListIndexesFunction}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.apache.geode.cache.query.QueryService
|
||||
* @see org.springframework.data.gemfire.config.admin.functions.ListIndexesFunction
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ListIndexesFunctionUnitTests {
|
||||
|
||||
@Mock
|
||||
private Cache mockCache;
|
||||
|
||||
@Mock
|
||||
private Index mockIndexOne;
|
||||
|
||||
@Mock
|
||||
private Index mockIndexTwo;
|
||||
|
||||
private ListIndexesFunction listIndexesFunction;
|
||||
|
||||
@Mock
|
||||
private QueryService mockQueryService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
this.listIndexesFunction = spy(new ListIndexesFunction());
|
||||
|
||||
doReturn(this.mockCache).when(this.listIndexesFunction).resolveCache();
|
||||
when(this.mockCache.getQueryService()).thenReturn(this.mockQueryService);
|
||||
when(this.mockIndexOne.getName()).thenReturn("MockIndexOne");
|
||||
when(this.mockIndexTwo.getName()).thenReturn("MockIndexTwo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listIndexesReturnsIndexNames() {
|
||||
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(Arrays.asList(this.mockIndexOne, this.mockIndexTwo));
|
||||
|
||||
assertThat(this.listIndexesFunction.listIndexes()).contains("MockIndexOne", "MockIndexTwo");
|
||||
|
||||
verify(this.listIndexesFunction, times(1)).resolveCache();
|
||||
verify(this.mockCache, times(1)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
verify(this.mockIndexOne, times(1)).getName();
|
||||
verify(this.mockIndexTwo, times(1)).getName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listIndexesReturnsEmptySetWhenCacheIsNull() {
|
||||
|
||||
doReturn(null).when(this.listIndexesFunction).resolveCache();
|
||||
|
||||
assertThat(this.listIndexesFunction.listIndexes()).isEmpty();
|
||||
|
||||
verify(this.listIndexesFunction, times(1)).resolveCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listIndexesReturnsEmptySetWhenQueryServiceIsNull() {
|
||||
|
||||
when(this.mockCache.getQueryService()).thenReturn(null);
|
||||
|
||||
assertThat(this.listIndexesFunction.listIndexes()).isEmpty();
|
||||
|
||||
verify(this.listIndexesFunction, times(1)).resolveCache();
|
||||
verify(this.mockCache, times(1)).getQueryService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listIndexesReturnsEmptySetWhenQueryServiceGetIndexesIsNull() {
|
||||
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(null);
|
||||
|
||||
assertThat(this.listIndexesFunction.listIndexes()).isEmpty();
|
||||
|
||||
verify(this.listIndexesFunction, times(1)).resolveCache();
|
||||
verify(this.mockCache, times(1)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.remote;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.asArray;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.Scope;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.management.internal.cli.domain.RegionInformation;
|
||||
import org.apache.geode.management.internal.cli.functions.GetRegionsFunction;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.client.function.ListRegionsOnServerFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.CreateIndexFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.CreateRegionFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.ListIndexesFunction;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.data.gemfire.function.execution.GemfireFunctionOperations;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link FunctionGemfireAdminTemplate}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.admin.remote.FunctionGemfireAdminTemplate
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class FunctionGemfireAdminTemplateUnitTests {
|
||||
|
||||
private FunctionGemfireAdminTemplate template;
|
||||
|
||||
@Mock
|
||||
private ClientCache mockClientCache;
|
||||
|
||||
@Mock
|
||||
private GemfireFunctionOperations mockFunctionOperations;
|
||||
|
||||
@Mock
|
||||
private Index mockIndex;
|
||||
|
||||
@Mock
|
||||
private Region mockRegion;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
this.template = spy(new FunctionGemfireAdminTemplate(this.mockClientCache));
|
||||
|
||||
when(this.template.newGemfireFunctionOperations(any(ClientCache.class)))
|
||||
.thenReturn(this.mockFunctionOperations);
|
||||
|
||||
when(this.mockIndex.getName()).thenReturn("MockIndex");
|
||||
when(this.mockRegion.getName()).thenReturn("MockRegion");
|
||||
}
|
||||
|
||||
private Region mockRegion(String name) {
|
||||
|
||||
Region mockRegion = mock(Region.class, name);
|
||||
|
||||
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name));
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class,
|
||||
String.format("Mock%sRegionAttributes", name));
|
||||
|
||||
when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.PARTITION);
|
||||
when(mockRegionAttributes.getScope()).thenReturn(Scope.DISTRIBUTED_ACK);
|
||||
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
private RegionInformation newRegionInformation(String regionName) {
|
||||
return new RegionInformation(mockRegion(regionName), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructFunctionGemfireAdminTemplateWithClientCache() {
|
||||
|
||||
FunctionGemfireAdminTemplate template = new FunctionGemfireAdminTemplate(this.mockClientCache);
|
||||
|
||||
assertThat(template).isNotNull();
|
||||
assertThat(template.getClientCache()).isSameAs(this.mockClientCache);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructFunctionGemfireAdminTemplateWithNull() {
|
||||
|
||||
try {
|
||||
new FunctionGemfireAdminTemplate(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("ClientCache is required");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailableServerRegionsExecutesListRegionsOnServerFunction() {
|
||||
|
||||
when(this.mockFunctionOperations.executeAndExtract(any(Function.class)))
|
||||
.thenReturn(asSet("RegionOne", "RegionTwo"));
|
||||
|
||||
Iterable<String> availableServerRegions = this.template.getAvailableServerRegions();
|
||||
|
||||
assertThat(availableServerRegions).isNotNull();
|
||||
assertThat(availableServerRegions).hasSize(2);
|
||||
assertThat(availableServerRegions).contains("RegionOne", "RegionTwo");
|
||||
|
||||
verify(this.mockFunctionOperations, times(1))
|
||||
.executeAndExtract(isA(ListRegionsOnServerFunction.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailableServerRegionsExecutesGetRegionsFunction() {
|
||||
|
||||
when(this.mockFunctionOperations.executeAndExtract(isA(ListRegionsOnServerFunction.class)))
|
||||
.thenThrow(new RuntimeException("TEST"));
|
||||
|
||||
Object[] regionInformation = asArray(newRegionInformation("MockRegionOne"),
|
||||
newRegionInformation("MockRegionTwo"));
|
||||
|
||||
when(this.mockFunctionOperations.executeAndExtract(isA(GetRegionsFunction.class)))
|
||||
.thenReturn(regionInformation);
|
||||
|
||||
Iterable<String> availableServerRegions = this.template.getAvailableServerRegions();
|
||||
|
||||
assertThat(availableServerRegions).isNotNull();
|
||||
assertThat(availableServerRegions).hasSize(2);
|
||||
assertThat(availableServerRegions).contains("MockRegionOne", "MockRegionTwo");
|
||||
|
||||
verify(this.mockFunctionOperations, times(1))
|
||||
.executeAndExtract(isA(ListRegionsOnServerFunction.class));
|
||||
|
||||
verify(this.mockFunctionOperations, times(1))
|
||||
.executeAndExtract(isA(GetRegionsFunction.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailableServerRegionIndexesCallsExecuteWithListIndexesFunctionId() {
|
||||
|
||||
this.template.getAvailableServerRegionIndexes();
|
||||
|
||||
verify(this.mockFunctionOperations, times(1))
|
||||
.executeAndExtract(eq(ListIndexesFunction.LIST_INDEXES_FUNCTION_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRegionCallsExecuteWithCreateRegionFunctionIdAndRegionDefinition() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
this.template.createRegion(regionDefinition);
|
||||
|
||||
verify(this.mockFunctionOperations, times(1))
|
||||
.executeAndExtract(eq(CreateRegionFunction.CREATE_REGION_FUNCTION_ID), eq(regionDefinition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIndexCallsExecuteWithCreateIndexFunctionIdAndIndexDefinition() {
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
this.template.createIndex(indexDefinition);
|
||||
|
||||
verify(this.mockFunctionOperations, times(1))
|
||||
.executeAndExtract(eq(CreateIndexFunction.CREATE_INDEX_FUNCTION_ID), eq(indexDefinition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsRegionInformationIsNullSafe() {
|
||||
assertThat(this.template.containsRegionInformation(null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsRegionInformationReturnsFalseForNonObjectArrayResult() {
|
||||
assertThat(this.template.containsRegionInformation(newRegionInformation("TestRegion"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsRegionInformationReturnsFalseForEmptyObjectArrayResult() {
|
||||
assertThat(this.template.containsRegionInformation(asArray())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsRegionInformationReturnsFalseForObjectArrayContainingNonRegionInformation() {
|
||||
assertThat(this.template.containsRegionInformation(asArray(mockRegion("TestRegion")))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsRegionInformationReturnsTrueForObjectArrayWithRegionInformation() {
|
||||
assertThat(this.template.containsRegionInformation(asArray(newRegionInformation("TestRegion"))))
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.remote;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RestHttpGemfireAdminTemplate}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.admin.remote.RestHttpGemfireAdminTemplate
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RestHttpGemfireAdminTemplateUnitTests {
|
||||
|
||||
@Mock
|
||||
private ClientCache mockClientCache;
|
||||
|
||||
@Mock
|
||||
private Index mockIndex;
|
||||
|
||||
@Mock
|
||||
private Region mockRegion;
|
||||
|
||||
private RestHttpGemfireAdminTemplate template;
|
||||
|
||||
@Mock
|
||||
private RestOperations mockRestOperations;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
this.template = new RestHttpGemfireAdminTemplate(this.mockClientCache) {
|
||||
@Override protected RestOperations newRestOperations() {
|
||||
return mockRestOperations;
|
||||
}
|
||||
};
|
||||
|
||||
when(this.mockRegion.getName()).thenReturn("MockRegion");
|
||||
when(this.mockIndex.getName()).thenReturn("MockIndex");
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("age");
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/Customers");
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.FUNCTIONAL.getGemfireIndexType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructDefaultRestHttpGemfireAdminTemplate() {
|
||||
|
||||
RestHttpGemfireAdminTemplate template = new RestHttpGemfireAdminTemplate(this.mockClientCache);
|
||||
|
||||
assertThat(template).isNotNull();
|
||||
assertThat(template.getClientCache()).isSameAs(this.mockClientCache);
|
||||
assertThat(template.getManagementRestApiUrl())
|
||||
.isEqualTo(String.format(RestHttpGemfireAdminTemplate.MANAGEMENT_REST_API_URL_TEMPLATE,
|
||||
RestHttpGemfireAdminTemplate.DEFAULT_HOST, RestHttpGemfireAdminTemplate.DEFAULT_PORT));
|
||||
assertThat(template.getRestOperations()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructCustomRestHttpGemfireAdminTemplate() {
|
||||
|
||||
RestHttpGemfireAdminTemplate template =
|
||||
new RestHttpGemfireAdminTemplate(this.mockClientCache, "skullbox", 8080);
|
||||
|
||||
assertThat(template).isNotNull();
|
||||
assertThat(template.getClientCache()).isSameAs(this.mockClientCache);
|
||||
assertThat(template.getManagementRestApiUrl())
|
||||
.isEqualTo(String.format(RestHttpGemfireAdminTemplate.MANAGEMENT_REST_API_URL_TEMPLATE, "skullbox", 8080));
|
||||
assertThat(template.getRestOperations()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createIndexCallsGemFireManagementRestApi() {
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
when(this.mockRestOperations.exchange(any(RequestEntity.class), eq(String.class))).thenAnswer(invocation -> {
|
||||
|
||||
RequestEntity requestEntity = invocation.getArgument(0);
|
||||
|
||||
assertThat(requestEntity).isNotNull();
|
||||
assertThat(requestEntity.getMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(requestEntity.getUrl()).isEqualTo(URI.create("http://localhost:7070/gemfire/v1/indexes"));
|
||||
|
||||
HttpHeaders headers = requestEntity.getHeaders();
|
||||
|
||||
assertThat(headers).isNotNull();
|
||||
assertThat(headers.getContentType()).isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
Object body = requestEntity.getBody();
|
||||
|
||||
assertThat(body).isInstanceOf(MultiValueMap.class);
|
||||
|
||||
MultiValueMap<String, Object> requestBody = (MultiValueMap<String, Object>) body;
|
||||
|
||||
assertThat(requestBody.getFirst("name")).isEqualTo(indexDefinition.getName());
|
||||
assertThat(requestBody.getFirst("expression")).isEqualTo(indexDefinition.getExpression());
|
||||
assertThat(requestBody.getFirst("region")).isEqualTo(indexDefinition.getFromClause());
|
||||
assertThat(requestBody.getFirst("type")).isEqualTo(indexDefinition.getIndexType().toString());
|
||||
|
||||
return new ResponseEntity(HttpStatus.OK);
|
||||
});
|
||||
|
||||
this.template.createIndex(indexDefinition);
|
||||
|
||||
verify(this.mockRestOperations, times(1))
|
||||
.exchange(isA(RequestEntity.class), eq(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createRegionCallsGemFireManagementRestApi() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
when(this.mockRestOperations.exchange(any(RequestEntity.class), eq(String.class))).thenAnswer(invocation -> {
|
||||
|
||||
RequestEntity requestEntity = invocation.getArgument(0);
|
||||
|
||||
assertThat(requestEntity).isNotNull();
|
||||
assertThat(requestEntity.getMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(requestEntity.getUrl()).isEqualTo(URI.create("http://localhost:7070/gemfire/v1/regions"));
|
||||
|
||||
HttpHeaders headers = requestEntity.getHeaders();
|
||||
|
||||
assertThat(headers).isNotNull();
|
||||
assertThat(headers.getContentType()).isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
Object body = requestEntity.getBody();
|
||||
|
||||
assertThat(body).isInstanceOf(MultiValueMap.class);
|
||||
|
||||
MultiValueMap<String, Object> requestBody = (MultiValueMap<String, Object>) body;
|
||||
|
||||
assertThat(requestBody.getFirst("name")).isEqualTo(regionDefinition.getName());
|
||||
assertThat(requestBody.getFirst("type")).isEqualTo(regionDefinition.getRegionShortcut().toString());
|
||||
assertThat(requestBody.getFirst("skip-if-exists"))
|
||||
.isEqualTo(String.valueOf(RestHttpGemfireAdminTemplate.CREATE_REGION_SKIP_IF_EXISTS_DEFAULT));
|
||||
|
||||
return new ResponseEntity(HttpStatus.OK);
|
||||
});
|
||||
|
||||
this.template.createRegion(regionDefinition);
|
||||
|
||||
verify(this.mockRestOperations, times(1))
|
||||
.exchange(isA(RequestEntity.class), eq(String.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.gemfire.IndexFactoryBean;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.admin.functions.CreateIndexFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.CreateRegionFunction;
|
||||
import org.springframework.data.gemfire.config.admin.functions.ListIndexesFunction;
|
||||
import org.springframework.data.gemfire.config.admin.remote.RestHttpGemfireAdminTemplate;
|
||||
import org.springframework.data.gemfire.function.config.EnableGemfireFunctions;
|
||||
import org.springframework.data.gemfire.process.ProcessWrapper;
|
||||
import org.springframework.data.gemfire.support.ConnectionEndpoint;
|
||||
import org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration tests for the {@link EnableClusterConfiguration} annotation
|
||||
* and {@link ClusterConfigurationConfiguration} class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.IndexFactoryBean
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClusterConfigurationConfiguration
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableClusterConfiguration
|
||||
* @see org.springframework.data.gemfire.process.ProcessWrapper
|
||||
* @see org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = EnableClusterConfigurationIntegrationTests.TestConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class EnableClusterConfigurationIntegrationTests extends ClientServerIntegrationTestsSupport {
|
||||
|
||||
private static final String LOG_LEVEL = "warning";
|
||||
|
||||
private static ProcessWrapper gemfireServer;
|
||||
|
||||
@Autowired
|
||||
private ClientCache gemfireCache;
|
||||
|
||||
private GemfireAdminOperations adminOperations;
|
||||
|
||||
@BeforeClass
|
||||
public static void startGemFireServer() throws Exception {
|
||||
|
||||
int availablePort = findAvailablePort();
|
||||
|
||||
gemfireServer = run(GemFireServerConfiguration.class,
|
||||
String.format("-D%s=%d", GEMFIRE_CACHE_SERVER_PORT_PROPERTY, availablePort));
|
||||
|
||||
waitForServerToStart("localhost", availablePort);
|
||||
|
||||
System.setProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY, String.valueOf(availablePort));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopGemFireServer() {
|
||||
System.clearProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY);
|
||||
stop(gemfireServer);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.adminOperations = new RestHttpGemfireAdminTemplate(this.gemfireCache,
|
||||
"localhost", Integer.getInteger(GEMFIRE_CACHE_SERVER_PORT_PROPERTY, 40404));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverIndexesAreCorrect() {
|
||||
assertThat(this.adminOperations.getAvailableServerRegionIndexes())
|
||||
.containsAll(Arrays.asList("IndexOne", "IndexTwo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverRegionsAreCorrect() {
|
||||
assertThat(this.adminOperations.getAvailableServerRegions())
|
||||
.containsAll(Arrays.asList("RegionOne", "RegionTwo", "RegionThree", "RegionFour"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableClusterConfiguration
|
||||
@Import(GemFireClientConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
}
|
||||
|
||||
@ClientCacheApplication(logLevel = LOG_LEVEL, subscriptionEnabled = true)
|
||||
static class GemFireClientConfiguration {
|
||||
|
||||
@Bean
|
||||
ClientCacheConfigurer clientCachePoolPortConfigurer(
|
||||
@Value("${" + GEMFIRE_CACHE_SERVER_PORT_PROPERTY + ":40404}") int port) {
|
||||
|
||||
return (bean, clientCacheFactoryBean) -> clientCacheFactoryBean.setServers(
|
||||
Collections.singletonList(new ConnectionEndpoint("localhost", port)));
|
||||
}
|
||||
|
||||
@Bean("IndexOne")
|
||||
@DependsOn("RegionOne")
|
||||
IndexFactoryBean indexOne(GemFireCache gemfireCache) {
|
||||
|
||||
IndexFactoryBean indexFactory = new IndexFactoryBean();
|
||||
|
||||
indexFactory.setCache(gemfireCache);
|
||||
indexFactory.setExpression("id");
|
||||
indexFactory.setFrom("/RegionOne");
|
||||
indexFactory.setType(IndexType.KEY);
|
||||
|
||||
return indexFactory;
|
||||
}
|
||||
|
||||
@Bean("RegionOne")
|
||||
ClientRegionFactoryBean<Object, Object> regionOne(GemFireCache gemfireCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> clientRegionFactory = new ClientRegionFactoryBean<>();
|
||||
|
||||
clientRegionFactory.setCache(gemfireCache);
|
||||
clientRegionFactory.setClose(false);
|
||||
clientRegionFactory.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
@Bean("RegionTwo")
|
||||
ClientRegionFactoryBean<Object, Object> regionTwo(GemFireCache gemfireCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> clientRegionFactory = new ClientRegionFactoryBean<>();
|
||||
|
||||
clientRegionFactory.setCache(gemfireCache);
|
||||
clientRegionFactory.setClose(false);
|
||||
clientRegionFactory.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
@Bean("RegionThree")
|
||||
ClientRegionFactoryBean<Object, Object> regionThree(GemFireCache gemfireCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> clientRegionFactory = new ClientRegionFactoryBean<>();
|
||||
|
||||
clientRegionFactory.setCache(gemfireCache);
|
||||
clientRegionFactory.setClose(false);
|
||||
clientRegionFactory.setShortcut(ClientRegionShortcut.CACHING_PROXY);
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@CacheServerApplication(name = "EnableClusterConfigurationIntegrationTests", logLevel = LOG_LEVEL)
|
||||
@EnableGemfireFunctions
|
||||
static class GemFireServerConfiguration {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
|
||||
EnableClusterConfigurationIntegrationTests.GemFireServerConfiguration.class);
|
||||
|
||||
applicationContext.registerShutdownHook();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CreateIndexFunction createIndexFunction() {
|
||||
return new CreateIndexFunction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CreateRegionFunction createRegionFunction() {
|
||||
return new CreateRegionFunction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ListIndexesFunction listIndexesFunction() {
|
||||
return new ListIndexesFunction();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheServerConfigurer cacheServerPortConfigurer(
|
||||
@Value("${" + GEMFIRE_CACHE_SERVER_PORT_PROPERTY + ":40404}") int port) {
|
||||
|
||||
return (bean, cacheServerFactoryBean) -> cacheServerFactoryBean.setPort(port);
|
||||
}
|
||||
|
||||
@Bean("IndexTwo")
|
||||
@DependsOn("RegionTwo")
|
||||
IndexFactoryBean indexTwo(GemFireCache gemfireCache) {
|
||||
|
||||
IndexFactoryBean indexFactory = new IndexFactoryBean();
|
||||
|
||||
indexFactory.setCache(gemfireCache);
|
||||
indexFactory.setExpression("name");
|
||||
indexFactory.setFrom("/RegionTwo");
|
||||
indexFactory.setType(IndexType.HASH);
|
||||
|
||||
return indexFactory;
|
||||
}
|
||||
|
||||
@Bean("RegionTwo")
|
||||
PartitionedRegionFactoryBean<Object, Object> regionTwo(GemFireCache gemfireCache) {
|
||||
|
||||
PartitionedRegionFactoryBean<Object, Object> regionFactoryBean = new PartitionedRegionFactoryBean<>();
|
||||
|
||||
regionFactoryBean.setCache(gemfireCache);
|
||||
regionFactoryBean.setClose(false);
|
||||
regionFactoryBean.setPersistent(false);
|
||||
|
||||
return regionFactoryBean;
|
||||
}
|
||||
|
||||
@Bean("RegionFour")
|
||||
ReplicatedRegionFactoryBean<Object, Object> regionFour(GemFireCache gemfireCache) {
|
||||
|
||||
ReplicatedRegionFactoryBean<Object, Object> regionFactoryBean = new ReplicatedRegionFactoryBean<>();
|
||||
|
||||
regionFactoryBean.setCache(gemfireCache);
|
||||
regionFactoryBean.setClose(false);
|
||||
regionFactoryBean.setPersistent(false);
|
||||
|
||||
return regionFactoryBean;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SchemaObjectDefinition}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class SchemaObjectDefinitionUnitTests {
|
||||
|
||||
private SchemaObjectDefinition newSchemaObjectDefinition(String name) {
|
||||
return new TestSchemaObjectDefinition(name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructSchemaObjectDefinitionWithName() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinition = newSchemaObjectDefinition("TEST");
|
||||
|
||||
assertThat(schemaObjectDefinition).isNotNull();
|
||||
assertThat(schemaObjectDefinition.getName()).isEqualTo("TEST");
|
||||
assertThat(schemaObjectDefinition.getType()).isEqualTo(SchemaObjectType.UNKNOWN);
|
||||
}
|
||||
|
||||
private SchemaObjectDefinition testConstructSchemaObjectDefinitionWithInvalidName(String name) {
|
||||
try {
|
||||
return newSchemaObjectDefinition(name);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Name [%s] is required", name);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructSchemaObjectDefinitionWithNull() {
|
||||
testConstructSchemaObjectDefinitionWithInvalidName(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructSchemaObjectDefinitionWithNoName() {
|
||||
testConstructSchemaObjectDefinitionWithInvalidName(" ");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructSchemaObjectDefinitionWithEmptyName() {
|
||||
testConstructSchemaObjectDefinitionWithInvalidName("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalSchemaObjectDefinitionsAreEqual() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinitionOne = newSchemaObjectDefinition("TEST");
|
||||
SchemaObjectDefinition schemaObjectDefinitionTwo = newSchemaObjectDefinition("TEST");
|
||||
|
||||
assertThat(schemaObjectDefinitionOne).isNotSameAs(schemaObjectDefinitionTwo);
|
||||
assertThat(schemaObjectDefinitionOne).isEqualTo(schemaObjectDefinitionTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identicalSchemaObjectDefinitionsAreEquals() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinition = newSchemaObjectDefinition("TEST");
|
||||
|
||||
assertThat(schemaObjectDefinition).isEqualTo(schemaObjectDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unequalSchemaObjectDefinitionsAreNotEqual() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinitionOne = newSchemaObjectDefinition("TEST");
|
||||
SchemaObjectDefinition schemaObjectDefinitionTwo = newSchemaObjectDefinition("test");
|
||||
|
||||
assertThat(schemaObjectDefinitionOne).isNotSameAs(schemaObjectDefinitionTwo);
|
||||
assertThat(schemaObjectDefinitionOne).isNotEqualTo(schemaObjectDefinitionTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalSchemaObjectDefinitionsHaveTheSameHashCode() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinitionOne = newSchemaObjectDefinition("TEST");
|
||||
SchemaObjectDefinition schemaObjectDefinitionTwo = newSchemaObjectDefinition("TEST");
|
||||
|
||||
assertThat(schemaObjectDefinitionOne).isNotSameAs(schemaObjectDefinitionTwo);
|
||||
assertThat(schemaObjectDefinitionOne.hashCode()).isEqualTo(schemaObjectDefinitionTwo.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identicalSchemaObjectDefinitionsHaveTheSameHashCode() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinition = newSchemaObjectDefinition("TEST");
|
||||
|
||||
assertThat(schemaObjectDefinition.hashCode()).isEqualTo(schemaObjectDefinition.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unequalSchemaObjectDefinitionsHaveDifferentHashCodes() {
|
||||
|
||||
SchemaObjectDefinition schemaObjectDefinitionOne = newSchemaObjectDefinition("TEST");
|
||||
SchemaObjectDefinition schemaObjectDefinitionTwo = newSchemaObjectDefinition("test");
|
||||
|
||||
assertThat(schemaObjectDefinitionOne).isNotSameAs(schemaObjectDefinitionTwo);
|
||||
assertThat(schemaObjectDefinitionOne.hashCode()).isNotEqualTo(schemaObjectDefinitionTwo.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringPrintsNameAndType() {
|
||||
assertThat(newSchemaObjectDefinition("test").toString()).isEqualTo("UNKNOWN[test]");
|
||||
}
|
||||
|
||||
private static final class TestSchemaObjectDefinition extends SchemaObjectDefinition {
|
||||
|
||||
private TestSchemaObjectDefinition(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaObjectType getType() {
|
||||
return SchemaObjectType.UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.DiskStore;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.lucene.LuceneIndex;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.wan.GatewayReceiver;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SchemaObjectType}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.schema.SchemaObjectType
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SchemaObjectTypeUnitTests {
|
||||
|
||||
@Test
|
||||
public void objectTypesAreSetAndCorrect() {
|
||||
|
||||
Set<Class<?>> expectedSchemaObjectTypes = asSet(AsyncEventQueue.class, Cache.class, ClientCache.class,
|
||||
DiskStore.class, Function.class, GatewayReceiver.class, GatewaySender.class, Index.class, LuceneIndex.class,
|
||||
Pool.class, Region.class, Void.class);
|
||||
|
||||
Set<Class<?>> actualSchemaObjectTypes = stream(SchemaObjectType.values())
|
||||
.map(SchemaObjectType::getObjectType)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
assertThat(actualSchemaObjectTypes).hasSameSizeAs(expectedSchemaObjectTypes);
|
||||
assertThat(actualSchemaObjectTypes).containsAll(expectedSchemaObjectTypes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromClass() {
|
||||
stream(SchemaObjectType.values()).forEach(it ->
|
||||
assertThat(SchemaObjectType.from(it.getObjectType())).isSameAs(it));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromNullIsUnknown() {
|
||||
assertThat(SchemaObjectType.from(null)).isSameAs(SchemaObjectType.UNKNOWN);
|
||||
assertThat(SchemaObjectType.from((Object) null)).isSameAs(SchemaObjectType.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromObject() {
|
||||
stream(SchemaObjectType.values()).filter(it -> !SchemaObjectType.UNKNOWN.equals(it)).forEach(it ->
|
||||
assertThat(SchemaObjectType.from(mock(it.getObjectType()))).isSameAs(it));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromUntypedObjectIsUnknown() {
|
||||
assertThat(SchemaObjectType.from(new Object())).isSameAs(SchemaObjectType.UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.definitions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.test.support.IOUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link IndexDefinition}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.data.gemfire.IndexType
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class IndexDefinitionUnitTests {
|
||||
|
||||
@Mock
|
||||
private Index mockIndex;
|
||||
|
||||
@Mock
|
||||
private Region<?, ?> mockRegion;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(this.mockIndex.getName()).thenReturn("MockIndex");
|
||||
when(this.mockRegion.getFullPath()).thenReturn(String.format("%sMockRegion", Region.SEPARATOR));
|
||||
}
|
||||
|
||||
private Index mockIndex(String name, String expression, String fromClause, IndexType type) {
|
||||
|
||||
Index mockIndex = mock(Index.class);
|
||||
|
||||
when(mockIndex.getName()).thenReturn(name);
|
||||
when(mockIndex.getIndexedExpression()).thenReturn(expression);
|
||||
when(mockIndex.getFromClause()).thenReturn(fromClause);
|
||||
when(mockIndex.getType()).thenReturn(type.getGemfireIndexType());
|
||||
|
||||
return mockIndex;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromIndexCreatesAnIndexDefinition() {
|
||||
|
||||
Index mockIndex = mockIndex("TestIndex", "id", "/Customers", IndexType.PRIMARY_KEY);
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getExpression()).isEqualTo(mockIndex.getIndexedExpression());
|
||||
assertThat(indexDefinition.getFromClause()).isEqualTo(mockIndex.getFromClause());
|
||||
assertThat(indexDefinition.getIndex()).isSameAs(mockIndex);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.valueOf(mockIndex.getType()));
|
||||
assertThat(indexDefinition.getType()).isEqualTo(SchemaObjectType.INDEX);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void fromNullIndexThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
IndexDefinition.from(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Index is required");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createCallsGemfireAdminOperationsCreateIndexWithThis() {
|
||||
|
||||
GemfireAdminOperations mockAdminOperations = mock(GemfireAdminOperations.class);
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getIndex()).isSameAs(this.mockIndex);
|
||||
|
||||
indexDefinition.create(mockAdminOperations);
|
||||
|
||||
verify(mockAdminOperations, times(1)).createIndex(eq(indexDefinition));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void asDifferentIndexTypes() {
|
||||
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.FUNCTIONAL.getGemfireIndexType());
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getIndex()).isSameAs(this.mockIndex);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.FUNCTIONAL);
|
||||
assertThat(indexDefinition.as(IndexType.HASH)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.HASH);
|
||||
assertThat(indexDefinition.as(org.apache.geode.cache.query.IndexType.PRIMARY_KEY)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.PRIMARY_KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asNullIndexType() {
|
||||
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.FUNCTIONAL.getGemfireIndexType());
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getIndex()).isSameAs(this.mockIndex);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.FUNCTIONAL);
|
||||
assertThat(indexDefinition.as((IndexType) null)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.FUNCTIONAL);
|
||||
assertThat(indexDefinition.as(IndexType.HASH)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.HASH);
|
||||
assertThat(indexDefinition.as((IndexType) null)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.FUNCTIONAL);
|
||||
}
|
||||
|
||||
private void testHavingIllegalExpression(String expression) {
|
||||
|
||||
try {
|
||||
IndexDefinition.from(this.mockIndex).having(expression);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Expression is required");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void havingExpression() {
|
||||
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("id");
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getIndex()).isSameAs(this.mockIndex);
|
||||
assertThat(indexDefinition.getExpression()).isEqualTo("id");
|
||||
assertThat(indexDefinition.having("age")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getExpression()).isEqualTo("age");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void havingEmptyExpression() {
|
||||
testHavingIllegalExpression("");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void havingNoExpression() {
|
||||
testHavingIllegalExpression(" ");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void havingNullExpression() {
|
||||
testHavingIllegalExpression(null);
|
||||
}
|
||||
|
||||
private void testOnIllegalFromClause(String fromClause) {
|
||||
|
||||
try {
|
||||
IndexDefinition.from(this.mockIndex).on(fromClause);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("From Clause is required");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFromClause() {
|
||||
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/People");
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getFromClause()).isEqualTo(this.mockIndex.getFromClause());
|
||||
assertThat(indexDefinition.on("/Customers")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getFromClause()).isEqualTo("/Customers");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void onEmptyFromClause() {
|
||||
testOnIllegalFromClause("");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void onNoFromClause() {
|
||||
testOnIllegalFromClause(" ");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void onNullFromClause() {
|
||||
testOnIllegalFromClause(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRegion() {
|
||||
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/Mock");
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getFromClause()).isEqualTo(this.mockIndex.getFromClause());
|
||||
assertThat(indexDefinition.on(this.mockRegion)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getFromClause()).isEqualTo(this.mockRegion.getFullPath());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void onNullRegion() {
|
||||
|
||||
try {
|
||||
IndexDefinition.from(this.mockIndex).on((Region) null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Region is required");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withName() {
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getName()).isEqualTo("MockIndex");
|
||||
assertThat(indexDefinition.with("TestIndex")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getName()).isEqualTo("TestIndex");
|
||||
assertThat(indexDefinition.with("")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getName()).isEqualTo("MockIndex");
|
||||
assertThat(indexDefinition.with("UniqueIndex")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getName()).isEqualTo("UniqueIndex");
|
||||
assertThat(indexDefinition.with(" ")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getName()).isEqualTo("MockIndex");
|
||||
assertThat(indexDefinition.with("NonUniqueIndex")).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getName()).isEqualTo("NonUniqueIndex");
|
||||
assertThat(indexDefinition.with(null)).isSameAs(indexDefinition);
|
||||
assertThat(indexDefinition.getName()).isEqualTo("MockIndex");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeDeserializeIsSuccessful() throws ClassNotFoundException, IOException {
|
||||
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("age");
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/Customers");
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.FUNCTIONAL.getGemfireIndexType());
|
||||
|
||||
IndexDefinition indexDefinition = IndexDefinition.from(this.mockIndex);
|
||||
|
||||
byte[] indexDefinitionBytes = IOUtils.serializeObject(indexDefinition);
|
||||
|
||||
IndexDefinition deserializedIndexDefinition = IOUtils.deserializeObject(indexDefinitionBytes);
|
||||
|
||||
assertThat(deserializedIndexDefinition).isNotNull();
|
||||
assertThat(deserializedIndexDefinition).isNotSameAs(indexDefinition);
|
||||
assertThat(deserializedIndexDefinition.getIndex()).isInstanceOf(Index.class);
|
||||
assertThat(deserializedIndexDefinition.getIndex()).isNotSameAs(this.mockIndex);
|
||||
assertThat(deserializedIndexDefinition.getName()).isEqualTo("MockIndex");
|
||||
assertThat(deserializedIndexDefinition.getExpression()).isEqualTo("age");
|
||||
assertThat(deserializedIndexDefinition.getFromClause()).isEqualTo("/Customers");
|
||||
assertThat(deserializedIndexDefinition.getIndexType()).isEqualTo(IndexType.FUNCTIONAL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.definitions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.test.support.IOUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RegionDefinition}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegionDefinitionUnitTests {
|
||||
|
||||
@Mock
|
||||
private Region<?, ?> mockRegion;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
assertThat(this.mockRegion).isNotNull();
|
||||
when(this.mockRegion.getName()).thenReturn("MockRegion");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromRegionCreatesRegionDefinition() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
assertThat(regionDefinition).isNotNull();
|
||||
assertThat(regionDefinition.getName()).isEqualTo(this.mockRegion.getName());
|
||||
assertThat(regionDefinition.getRegion()).isSameAs(this.mockRegion);
|
||||
assertThat(regionDefinition.getRegionShortcut()).isEqualTo(RegionDefinition.DEFAULT_REGION_SHORTCUT);
|
||||
assertThat(regionDefinition.getType()).isEqualTo(SchemaObjectType.REGION);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void fromNullRegionThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
RegionDefinition.from(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Region is required");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void create() {
|
||||
|
||||
GemfireAdminOperations mockAdminOperations = mock(GemfireAdminOperations.class);
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
assertThat(regionDefinition).isNotNull();
|
||||
assertThat(regionDefinition.getRegion()).isSameAs(this.mockRegion);
|
||||
|
||||
regionDefinition.create(mockAdminOperations);
|
||||
|
||||
verify(mockAdminOperations, times(1)).createRegion(eq(regionDefinition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void havingRegionShortcut() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
assertThat(regionDefinition).isNotNull();
|
||||
assertThat(regionDefinition.getRegion()).isSameAs(this.mockRegion);
|
||||
assertThat(regionDefinition.getRegionShortcut()).isEqualTo(RegionDefinition.DEFAULT_REGION_SHORTCUT);
|
||||
assertThat(regionDefinition.having(RegionShortcut.LOCAL)).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getRegionShortcut()).isEqualTo(RegionShortcut.LOCAL);
|
||||
assertThat(regionDefinition.having(null)).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getRegionShortcut()).isEqualTo(RegionDefinition.DEFAULT_REGION_SHORTCUT);
|
||||
assertThat(regionDefinition.having(RegionShortcut.REPLICATE)).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getRegionShortcut()).isEqualTo(RegionShortcut.REPLICATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withName() {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion);
|
||||
|
||||
assertThat(regionDefinition).isNotNull();
|
||||
assertThat(regionDefinition.getRegion()).isSameAs(this.mockRegion);
|
||||
assertThat(regionDefinition.getName()).isEqualTo(this.mockRegion.getName());
|
||||
assertThat(regionDefinition.with("/Test")).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getName()).isEqualTo("/Test");
|
||||
assertThat(regionDefinition.with(" ")).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getName()).isEqualTo(this.mockRegion.getName());
|
||||
assertThat(regionDefinition.with("/Mock")).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getName()).isEqualTo("/Mock");
|
||||
assertThat(regionDefinition.with(null)).isSameAs(regionDefinition);
|
||||
assertThat(regionDefinition.getName()).isEqualTo(this.mockRegion.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeDeserializeIsSuccessful() throws IOException, ClassNotFoundException {
|
||||
|
||||
RegionDefinition regionDefinition = RegionDefinition.from(this.mockRegion).having(RegionShortcut.REPLICATE);
|
||||
|
||||
byte[] regionDefinitionBytes = IOUtils.serializeObject(regionDefinition);
|
||||
|
||||
RegionDefinition deserializedRegionDefinition = IOUtils.deserializeObject(regionDefinitionBytes);
|
||||
|
||||
assertThat(deserializedRegionDefinition).isNotNull();
|
||||
assertThat(deserializedRegionDefinition.getRegion()).isNull();
|
||||
assertThat(deserializedRegionDefinition.getName()).isEqualTo("MockRegion");
|
||||
assertThat(deserializedRegionDefinition.getRegionShortcut()).isEqualTo(RegionShortcut.REPLICATE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ClientRegionCollector}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.schema.support.ClientRegionCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ClientRegionCollectorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationContext mockApplicationContext;
|
||||
|
||||
@Mock
|
||||
private GemFireCache mockCache;
|
||||
|
||||
private ClientRegionCollector clientRegionCollector = new ClientRegionCollector();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, V> Region<K, V> mockRegion(String name) {
|
||||
|
||||
Region<K, V> mockRegion = mock(Region.class, name);
|
||||
|
||||
when(mockRegion.getName()).thenReturn(name);
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
private Map<String, Region> asMap(Region<?, ?>... regions) {
|
||||
return stream(regions).collect(Collectors.toMap(Region::getName, Function.identity()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectClientRegionsFromApplicationContext() {
|
||||
|
||||
Region mockRegionOne = mockRegion("MockRegionOne");
|
||||
Region mockRegionTwo = mockRegion("MockRegionTwo");
|
||||
Region mockRegionThree = mockRegion("MockRegionThree");
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn("TestPool");
|
||||
when(mockRegionTwo.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
|
||||
Map<String, Region> regionBeans = asMap(mockRegionOne, mockRegionTwo, mockRegionThree);
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(eq(Region.class))).thenReturn(regionBeans);
|
||||
|
||||
Set<Region> clientRegions = this.clientRegionCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(clientRegions).isNotNull();
|
||||
assertThat(clientRegions).hasSize(1);
|
||||
assertThat(clientRegions).containsAll(asSet(mockRegionTwo));
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(Region.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectClientRegionsFromApplicationContextWithNoClientRegions() {
|
||||
|
||||
Region mockRegionOne = mockRegion("MockRegionOne");
|
||||
Region mockRegionTwo = mockRegion("MockRegionTwo");
|
||||
Region mockRegionThree = mockRegion("MockRegionThree");
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn(" ");
|
||||
when(mockRegionOne.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionThree.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
|
||||
Map<String, Region> regionBeans = asMap(mockRegionOne, mockRegionTwo, mockRegionThree);
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(eq(Region.class))).thenReturn(regionBeans);
|
||||
|
||||
Set<Region> clientRegions = this.clientRegionCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(clientRegions).isNotNull();
|
||||
assertThat(clientRegions).isEmpty();
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(Region.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectClientRegionsFromGemFireCache() {
|
||||
|
||||
Region mockRegionOne = mockRegion("MockRegionOne");
|
||||
Region mockRegionTwo = mockRegion("MockRegionTwo");
|
||||
Region mockRegionThree = mockRegion("MockRegionThree");
|
||||
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn("TestPool");
|
||||
when(mockRegionOne.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionTwo.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
|
||||
when(this.mockCache.rootRegions()).thenReturn(asSet(mockRegionOne, mockRegionTwo, mockRegionThree));
|
||||
|
||||
Set<Region> clientRegions = this.clientRegionCollector.collectFrom(this.mockCache);
|
||||
|
||||
assertThat(clientRegions).isNotNull();
|
||||
assertThat(clientRegions).hasSize(2);
|
||||
assertThat(clientRegions).containsAll(asSet(mockRegionOne, mockRegionTwo));
|
||||
|
||||
verify(this.mockCache, times(1)).rootRegions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectCollector;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ComposableSchemaObjectCollector}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.schema.support.ComposableSchemaObjectCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ComposableSchemaObjectCollectorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationContext mockApplicationContext;
|
||||
|
||||
@Mock
|
||||
private GemFireCache mockCache;
|
||||
|
||||
@Mock
|
||||
private SchemaObjectCollector<Object> mockSchemaObjectCollectorOne;
|
||||
|
||||
@Mock
|
||||
private SchemaObjectCollector<Object> mockSchemaObjectCollectorTwo;
|
||||
|
||||
private <T> Iterable<T> emptyIterable() {
|
||||
return Collections::emptyIterator;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeArrayWithNoElements() {
|
||||
assertThat(ComposableSchemaObjectCollector.compose()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeArrayWithOneElement() {
|
||||
assertThat(ComposableSchemaObjectCollector.compose(this.mockSchemaObjectCollectorOne))
|
||||
.isSameAs(this.mockSchemaObjectCollectorOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeArrayWithTwoElements() {
|
||||
|
||||
SchemaObjectCollector<?> composedSchemaObjectCollector = ComposableSchemaObjectCollector.compose(
|
||||
this.mockSchemaObjectCollectorOne, this.mockSchemaObjectCollectorTwo);
|
||||
|
||||
assertThat(composedSchemaObjectCollector).isInstanceOf(ComposableSchemaObjectCollector.class);
|
||||
assertThat((ComposableSchemaObjectCollector) composedSchemaObjectCollector).hasSize(2);
|
||||
assertThat((ComposableSchemaObjectCollector) composedSchemaObjectCollector)
|
||||
.containsAll(asSet(this.mockSchemaObjectCollectorOne, this.mockSchemaObjectCollectorTwo));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeIterableWithNoElements() {
|
||||
assertThat(ComposableSchemaObjectCollector.compose(emptyIterable())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composableIterableWithOneElement() {
|
||||
assertThat(ComposableSchemaObjectCollector.compose(Collections.singleton(this.mockSchemaObjectCollectorTwo)))
|
||||
.isSameAs(this.mockSchemaObjectCollectorTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeIterableWithTwoElements() {
|
||||
|
||||
SchemaObjectCollector<?> composedSchemaObjectCollector = ComposableSchemaObjectCollector.compose(
|
||||
asSet(this.mockSchemaObjectCollectorOne, this.mockSchemaObjectCollectorTwo));
|
||||
|
||||
assertThat(composedSchemaObjectCollector).isInstanceOf(ComposableSchemaObjectCollector.class);
|
||||
assertThat((ComposableSchemaObjectCollector) composedSchemaObjectCollector)
|
||||
.containsAll(asSet(this.mockSchemaObjectCollectorOne, this.mockSchemaObjectCollectorTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectFromApplicationContext() {
|
||||
|
||||
SchemaObject region = SchemaObject.of(SchemaObjectType.REGION);
|
||||
SchemaObject index = SchemaObject.of(SchemaObjectType.INDEX);
|
||||
SchemaObject diskStore = SchemaObject.of(SchemaObjectType.DISK_STORE);
|
||||
|
||||
when(this.mockSchemaObjectCollectorOne.collectFrom(any(ApplicationContext.class)))
|
||||
.thenReturn(asSet(region, index));
|
||||
|
||||
when(this.mockSchemaObjectCollectorTwo.collectFrom(any(ApplicationContext.class)))
|
||||
.thenReturn(asSet(diskStore));
|
||||
|
||||
SchemaObjectCollector composedSchemaObjectCollector = ComposableSchemaObjectCollector.compose(
|
||||
asSet(this.mockSchemaObjectCollectorOne, this.mockSchemaObjectCollectorTwo));
|
||||
|
||||
assertThat(composedSchemaObjectCollector).isNotNull();
|
||||
|
||||
Iterable<Object> schemaObjects = composedSchemaObjectCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(schemaObjects).isNotNull();
|
||||
assertThat(schemaObjects).hasSize(3);
|
||||
assertThat(schemaObjects).contains(region, index, diskStore);
|
||||
|
||||
verify(this.mockSchemaObjectCollectorOne, times(1))
|
||||
.collectFrom(eq(this.mockApplicationContext));
|
||||
|
||||
verify(this.mockSchemaObjectCollectorTwo, times(1))
|
||||
.collectFrom(eq(this.mockApplicationContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectFromGemFireCache() {
|
||||
|
||||
SchemaObject asyncEventQueue = SchemaObject.of(SchemaObjectType.ASYNC_EVENT_QUEUE);
|
||||
SchemaObject gatewayReceiver = SchemaObject.of(SchemaObjectType.GATEWAY_RECEIVER);
|
||||
SchemaObject gatewaySender = SchemaObject.of(SchemaObjectType.GATEWAY_SENDER);
|
||||
|
||||
when(this.mockSchemaObjectCollectorOne.collectFrom(any(GemFireCache.class)))
|
||||
.thenReturn(asSet(gatewayReceiver, gatewaySender));
|
||||
|
||||
when(this.mockSchemaObjectCollectorTwo.collectFrom(any(GemFireCache.class)))
|
||||
.thenReturn(asSet(asyncEventQueue));
|
||||
|
||||
SchemaObjectCollector composedSchemaObjectCollector = ComposableSchemaObjectCollector.compose(
|
||||
asSet(this.mockSchemaObjectCollectorOne, this.mockSchemaObjectCollectorTwo));
|
||||
|
||||
assertThat(composedSchemaObjectCollector).isNotNull();
|
||||
|
||||
Iterable<Object> schemaObjects = composedSchemaObjectCollector.collectFrom(this.mockCache);
|
||||
|
||||
assertThat(schemaObjects).isNotNull();
|
||||
assertThat(schemaObjects).hasSize(3);
|
||||
assertThat(schemaObjects).contains(gatewayReceiver, gatewaySender, asyncEventQueue);
|
||||
|
||||
verify(this.mockSchemaObjectCollectorOne, times(1)).collectFrom(eq(this.mockCache));
|
||||
|
||||
verify(this.mockSchemaObjectCollectorTwo, times(1)).collectFrom(eq(this.mockCache));
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(staticName = "of")
|
||||
static class SchemaObject {
|
||||
@NonNull SchemaObjectType type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atMost;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectDefiner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ComposableSchemaObjectDefiner}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see SchemaObjectDefiner
|
||||
* @see ComposableSchemaObjectDefiner
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ComposableSchemaObjectDefinerUnitTests {
|
||||
|
||||
@Mock
|
||||
private SchemaObjectDefiner mockHandlerOne;
|
||||
|
||||
@Mock
|
||||
private SchemaObjectDefiner mockHandlerTwo;
|
||||
|
||||
private <T> Iterable<T> emptyIterable() {
|
||||
return Collections::<T>emptyIterator;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeArrayWithNoElements() {
|
||||
assertThat(ComposableSchemaObjectDefiner.compose()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeArrayWithOneElement() {
|
||||
assertThat(ComposableSchemaObjectDefiner.compose(this.mockHandlerOne)).isSameAs(this.mockHandlerOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeArrayWithTwoElements() {
|
||||
|
||||
SchemaObjectDefiner handler =
|
||||
ComposableSchemaObjectDefiner.compose(this.mockHandlerOne, this.mockHandlerTwo);
|
||||
|
||||
assertThat(handler).isInstanceOf(ComposableSchemaObjectDefiner.class);
|
||||
assertThat((ComposableSchemaObjectDefiner) handler)
|
||||
.containsAll(asSet(this.mockHandlerOne, this.mockHandlerTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeIterableWithNoElements() {
|
||||
assertThat(ComposableSchemaObjectDefiner.compose(emptyIterable())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeIterableWithOneElement() {
|
||||
assertThat(ComposableSchemaObjectDefiner.compose(Collections.singleton(this.mockHandlerTwo)))
|
||||
.isSameAs(this.mockHandlerTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeIterableWithTwoElements() {
|
||||
|
||||
SchemaObjectDefiner handler =
|
||||
ComposableSchemaObjectDefiner.compose(asSet(this.mockHandlerOne, this.mockHandlerTwo));
|
||||
|
||||
assertThat(handler).isInstanceOf(ComposableSchemaObjectDefiner.class);
|
||||
assertThat((ComposableSchemaObjectDefiner) handler)
|
||||
.containsAll(asSet(this.mockHandlerOne, this.mockHandlerTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSchemaObjectTypesIsComposed() {
|
||||
|
||||
when(this.mockHandlerOne.getSchemaObjectTypes())
|
||||
.thenReturn(asSet(SchemaObjectType.INDEX, SchemaObjectType.LUCENE_INDEX));
|
||||
|
||||
when(this.mockHandlerTwo.getSchemaObjectTypes())
|
||||
.thenReturn(Collections.singleton(SchemaObjectType.DISK_STORE));
|
||||
|
||||
SchemaObjectDefiner handler =
|
||||
ComposableSchemaObjectDefiner.compose(this.mockHandlerOne, this.mockHandlerTwo);
|
||||
|
||||
assertThat(handler).isNotNull();
|
||||
|
||||
assertThat(handler.getSchemaObjectTypes()).containsAll(
|
||||
Arrays.asList(SchemaObjectType.INDEX, SchemaObjectType.LUCENE_INDEX, SchemaObjectType.DISK_STORE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineReturnsRegionDefinition() {
|
||||
|
||||
Region<?, ?> mockRegion = mock(Region.class);
|
||||
|
||||
when(mockRegion.getName()).thenReturn("MockRegion");
|
||||
|
||||
Optional<RegionDefinition> regionDefinition = Optional.of(RegionDefinition.from(mockRegion));
|
||||
|
||||
when(this.mockHandlerTwo.canDefine(any(Region.class))).thenReturn(true);
|
||||
when(this.mockHandlerTwo.define(any(Region.class))).thenAnswer(invocation -> regionDefinition);
|
||||
|
||||
SchemaObjectDefiner handler =
|
||||
ComposableSchemaObjectDefiner.compose(this.mockHandlerOne, this.mockHandlerTwo);
|
||||
|
||||
assertThat(handler).isNotNull();
|
||||
assertThat(handler.define(mockRegion)).isEqualTo(regionDefinition);
|
||||
|
||||
verify(this.mockHandlerOne, atMost(1)).canDefine(eq(mockRegion));
|
||||
verify(this.mockHandlerOne, never()).define(any());
|
||||
verify(this.mockHandlerTwo, times(1)).canDefine(eq(mockRegion));
|
||||
verify(this.mockHandlerTwo, times(1)).define(eq(mockRegion));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineReturnsEmptyOptional() {
|
||||
|
||||
Object object = new Object();
|
||||
|
||||
when(this.mockHandlerOne.canDefine(any(Object.class))).thenReturn(false);
|
||||
when(this.mockHandlerTwo.canDefine(any(Object.class))).thenReturn(false);
|
||||
|
||||
SchemaObjectDefiner handler =
|
||||
ComposableSchemaObjectDefiner.compose(this.mockHandlerOne, this.mockHandlerTwo);
|
||||
|
||||
assertThat(handler).isNotNull();
|
||||
assertThat(handler.define(object).isPresent()).isFalse();
|
||||
|
||||
verify(this.mockHandlerOne, times(1)).canDefine(eq(object));
|
||||
verify(this.mockHandlerOne, never()).define(any());
|
||||
verify(this.mockHandlerTwo, times(1)).canDefine(eq(object));
|
||||
verify(this.mockHandlerTwo, never()).define(any());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.apache.geode.cache.query.QueryService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link IndexCollector}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class IndexCollectorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationContext mockApplicationContext;
|
||||
|
||||
@Mock
|
||||
private GemFireCache mockCache;
|
||||
|
||||
private IndexCollector indexCollector = new IndexCollector();
|
||||
|
||||
@Mock
|
||||
private QueryService mockQueryService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(this.mockCache.getQueryService()).thenReturn(this.mockQueryService);
|
||||
}
|
||||
|
||||
private Index mockIndex(String name) {
|
||||
|
||||
Index mockIndex = mock(Index.class, name);
|
||||
|
||||
when(mockIndex.getName()).thenReturn(name);
|
||||
|
||||
return mockIndex;
|
||||
}
|
||||
|
||||
private Map<String, Index> asMap(Index... indexes) {
|
||||
return stream(indexes).collect(Collectors.toMap(Index::getName, Function.identity()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectIndexesFromApplicationContext() {
|
||||
|
||||
Index mockIndexOne = mockIndex("MockIndexOne");
|
||||
Index mockIndexTwo = mockIndex("MockIndexTwo");
|
||||
|
||||
Map<String, Index> indexBeans = asMap(mockIndexOne, mockIndexTwo);
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(eq(Index.class))).thenReturn(indexBeans);
|
||||
|
||||
Set<Index> indexes = this.indexCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(indexes).isNotNull();
|
||||
assertThat(indexes).hasSize(2);
|
||||
assertThat(indexes).containsAll(asSet(mockIndexOne, mockIndexTwo));
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(Index.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectIndexesFromApplicationContextWhenNoBeansOfTypeIndexExist() {
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(eq(Index.class))).thenReturn(Collections.emptyMap());
|
||||
|
||||
Set<Index> indexes = this.indexCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(indexes).isNotNull();
|
||||
assertThat(indexes).isEmpty();
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(Index.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectIndexesFromGemFireCache() {
|
||||
|
||||
Index mockIndexOne = mockIndex("MockIndexOne");
|
||||
Index mockIndexTwo = mockIndex("MockIndexTwo");
|
||||
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(asSet(mockIndexOne, mockIndexTwo));
|
||||
|
||||
Set<Index> indexes = this.indexCollector.collectFrom(this.mockCache);
|
||||
|
||||
assertThat(indexes).isNotNull();
|
||||
assertThat(indexes).hasSize(2);
|
||||
assertThat(indexes).containsAll(asSet(mockIndexOne, mockIndexTwo));
|
||||
|
||||
verify(this.mockCache, times(1)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectIndexesFromGemFireCacheWhenNoIndexesExist() {
|
||||
|
||||
when(this.mockQueryService.getIndexes()).thenReturn(Collections.emptySet());
|
||||
|
||||
Set<Index> indexes = this.indexCollector.collectFrom(this.mockCache);
|
||||
|
||||
assertThat(indexes).isNotNull();
|
||||
assertThat(indexes).isEmpty();
|
||||
|
||||
verify(this.mockCache, times(1)).getQueryService();
|
||||
verify(this.mockQueryService, times(1)).getIndexes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.IndexType;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link IndexDefiner}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.data.gemfire.IndexType
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.IndexDefinition
|
||||
* @see IndexDefiner
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class IndexDefinerUnitTests {
|
||||
|
||||
@Mock
|
||||
private Index mockIndex;
|
||||
|
||||
@Mock
|
||||
private Region<?, ?> mockRegion;
|
||||
|
||||
private IndexDefiner indexInstanceHandler = new IndexDefiner();
|
||||
|
||||
@Before
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setup() {
|
||||
when(this.mockIndex.getName()).thenReturn("MockIndex");
|
||||
when(this.mockIndex.getIndexedExpression()).thenReturn("testExpression");
|
||||
when(this.mockIndex.getFromClause()).thenReturn("/TestFromClause");
|
||||
when(this.mockIndex.getType()).thenReturn(IndexType.HASH.getGemfireIndexType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIndexInstanceIsTrue() {
|
||||
assertThat(this.indexInstanceHandler.canDefine(this.mockIndex)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleNullInstanceIsFalse() {
|
||||
assertThat(this.indexInstanceHandler.canDefine((Object) null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleRegionInstanceIsFalse() {
|
||||
assertThat(this.indexInstanceHandler.canDefine(this.mockRegion)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIndexTypeIsTrue() {
|
||||
assertThat(this.indexInstanceHandler.canDefine(Index.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleNullTypeIsFalse() {
|
||||
assertThat(this.indexInstanceHandler.canDefine((Class<?>) null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleRegionTypeIsFalse() {
|
||||
assertThat(this.indexInstanceHandler.canDefine(Region.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIndexSchemaObjectTypeIsTrue() {
|
||||
assertThat(this.indexInstanceHandler.canDefine(SchemaObjectType.INDEX)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleNullSchemaObjectTypeIsFalse() {
|
||||
assertThat(this.indexInstanceHandler.canDefine((SchemaObjectType) null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleRegionSchemaObjectTypeIsFalse() {
|
||||
assertThat(this.indexInstanceHandler.canDefine(SchemaObjectType.REGION)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineForIndexObject() {
|
||||
|
||||
IndexDefinition indexDefinition = this.indexInstanceHandler.define(this.mockIndex).orElse(null);
|
||||
|
||||
assertThat(indexDefinition).isNotNull();
|
||||
assertThat(indexDefinition.getExpression()).isEqualTo("testExpression");
|
||||
assertThat(indexDefinition.getFromClause()).isEqualTo("/TestFromClause");
|
||||
assertThat(indexDefinition.getIndexType()).isEqualTo(IndexType.HASH);
|
||||
assertThat(indexDefinition.getType()).isEqualTo(SchemaObjectType.INDEX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineForRegionObject() {
|
||||
assertThat(this.indexInstanceHandler.define(this.mockRegion).isPresent()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RegionCollector}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.schema.support.RegionCollector
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegionCollectorUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationContext mockApplicationContext;
|
||||
|
||||
@Mock
|
||||
private GemFireCache mockCache;
|
||||
|
||||
private RegionCollector regionCollector = new RegionCollector();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, V> Region<K, V> mockRegion(String name) {
|
||||
|
||||
Region<K, V> mockRegion = mock(Region.class, name);
|
||||
|
||||
when(mockRegion.getName()).thenReturn(name);
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
private Map<String, Region> asMap(Region<?, ?>... regions) {
|
||||
return stream(regions).collect(Collectors.toMap(Region::getName, Function.identity()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectRegionsFromApplicationContext() {
|
||||
|
||||
Region mockRegionOne = mockRegion("MockRegionOne");
|
||||
Region mockRegionTwo = mockRegion("MockRegionTwo");
|
||||
|
||||
Map<String, Region> regionBeans = asMap(mockRegionOne, mockRegionTwo);
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(eq(Region.class))).thenReturn(regionBeans);
|
||||
|
||||
Set<Region> actualRegions = this.regionCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(actualRegions).isNotNull();
|
||||
assertThat(actualRegions).hasSize(2);
|
||||
assertThat(actualRegions).containsAll(asSet(mockRegionOne, mockRegionTwo));
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(Region.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectRegionsFromApplicationContextWhenNoBeansOfTypeRegionExist() {
|
||||
|
||||
when(this.mockApplicationContext.getBeansOfType(eq(Region.class))).thenReturn(Collections.emptyMap());
|
||||
|
||||
Set<Region> actualRegions = this.regionCollector.collectFrom(this.mockApplicationContext);
|
||||
|
||||
assertThat(actualRegions).isNotNull();
|
||||
assertThat(actualRegions).isEmpty();
|
||||
|
||||
verify(this.mockApplicationContext, times(1)).getBeansOfType(eq(Region.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectRegionsFromGemFireCache() {
|
||||
|
||||
Region mockRegionOne = mockRegion("MockRegionOne");
|
||||
Region mockRegionTwo = mockRegion("MockRegionTwo");
|
||||
|
||||
when(this.mockCache.rootRegions()).thenReturn(asSet(mockRegionOne, mockRegionTwo));
|
||||
|
||||
Set<Region> actualRegions = this.regionCollector.collectFrom(this.mockCache);
|
||||
|
||||
assertThat(actualRegions).isNotNull();
|
||||
assertThat(actualRegions).hasSize(2);
|
||||
assertThat(actualRegions).containsAll(asSet(mockRegionOne, mockRegionTwo));
|
||||
|
||||
verify(this.mockCache, times(1)).rootRegions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void collectRegionsFromGemFireCacheWhenNoRootRegionsExist() {
|
||||
|
||||
when(this.mockCache.rootRegions()).thenReturn(Collections.emptySet());
|
||||
|
||||
Set<Region> actualRegions = this.regionCollector.collectFrom(this.mockCache);
|
||||
|
||||
assertThat(actualRegions).isNotNull();
|
||||
assertThat(actualRegions).isEmpty();
|
||||
|
||||
verify(this.mockCache, times(1)).rootRegions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.schema.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.gemfire.config.schema.SchemaObjectType;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RegionDefiner}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.data.gemfire.config.schema.definitions.RegionDefinition
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegionDefinerUnitTests {
|
||||
|
||||
@Mock
|
||||
private Index mockIndex;
|
||||
|
||||
@Mock
|
||||
private Region<Object, Object> mockRegion;
|
||||
|
||||
private RegionDefiner regionInstanceHandler = new RegionDefiner();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(this.mockRegion.getName()).thenReturn("MockRegion");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIndexInstanceIsFalse() {
|
||||
assertThat(this.regionInstanceHandler.canDefine(this.mockIndex)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleNullInstanceIsFalse() {
|
||||
assertThat(this.regionInstanceHandler.canDefine((Object) null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleRegionInstanceIsTrue() {
|
||||
assertThat(this.regionInstanceHandler.canDefine(this.mockRegion)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIndexTypeIsFalse() {
|
||||
assertThat(this.regionInstanceHandler.canDefine(Index.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleNullTypeIsFalse() {
|
||||
assertThat(this.regionInstanceHandler.canDefine((Class<?>) null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleRegionTypeIsTrue() {
|
||||
assertThat(this.regionInstanceHandler.canDefine(Region.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIndexSchemaObjectTypeIsFalse() {
|
||||
assertThat(this.regionInstanceHandler.canDefine(SchemaObjectType.INDEX)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleNullSchemaObjectTypeIsFalse() {
|
||||
assertThat(this.regionInstanceHandler.canDefine((SchemaObjectType) null)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleRegionSchemaObjectTypeIsTrue() {
|
||||
assertThat(this.regionInstanceHandler.canDefine(SchemaObjectType.REGION)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void defineClientRegion() {
|
||||
|
||||
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(this.mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn("TestPool");
|
||||
|
||||
RegionDefinition regionDefinition = this.regionInstanceHandler.define(this.mockRegion).orElse(null);
|
||||
|
||||
assertThat(regionDefinition).isNotNull();
|
||||
assertThat(regionDefinition.getName()).isEqualTo(this.mockRegion.getName());
|
||||
assertThat(regionDefinition.getRegionShortcut()).isEqualTo(RegionShortcut.PARTITION);
|
||||
assertThat(regionDefinition.getType()).isEqualTo(SchemaObjectType.REGION);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void definePeerRegion() {
|
||||
|
||||
RegionAttributes<Object, Object> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(this.mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionAttributes.getPoolName()).thenReturn(" ");
|
||||
|
||||
assertThat(this.regionInstanceHandler.define(this.mockRegion).isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineWithNull() {
|
||||
assertThat(this.regionInstanceHandler.define(null).isPresent()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package org.springframework.data.gemfire.test.support;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -35,19 +40,57 @@ public abstract class IOUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean close(Closeable closeable) {
|
||||
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
return true;
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
catch (IOException cause) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(String.format("Failed to close the Closeable object (%1$s) due to an I/O error:%n%2$s",
|
||||
closeable, ThrowableUtils.toString(ignore)));
|
||||
closeable, ThrowableUtils.toString(cause)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T deserializeObject(byte[] objectBytes) throws IOException, ClassNotFoundException {
|
||||
|
||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(objectBytes);
|
||||
|
||||
ObjectInputStream objectInputStream = null;
|
||||
|
||||
try {
|
||||
objectInputStream = new ObjectInputStream(byteArrayInputStream);
|
||||
|
||||
return (T) objectInputStream.readObject();
|
||||
}
|
||||
finally {
|
||||
IOUtils.close(objectInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static byte[] serializeObject(Serializable obj) throws IOException {
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
ObjectOutputStream objectOutputStream = null;
|
||||
|
||||
try {
|
||||
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
|
||||
objectOutputStream.writeObject(obj);
|
||||
objectOutputStream.flush();
|
||||
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
finally {
|
||||
IOUtils.close(objectOutputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user