SGF-674 - Add EnableClusterConfiguration annotation to push cluster configuration meta-data from the client to the server.
This commit is contained in:
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user