DATAGEODE-122 - Refactor Function annotation configuration to be smarter in resolving Apache Geode objects on startup.

Renames OnMember, OnMembers, OnRegion, OnServer and OnServers *ExecutionBeanDefinitionBuilder classes to *FunctionExecutionBeanDefinitionBuilder.
This commit is contained in:
John Blum
2018-06-12 19:42:55 -07:00
parent ddcc6a1b34
commit 89cafeba2d
33 changed files with 833 additions and 464 deletions

View File

@@ -139,27 +139,22 @@ public class FunctionGemfireAdminTemplate extends AbstractGemfireAdminOperations
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)

View File

@@ -27,7 +27,6 @@ class DefaultFunctionArgumentResolver implements FunctionArgumentResolver {
/*
* (non-Javadoc)
*
* @see java.lang.reflect.Method
*/
@Override
@@ -37,28 +36,33 @@ class DefaultFunctionArgumentResolver implements FunctionArgumentResolver {
/*
* (non-Javadoc)
*
* @see org.springframework.data.gemfire.function.FunctionArgumentResolver#resolveFunctionArguments(org.apache.geode.cache.execute.FunctionContext)
*/
@Override
public Object[] resolveFunctionArguments(final FunctionContext functionContext) {
return (isArray(functionContext.getArguments())) ? toObjectArray((Object[]) functionContext.getArguments())
return isArray(functionContext.getArguments())
? toObjectArray((Object[]) functionContext.getArguments())
: getArguments(functionContext);
}
private boolean isArray(final Object value) {
return (value != null && value.getClass().isArray());
return value != null && value.getClass().isArray();
}
private Object[] toObjectArray(final Object[] arguments) {
Object[] result = new Object[arguments.length];
System.arraycopy(arguments, 0, result, 0, arguments.length);
return result;
}
private Object[] getArguments(final FunctionContext context) {
Object arguments = context.getArguments();
return (arguments != null ? new Object[] { arguments } : EMPTY_ARRAY);
}
Object arguments = context.getArguments();
return arguments != null ? new Object[] { arguments } : EMPTY_ARRAY;
}
}

View File

@@ -45,6 +45,7 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv
private final Method method;
public FunctionContextInjectingArgumentResolver(Method method) {
this.method = method;
int regionDataAnnotationParameterPosition = GemfireFunctionUtils.getAnnotationParameterPosition(
@@ -76,11 +77,12 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv
@Override
public Method getFunctionAnnotatedMethod() {
return method;
return this.method;
}
@Override
public Object[] resolveFunctionArguments(FunctionContext functionContext) {
Object[] args = super.resolveFunctionArguments(functionContext);
if (functionContext instanceof RegionFunctionContext) {
@@ -103,9 +105,9 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv
args = ArrayUtils.insert(args, resultSenderParameterPosition, functionContext.getResultSender());
}
Assert.isTrue(args.length == method.getParameterTypes().length, String.format(
"wrong number of arguments for method %s. Expected %d, but was %d", method.getName(),
method.getParameterTypes().length, args.length));
Assert.isTrue(args.length == this.method.getParameterTypes().length,
String.format("Wrong number of arguments for method [%s]; Expected [%d], but was [%d]",
this.method.getName(), this.method.getParameterTypes().length, args.length));
return args;
}
@@ -131,9 +133,6 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv
return region;
}
/*
* (non-Javadoc)
*/
private static int getArgumentTypePosition(Method method, Class<?> requiredType) {
int index = 0;
int position = -1;
@@ -152,5 +151,4 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv
return position;
}
}

View File

@@ -39,18 +39,20 @@ class PdxFunctionArgumentResolver extends DefaultFunctionArgumentResolver {
/*
* (non-Javadoc)
*
* @see org.apache.geode.cache.execute.FunctionContext
*/
@Override
public Object[] resolveFunctionArguments(final FunctionContext functionContext) {
Object[] functionArguments = super.resolveFunctionArguments(functionContext);
if (isPdxSerializerConfigured()) {
int index = 0;
for (Object functionArgument : functionArguments) {
if (functionArgument instanceof PdxInstance) {
String className = ((PdxInstance) functionArgument).getClassName();
if (isDeserializationNecessary(className)) {
@@ -67,7 +69,6 @@ class PdxFunctionArgumentResolver extends DefaultFunctionArgumentResolver {
/*
* (non-Javadoc)
*
* @see java.lang.reflect.Method
*/
@Override
@@ -77,7 +78,6 @@ class PdxFunctionArgumentResolver extends DefaultFunctionArgumentResolver {
/*
* (non-Javadoc)
*
* @see org.apache.geode.cache.Cache#getPdxSerializer()
* @see org.apache.geode.cache.CacheFactory#getAnyInstance()
*/
@@ -92,16 +92,15 @@ class PdxFunctionArgumentResolver extends DefaultFunctionArgumentResolver {
/*
* (non-Javadac)
*
* @see #isOnClasspath(String)
* @see #functionAnnotatedMethodHasParameterOfType(String)
*/
boolean isDeserializationNecessary(final String className) {
return (isOnClasspath(className) && functionAnnotatedMethodHasParameterOfType(className));
}
/*
* (non-Javadoc)
*
* @see java.lang.Thread#currentThread()
* @see java.lang.Thread#getContextClassLoader()
* @see org.springframework.util.ClassUtils#isPresent(String, ClassLoader)
@@ -112,7 +111,6 @@ class PdxFunctionArgumentResolver extends DefaultFunctionArgumentResolver {
/*
* (non-Javadoc)
*
* @see #getFunctionAnnotatedMethod()
* @see java.lang.reflect.Method#getParameterTypes()
*/
@@ -125,5 +123,4 @@ class PdxFunctionArgumentResolver extends DefaultFunctionArgumentResolver {
return false;
}
}

View File

@@ -61,10 +61,11 @@ public class PojoFunctionWrapper implements Function {
private final String id;
public PojoFunctionWrapper(Object target, Method method, String id) {
this.functionArgumentResolver = new FunctionContextInjectingArgumentResolver(method);
this.target = target;
this.method = method;
this.id = (StringUtils.hasText(id) ? id : method.getName());
this.id = StringUtils.hasText(id) ? id : method.getName();
this.functionArgumentResolver = new FunctionContextInjectingArgumentResolver(method);
this.HA = false;
this.hasResult = !method.getReturnType().equals(void.class);
this.optimizeForWrite = false;
@@ -108,7 +109,7 @@ public class PojoFunctionWrapper implements Function {
@Override
@SuppressWarnings("unchecked")
public void execute(final FunctionContext functionContext) {
public void execute(FunctionContext functionContext) {
Object[] args = this.functionArgumentResolver.resolveFunctionArguments(functionContext);
@@ -123,8 +124,10 @@ public class PojoFunctionWrapper implements Function {
if (logger.isDebugEnabled()) {
logger.debug(String.format("About to invoke method [%s] on class [%s] as Function [%s]",
this.method.getName(), this.target.getClass().getName(), getId()));
if (logger.isDebugEnabled()) {
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(String.format("Argument of type [%s] is [%s]", arg.getClass().getName(), arg.toString()));
@@ -141,10 +144,10 @@ public class PojoFunctionWrapper implements Function {
}
else {
if (ObjectUtils.isArray(result)) {
new BatchingResultSender(batchSize, resultSender).sendArrayResults(result);
new BatchingResultSender(this.batchSize, resultSender).sendArrayResults(result);
}
else if (Iterable.class.isAssignableFrom(result.getClass())) {
new BatchingResultSender(batchSize, resultSender).sendResults((Iterable<?>) result);
new BatchingResultSender(this.batchSize, resultSender).sendResults((Iterable<?>) result);
}
else {
resultSender.lastResult(result);

View File

@@ -1,17 +1,20 @@
/*
* 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 java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -35,40 +38,37 @@ abstract class AbstractFunctionExecutionBeanDefinitionBuilder {
protected final Log log = LogFactory.getLog(getClass());
/**
*
* @param configuration the configuration values
*/
AbstractFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
Assert.notNull(configuration);
AbstractFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
Assert.notNull(configuration, "Configuration must not be null");
this.configuration = configuration;
}
/**
* Build the bean definition
* @param registry
* @return
*/
BeanDefinition build(BeanDefinitionRegistry registry) {
BeanDefinition build(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder functionProxyFactoryBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(
getFunctionProxyFactoryBeanClass());
functionProxyFactoryBeanBuilder.addConstructorArgValue(configuration.getFunctionExecutionInterface());
functionProxyFactoryBeanBuilder.addConstructorArgValue(this.configuration.getFunctionExecutionInterface());
functionProxyFactoryBeanBuilder.addConstructorArgReference(BeanDefinitionReaderUtils.registerWithGeneratedName(
buildGemfireFunctionOperations(registry), registry));
return functionProxyFactoryBeanBuilder.getBeanDefinition();
}
}
protected AbstractBeanDefinition buildGemfireFunctionOperations(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder functionTemplateBuilder = getGemfireFunctionOperationsBeanDefinitionBuilder(registry);
functionTemplateBuilder.setLazyInit(true);
String resultCollectorReference = (String) configuration.getAttribute("resultCollector");
if (StringUtils.hasText(resultCollectorReference)){
functionTemplateBuilder.addPropertyReference("resultCollector", resultCollectorReference);
}
Optional.ofNullable(this.configuration.getAttribute("resultCollector"))
.map(String::valueOf)
.filter(StringUtils::hasText)
.ifPresent(reference -> functionTemplateBuilder.addPropertyReference("resultCollector", reference));
return functionTemplateBuilder.getBeanDefinition();
}

View File

@@ -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.
@@ -28,11 +28,11 @@ import org.springframework.data.gemfire.function.annotation.OnServers;
* @see org.springframework.data.gemfire.function.annotation.OnRegion
* @see org.springframework.data.gemfire.function.annotation.OnServer
* @see org.springframework.data.gemfire.function.annotation.OnServers
* @see org.springframework.data.gemfire.function.config.OnMemberExecutionBeanDefinitionBuilder
* @see org.springframework.data.gemfire.function.config.OnMembersExecutionBeanDefinitionBuilder
* @see org.springframework.data.gemfire.function.config.OnRegionExecutionBeanDefinitionBuilder
* @see org.springframework.data.gemfire.function.config.OnServerExecutionBeanDefinitionBuilder
* @see org.springframework.data.gemfire.function.config.OnServersExecutionBeanDefinitionBuilder
* @see OnMemberFunctionExecutionBeanDefinitionBuilder
* @see OnMembersFunctionExecutionBeanDefinitionBuilder
* @see OnRegionFunctionExecutionBeanDefinitionBuilder
* @see OnServerFunctionExecutionBeanDefinitionBuilder
* @see OnServersFunctionExecutionBeanDefinitionBuilder
*/
abstract class FunctionExecutionBeanDefinitionBuilderFactory {
@@ -40,22 +40,21 @@ abstract class FunctionExecutionBeanDefinitionBuilderFactory {
String functionExecutionAnnotation = configuration.getAnnotationType();
if (OnMember.class.getName().equals(functionExecutionAnnotation)) {
return new OnMemberExecutionBeanDefinitionBuilder(configuration);
return new OnMemberFunctionExecutionBeanDefinitionBuilder(configuration);
}
else if (OnMembers.class.getName().equals(functionExecutionAnnotation)) {
return new OnMembersExecutionBeanDefinitionBuilder(configuration);
return new OnMembersFunctionExecutionBeanDefinitionBuilder(configuration);
}
else if (OnRegion.class.getName().equals(functionExecutionAnnotation)) {
return new OnRegionExecutionBeanDefinitionBuilder(configuration);
}
return new OnRegionFunctionExecutionBeanDefinitionBuilder(configuration);
}
else if (OnServer.class.getName().equals(functionExecutionAnnotation)) {
return new OnServerExecutionBeanDefinitionBuilder(configuration);
}
return new OnServerFunctionExecutionBeanDefinitionBuilder(configuration);
}
else if (OnServers.class.getName().equals(functionExecutionAnnotation)) {
return new OnServersExecutionBeanDefinitionBuilder(configuration);
return new OnServersFunctionExecutionBeanDefinitionBuilder(configuration);
}
return null;
}
}

View File

@@ -109,17 +109,19 @@ public class FunctionExecutionBeanDefinitionRegistrar implements ImportBeanDefin
Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes();
String functionExecutionAnnotation = null;
String existingFunctionExecutionAnnotation = null;
for (String annotationType : annotationTypes) {
if (functionExecutionAnnotationTypeNames.contains(annotationType)) {
Assert.isNull(functionExecutionAnnotation, String.format(
"interface %1$s contains multiple Function Execution Annotations: %2$s, %3$s",
beanDefinition.getBeanClassName(), functionExecutionAnnotation, annotationType));
functionExecutionAnnotation = annotationType;
Assert.isNull(existingFunctionExecutionAnnotation,
String.format("Interface [%1$s] contains multiple Function Execution Annotations: %2$s, %3$s",
beanDefinition.getBeanClassName(), existingFunctionExecutionAnnotation, annotationType));
existingFunctionExecutionAnnotation = annotationType;
}
}
return functionExecutionAnnotation;
return existingFunctionExecutionAnnotation;
}
}

View File

@@ -1,72 +1,81 @@
/*
* 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 java.util.Map;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.Assert;
/**
* Function execution configuration used by bean definition builders
*
*
* @author David Turanski
* @author John Blum
*/
class FunctionExecutionConfiguration {
private Class<?> functionExecutionInterface;
private final Map<String,Object> attributes;
private final AnnotationAttributes annotationAttributes;
private final String annotationType;
/* constructor for testing purposes only! */
/* constructor for testing purposes only */
FunctionExecutionConfiguration() {
this.annotationType = null;
this.attributes = null;
this.annotationAttributes = null;
}
FunctionExecutionConfiguration(ScannedGenericBeanDefinition beanDefinition, String annotationType) {
try {
this.annotationType = annotationType;
this.attributes = beanDefinition.getMetadata().getAnnotationAttributes(annotationType, true);
this.functionExecutionInterface = beanDefinition.resolveBeanClass(beanDefinition.getClass().getClassLoader());
Assert.isTrue(functionExecutionInterface.isInterface(),
String.format("The annotation %1$s only applies to an interface. It is not valid for the type %2$s",
annotationType, functionExecutionInterface.getName()));
this.annotationType = annotationType;
this.annotationAttributes = AnnotationAttributes.fromMap(beanDefinition.getMetadata()
.getAnnotationAttributes(annotationType, true));
this.functionExecutionInterface =
beanDefinition.resolveBeanClass(beanDefinition.getClass().getClassLoader());
assertFunctionExecutionInterfaceIsValid(annotationType);
}
catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private void assertFunctionExecutionInterfaceIsValid(String annotationType) {
boolean valid = this.functionExecutionInterface != null && this.functionExecutionInterface.isInterface();
Assert.isTrue(valid, String.format("The annotation [%1$s] only applies to an interface; It is not valid for type [%2$s]",
annotationType, SpringUtils.nullSafeName(this.functionExecutionInterface)));
}
String getAnnotationType() {
return this.annotationType;
}
Object getAttribute(String name) {
return attributes.get(name);
return this.annotationAttributes.get(name);
}
Map<String, Object> getAttributes() {
return this.attributes;
AnnotationAttributes getAttributes() {
return this.annotationAttributes;
}
Class<?> getFunctionExecutionInterface() {
return this.functionExecutionInterface;
}
}

View File

@@ -10,8 +10,11 @@
* 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 java.util.Optional;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.gemfire.function.annotation.OnMember;
@@ -27,13 +30,15 @@ import org.springframework.util.StringUtils;
* @author John Blum
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder
*/
abstract class MemberBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder {
abstract class MemberBasedFunctionExecutionBeanDefinitionBuilder
extends AbstractFunctionExecutionBeanDefinitionBuilder {
MemberBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
MemberBasedFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry)
*/
@Override
@@ -42,17 +47,19 @@ abstract class MemberBasedExecutionBeanDefinitionBuilder extends AbstractFunctio
BeanDefinitionBuilder functionTemplateBuilder =
BeanDefinitionBuilder.genericBeanDefinition(getGemfireOperationsClass());
String groups = (String)configuration.getAttribute("groups");
if (StringUtils.hasText(groups)) {
functionTemplateBuilder.addConstructorArgValue(StringUtils.commaDelimitedListToStringArray(groups));
}
Optional.ofNullable(this.configuration.getAttribute("groups"))
.map(String::valueOf)
.map(StringUtils::trimAllWhitespace)
.filter(StringUtils::hasText)
.map(StringUtils::commaDelimitedListToStringArray)
.ifPresent(functionTemplateBuilder::addConstructorArgValue);
return functionTemplateBuilder;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getFunctionProxyFactoryBeanClass()
*/
@Override

View File

@@ -1,36 +1,33 @@
/*
* 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 org.springframework.data.gemfire.function.execution.GemfireOnMemberFunctionTemplate;
/**
*
* @author David Turanski
*
* @author John Blum
*/
class OnMemberExecutionBeanDefinitionBuilder extends MemberBasedExecutionBeanDefinitionBuilder {
class OnMemberFunctionExecutionBeanDefinitionBuilder extends MemberBasedFunctionExecutionBeanDefinitionBuilder {
/**
* @param configuration
*/
OnMemberExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
OnMemberFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
// TODO Auto-generated constructor stub
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.MemberBasedExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsClass()
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.MemberBasedFunctionExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsClass()
*/
@Override
protected Class<?> getGemfireOperationsClass() {

View File

@@ -1,39 +1,36 @@
/*
* 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 org.springframework.data.gemfire.function.execution.GemfireOnMembersFunctionTemplate;
/**
* @author David Turanski
*
* @author John Blum
*/
class OnMembersExecutionBeanDefinitionBuilder extends MemberBasedExecutionBeanDefinitionBuilder {
class OnMembersFunctionExecutionBeanDefinitionBuilder extends MemberBasedFunctionExecutionBeanDefinitionBuilder {
/**
* @param configuration
*/
OnMembersExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
OnMembersFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
// TODO Auto-generated constructor stub
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.MemberBasedExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsClass()
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.MemberBasedFunctionExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsClass()
*/
@Override
protected Class<?> getGemfireOperationsClass() {
return GemfireOnMembersFunctionTemplate.class;
}
}

View File

@@ -1,15 +1,16 @@
/*
* 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 org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -21,34 +22,38 @@ import org.springframework.data.gemfire.function.execution.OnRegionFunctionProxy
* @author David Turanski
*
*/
class OnRegionExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder {
class OnRegionFunctionExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder {
/**
* @param configuration
*/
OnRegionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
OnRegionFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry)
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder
* #getGemfireFunctionOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry)
*/
@Override
protected BeanDefinitionBuilder getGemfireFunctionOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder functionTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(GemfireOnRegionFunctionTemplate.class);
functionTemplateBuilder.addConstructorArgReference((String)configuration.getAttribute("region"));
BeanDefinitionBuilder functionTemplateBuilder =
BeanDefinitionBuilder.genericBeanDefinition(GemfireOnRegionFunctionTemplate.class);
String regionBeanName = String.valueOf(this.configuration.getAttribute("region"));
functionTemplateBuilder.addConstructorArgReference(regionBeanName);
return functionTemplateBuilder;
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getFunctionProxyFactoryBeanClass()
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder
* #getFunctionProxyFactoryBeanClass()
*/
@Override
protected Class<?> getFunctionProxyFactoryBeanClass() {
return OnRegionFunctionProxyFactoryBean.class;
}
}

View File

@@ -10,6 +10,7 @@
* 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 org.springframework.data.gemfire.function.execution.GemfireOnServerFunctionTemplate;
@@ -18,19 +19,19 @@ import org.springframework.data.gemfire.function.execution.GemfireOnServerFuncti
* @author David Turanski
* @author John Blum
*/
class OnServerExecutionBeanDefinitionBuilder extends ServerBasedExecutionBeanDefinitionBuilder {
class OnServerFunctionExecutionBeanDefinitionBuilder extends ServerBasedFunctionExecutionBeanDefinitionBuilder {
OnServerExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
OnServerFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.ServerBasedExecutionBeanDefinitionBuilder
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.ServerBasedFunctionExecutionBeanDefinitionBuilder
* #getGemfireFunctionOperationsClass()
*/
@Override
protected Class<?> getGemfireFunctionOperationsClass() {
return GemfireOnServerFunctionTemplate.class;
}
}

View File

@@ -10,25 +10,25 @@
* 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 org.springframework.data.gemfire.function.execution.GemfireOnServersFunctionTemplate;
/**
* @author David Turanski
*
* @author John Blum
*/
class OnServersExecutionBeanDefinitionBuilder extends ServerBasedExecutionBeanDefinitionBuilder {
class OnServersFunctionExecutionBeanDefinitionBuilder extends ServerBasedFunctionExecutionBeanDefinitionBuilder {
/**
* @param configuration
*/
OnServersExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
OnServersFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.ServerBasedExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsClass()
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.ServerBasedFunctionExecutionBeanDefinitionBuilder
* #getGemfireFunctionOperationsClass()
*/
@Override
protected Class<?> getGemfireFunctionOperationsClass() {

View File

@@ -12,13 +12,14 @@
*/
package org.springframework.data.gemfire.function.config;
import java.util.Optional;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.function.annotation.OnServer;
import org.springframework.data.gemfire.function.annotation.OnServers;
import org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -27,38 +28,51 @@ import org.springframework.util.StringUtils;
*
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.data.gemfire.function.annotation.OnServer
* @see org.springframework.data.gemfire.function.annotation.OnServers
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder
*/
abstract class ServerBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder {
abstract class ServerBasedFunctionExecutionBeanDefinitionBuilder
extends AbstractFunctionExecutionBeanDefinitionBuilder {
ServerBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
ServerBasedFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder
* #getGemfireFunctionOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry)
*/
@Override
protected BeanDefinitionBuilder getGemfireFunctionOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) {
String resolvedCacheBeanName = Optional.ofNullable(this.configuration.getAttribute("cache"))
.map(String::valueOf)
.filter(StringUtils::hasText)
.orElse(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
Optional<String> poolBeanName = Optional.ofNullable(this.configuration.getAttribute("pool"))
.map(String::valueOf)
.filter(StringUtils::hasText);
BeanDefinitionBuilder functionTemplateBuilder =
BeanDefinitionBuilder.genericBeanDefinition(getGemfireFunctionOperationsClass());
String cache = (String) this.configuration.getAttribute("cache");
String pool = (String) this.configuration.getAttribute("pool");
functionTemplateBuilder.addConstructorArgReference(resolvedCacheBeanName);
Assert.state(!(StringUtils.hasText(cache) && StringUtils.hasText(pool)),
String.format("Invalid configuration for interface [%s]; cannot specify both 'pool' and 'cache'",
this.configuration.getFunctionExecutionInterface().getName()));
functionTemplateBuilder.addConstructorArgReference(StringUtils.hasText(pool)
? pool : (StringUtils.hasText(cache) ? cache : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
poolBeanName.ifPresent(it -> {
functionTemplateBuilder.addDependsOn(it);
functionTemplateBuilder.addPropertyReference("pool", it);
});
return functionTemplateBuilder;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder
* #getFunctionProxyFactoryBeanClass()
*/

View File

@@ -10,29 +10,32 @@
* 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;
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.ResultCollector;
import org.springframework.beans.factory.InitializingBean;
/**
* The base class for GemFire FunctionTemplates used to invoke GemFire Functions.
* The base class for {@link Function} templates used to invoke Apache Geode/Pivotal GemFire {@link Function Functions}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.ResultCollector
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.function.execution.GemfireFunctionOperations
*/
abstract class AbstractFunctionTemplate implements GemfireFunctionOperations {
protected Log log = LogFactory.getLog(this.getClass());
abstract class AbstractFunctionTemplate implements GemfireFunctionOperations, InitializingBean {
protected long timeout;
protected volatile ResultCollector<?, ?> resultCollector;
@Override
public void afterPropertiesSet() throws Exception { }
@Override
public <T> Iterable<T> execute(Function function, Object... args) {
return execute(getFunctionExecution().setArgs(args).setFunction(function));

View File

@@ -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.
@@ -16,8 +16,8 @@ import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
@@ -27,7 +27,7 @@ import org.springframework.util.ClassUtils;
/**
* A Proxy FactoryBean for all non-Region Function Execution interfaces.
*
*
* @author David Turanski
* @author John Blum
* @see java.lang.reflect.Method
@@ -47,7 +47,7 @@ public class GemfireFunctionProxyFactoryBean implements FactoryBean<Object>, Met
private final GemfireFunctionOperations gemfireFunctionOperations;
protected Log logger = LogFactory.getLog(this.getClass());
protected Logger logger = LoggerFactory.getLogger(this.getClass());
private FunctionExecutionMethodMetadata<MethodMetadata> methodMetadata;
@@ -56,8 +56,12 @@ public class GemfireFunctionProxyFactoryBean implements FactoryBean<Object>, Met
* @param gemfireFunctionOperations an interface used to delegate the function invocation (typically a GemFire function template)
*/
public GemfireFunctionProxyFactoryBean(Class<?> functionExecutionInterface, GemfireFunctionOperations gemfireFunctionOperations) {
Assert.notNull(functionExecutionInterface, "'functionExecutionInterface' must not be null");
Assert.isTrue(functionExecutionInterface.isInterface(), "'functionExecutionInterface' must be an interface");
Assert.notNull(functionExecutionInterface, "Function execution interface must not be null");
Assert.isTrue(functionExecutionInterface.isInterface(),
String.format("Function execution type [%s] must be an interface",
functionExecutionInterface.getClass().getName()));
this.functionExecutionInterface = functionExecutionInterface;
this.gemfireFunctionOperations = gemfireFunctionOperations;
@@ -76,26 +80,27 @@ public class GemfireFunctionProxyFactoryBean implements FactoryBean<Object>, Met
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (AopUtils.isToStringMethod(invocation.getMethod())) {
return "GemFire Function Proxy for service interface [" + this.functionExecutionInterface + "]";
return String.format("Function Proxy for interface [%s]", this.functionExecutionInterface.getName());
}
if (logger.isDebugEnabled()) {
logger.debug("invoking method " + invocation.getMethod().getName());
logger.debug("Invoking method {}", invocation.getMethod().getName());
}
return invokeFunction(invocation.getMethod(), invocation.getArguments());
}
protected Object invokeFunction(Method method, Object[] args) {
return this.gemfireFunctionOperations.executeAndExtract(
methodMetadata.getMethodMetadata(method).getFunctionId(), args);
return this.gemfireFunctionOperations
.executeAndExtract(this.methodMetadata.getMethodMetadata(method).getFunctionId(), args);
}
@Override
public Object getObject() throws Exception {
if (functionExecutionProxy == null) {
onInit();
Assert.notNull(functionExecutionProxy, "failed to initialize proxy");
Assert.notNull(this.functionExecutionProxy, "Failed to initialize Function Proxy");
}
return functionExecutionProxy;
@@ -118,5 +123,4 @@ public class GemfireFunctionProxyFactoryBean implements FactoryBean<Object>, Met
initialized = true;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 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
@@ -10,6 +10,7 @@
* 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;
import java.util.Set;
@@ -20,50 +21,58 @@ import org.springframework.util.Assert;
/**
* @author David Turanski
*
* @author John Blum
*/
public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate implements GemfireOnRegionOperations {
private Region<?, ?> region;
private final Region<?, ?> region;
/**
* Constructs an instance of the GemFireOnRegionFunctionTemplate with the given GemFire Cache Region.
* Constructs a new instance of the {@link GemfireOnRegionFunctionTemplate} initialized with
* the given {@link Region}.
*
* @param region the GemFire Cache Region upon which the Function will be executed.
* @param region the {@link Region} upon which the {@link Function} will be executed.
* @throws IllegalArgumentException if {@link Region} is {@literal null}.
* @see org.apache.geode.cache.Region
*/
public GemfireOnRegionFunctionTemplate(Region<?, ?> region) {
Assert.notNull(region, "Region cannot be null");
Assert.notNull(region, "Region must not be null");
this.region = region;
}
@Override
public <T> Iterable<T> execute(Function function, Set<?> keys, Object... args) {
return execute(new RegionFunctionExecution(region).setKeys(keys).setFunction(function).setTimeout(timeout)
.setArgs(args));
}
@Override
public <T> Iterable<T> execute(String functionId, Set<?> keys, Object... args) {
return execute(new RegionFunctionExecution(region).setKeys(keys).setFunctionId(functionId).setTimeout(timeout)
.setArgs(args));
}
@Override
public <T> T executeAndextract(String functionId, Set<?> keys, Object... args) {
return this.<T> executeAndExtract(new RegionFunctionExecution(region).setKeys(keys).setFunctionId(functionId)
.setTimeout(timeout).setArgs(args));
}
@Override
protected AbstractFunctionExecution getFunctionExecution() {
protected RegionFunctionExecution getFunctionExecution() {
return new RegionFunctionExecution(this.region);
}
@Override
public void executeWithNoResult(String functionId, Set<?> keys, Object... args) {
execute(new RegionFunctionExecution(region).setKeys(keys).setFunctionId(functionId).setTimeout(timeout)
.setArgs(args), false);
public <T> Iterable<T> execute(String functionId, Set<?> keys, Object... args) {
return execute(getFunctionExecution()
.setKeys(keys)
.setFunctionId(functionId)
.setTimeout(this.timeout)
.setArgs(args));
}
@Override
public <T> T executeAndExtract(String functionId, Set<?> keys, Object... args) {
return executeAndExtract(getFunctionExecution()
.setKeys(keys)
.setFunctionId(functionId)
.setTimeout(this.timeout).setArgs(args));
}
@Override
public void executeWithNoResult(String functionId, Set<?> keys, Object... args) {
execute(getFunctionExecution()
.setKeys(keys)
.setFunctionId(functionId)
.setTimeout(this.timeout)
.setArgs(args), false);
}
}

View File

@@ -10,20 +10,42 @@
* 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;
import java.util.Set;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.Function;
/**
* Interface define {@link Region} {@link Function} data access operations.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.execute.Function
* @see org.springframework.data.gemfire.function.execution.GemfireFunctionOperations
*/
@SuppressWarnings("unused")
public interface GemfireOnRegionOperations extends GemfireFunctionOperations {
public abstract <T> Iterable<T> execute(String functionId, Set<?> keys, Object... args);
public abstract <T> Iterable<T> execute(Function function, Set<?> keys, Object... args);
public abstract void executeWithNoResult(String functionId, Set<?> keys, Object... args);
public abstract <T> T executeAndextract(String functionId, Set<?> keys, Object... args);
default <T> Iterable<T> execute(Function function, Set<?> keys, Object... args) {
return execute(function.getId(), keys, args);
}
<T> Iterable<T> execute(String functionId, Set<?> keys, Object... args);
default <T> T executeAndExtract(Function function, Set<?> keys, Object... args) {
return executeAndExtract(function.getId(), keys, args);
}
<T> T executeAndExtract(String functionId, Set<?> keys, Object... args);
default void executeWithNoResult(Function function, Set<?> keys, Object... args) {
executeWithNoResult(function.getId(), keys, args);
}
void executeWithNoResult(String functionId, Set<?> keys, Object... args);
}

View File

@@ -13,31 +13,110 @@
package org.springframework.data.gemfire.function.execution;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Optional;
import org.apache.geode.cache.RegionService;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.shiro.util.Assert;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.util.CacheUtils;
import org.springframework.util.StringUtils;
/**
* Creates an {@literal OnServer} {@link Function} {@link Execution} initialized with
* either a {@link RegionService cache} or a {@link Pool}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.RegionService
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionTemplate
*/
public class GemfireOnServerFunctionTemplate extends AbstractFunctionTemplate {
@SuppressWarnings("unused")
public class GemfireOnServerFunctionTemplate extends AbstractFunctionTemplate {
private Pool pool;
private final Pool pool;
private final RegionService cache;
private String poolName;
public GemfireOnServerFunctionTemplate(RegionService cache) {
Assert.notNull(cache, "RegionService must not be null");
this.cache = cache;
this.pool = null;
}
public GemfireOnServerFunctionTemplate(Pool pool) {
this.cache = null;
this.cache = resolveClientCache();
this.pool = pool;
}
public GemfireOnServerFunctionTemplate(String poolName) {
this.cache = resolveClientCache();
this.poolName = poolName;
}
public void setPool(Pool pool) {
this.pool = pool;
}
public void setPoolName(String poolName) {
this.poolName = poolName;
}
@Override
protected AbstractFunctionExecution getFunctionExecution() {
return (pool != null ? new PoolServerFunctionExecution(this.pool) : new ServerFunctionExecution(this.cache));
Object gemfireObject = resolveRequiredGemFireObject();
return gemfireObject instanceof Pool
? new PoolServerFunctionExecution((Pool) gemfireObject)
: new ServerFunctionExecution((RegionService) gemfireObject);
}
private Object resolveRequiredGemFireObject() {
return Optional.<Object>ofNullable(resolvePool()).orElseGet(this::resolveClientCache);
}
protected ClientCache resolveClientCache() {
return Optional.ofNullable(CacheUtils.getClientCache())
.orElseThrow(() -> newIllegalStateException("No ClientCache instance is present"));
}
protected Pool resolveDefaultPool() {
return Optional.ofNullable(PoolManager.find(GemfireUtils.DEFAULT_POOL_NAME))
.orElseThrow(() -> newIllegalStateException("No Pool was configured"));
}
protected Pool resolveNamedPool() {
if (StringUtils.hasText(this.poolName)) {
this.pool = Optional.ofNullable(PoolManager.find(this.poolName))
.orElseThrow(() -> newIllegalStateException("No Pool with name [%s] exists",
this.poolName));
}
return this.pool;
}
protected Pool resolvePool() {
this.pool = Optional.ofNullable(this.pool)
.orElseGet(this::resolveNamedPool);
return this.pool;
}
}

View File

@@ -13,35 +13,110 @@
package org.springframework.data.gemfire.function.execution;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Optional;
import org.apache.geode.cache.RegionService;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.util.CacheUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author David Turanski
* Creates an {@literal OnServers} {@link Function} {@link Execution} initialized with
* either a {@link RegionService cache} or a {@link Pool}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.RegionService
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionTemplate
*/
public class GemfireOnServersFunctionTemplate extends AbstractFunctionTemplate {
@SuppressWarnings("unused")
public class GemfireOnServersFunctionTemplate extends AbstractFunctionTemplate {
private Pool pool;
private final RegionService cache;
private final Pool pool;
private String poolName;
public GemfireOnServersFunctionTemplate(RegionService cache) {
Assert.notNull(cache, "RegionService must not be null");
public GemfireOnServersFunctionTemplate (RegionService cache) {
this.cache = cache;
this.pool = null;
}
public GemfireOnServersFunctionTemplate (Pool pool) {
public GemfireOnServersFunctionTemplate(Pool pool) {
this.cache = resolveClientCache();
this.pool = pool;
this.cache = null;
}
public GemfireOnServersFunctionTemplate(String poolName) {
this.cache = resolveClientCache();
this.poolName = poolName;
}
public void setPool(Pool pool) {
this.pool = pool;
}
public void setPoolName(String poolName) {
this.poolName = poolName;
}
@Override
protected AbstractFunctionExecution getFunctionExecution() {
if (this.pool == null) {
return new ServersFunctionExecution(this.cache);
}
return new PoolServersFunctionExecution(this.pool);
Object gemfireObject = resolveRequiredGemFireObject();
return gemfireObject instanceof Pool
? new PoolServersFunctionExecution((Pool) gemfireObject)
: new ServersFunctionExecution((RegionService) gemfireObject);
}
protected Object resolveRequiredGemFireObject() {
return Optional.<Object>ofNullable(resolvePool()).orElseGet(this::resolveClientCache);
}
protected ClientCache resolveClientCache() {
return Optional.ofNullable(CacheUtils.getClientCache())
.orElseThrow(() -> newIllegalStateException("No ClientCache instance is present"));
}
protected Pool resolveDefaultPool() {
return Optional.ofNullable(PoolManager.find(GemfireUtils.DEFAULT_POOL_NAME))
.orElseThrow(() -> newIllegalStateException("No Pool was configured"));
}
protected Pool resolveNamedPool() {
if (StringUtils.hasText(this.poolName)) {
this.pool = Optional.ofNullable(PoolManager.find(this.poolName))
.orElseThrow(() -> newIllegalStateException("No Pool with name [%s] exists",
this.poolName));
}
return this.pool;
}
protected Pool resolvePool() {
this.pool = Optional.ofNullable(this.pool)
.orElseGet(this::resolveNamedPool);
return this.pool;
}
}

View File

@@ -10,35 +10,47 @@
* 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;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionService;
import org.springframework.util.Assert;
/**
* Constructs an {@link Execution} using {@link FunctionService#onMember(String...)}.
*
* @author David Turanski
* @author John Blum
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.FunctionService
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
class GroupMemberFunctionExecution extends AbstractFunctionExecution {
private final String[] groups;
/**
* Constructs an instance of the GroupMemberFunctionExecution class to execute a data independent Function
* on a single member from each of the specified groups.
* Constructs a new instance of the {@link GroupMemberFunctionExecution} initialized to execute a data independent
* {@link Function} on a single member from each of the specified groups.
*
* @param groups the list of GemFire Groups from which to pick a member from each group on which to execute
* the data independent Function.
* @param groups array of {@link String groups} from which to pick a member from each group
* on which to execute the data independent {@link Function}.
* @throws IllegalArgumentException if {@link String groups} is {@literal null} or empty.
*/
public GroupMemberFunctionExecution(final String... groups) {
Assert.notEmpty(groups, "'groups' cannot be null or empty.");
public GroupMemberFunctionExecution(String... groups) {
Assert.notEmpty(groups, "Groups must not be null or empty");
this.groups = groups;
}
protected String[] getGroups() {
return this.groups;
}
/**
* Executes the data independent Function on a single member from each of the specified groups.
*
@@ -47,7 +59,6 @@ class GroupMemberFunctionExecution extends AbstractFunctionExecution {
*/
@Override
protected Execution getExecution() {
return FunctionService.onMember(this.groups);
return FunctionService.onMember(getGroups());
}
}

View File

@@ -10,34 +10,47 @@
* 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;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionService;
import org.springframework.util.Assert;
/**
* Constructs an {@link Execution} using {@link FunctionService#onMembers(String...)}.
*
* @author David Turanski
* @author John Blum
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.FunctionService
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
class GroupMembersFunctionExecution extends AbstractFunctionExecution {
private final String[] groups;
/**
* Constructs an instance of the GroupMembersFunctionExecution class to execute a data independent Function
* on all members from each of the specified groups.
* Constructs a new instance of {@link GroupMembersFunctionExecution} initialized to execute a data independent
* {@link Function} on all members from each of the specified {@link String groups}.
*
* @param groups the list of GemFire Groups indicating the members on which to execute the data independent Function.
* @param groups array of {@link String groups} indicating the members on which to execute
* the data independent {@link Function}.
* @throws IllegalArgumentException if {@link String groups} is {@literal null} or empty.
*/
public GroupMembersFunctionExecution(final String... groups) {
Assert.notEmpty(groups, "'groups' cannot be null or empty.");
public GroupMembersFunctionExecution(String... groups) {
Assert.notEmpty(groups, "Groups must not be null or empty");
this.groups = groups;
}
protected String[] getGroups() {
return this.groups;
}
/**
* Executes the data independent Function on all members from each of the specified groups.
*
@@ -46,7 +59,6 @@ class GroupMembersFunctionExecution extends AbstractFunctionExecution {
*/
@Override
protected Execution getExecution() {
return FunctionService.onMembers(this.groups);
return FunctionService.onMembers(getGroups());
}
}

View File

@@ -10,57 +10,42 @@
* 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;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.FunctionService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Creates a GemFire {@link Execution} using {code}FunctionService.onServer(Pool pool){code}
* @author David Turanski
* Constructs an {@link Execution} using {@link FunctionService#onServer(Pool)}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.FunctionService
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
class PoolServerFunctionExecution extends AbstractFunctionExecution implements InitializingBean {
class PoolServerFunctionExecution extends AbstractFunctionExecution {
private final Pool pool;
private Pool pool;
private String poolname;
PoolServerFunctionExecution(Pool pool) {
Assert.notNull(pool, "Pool must not be null");
/**
* @param pool the {@link Pool}
*/
public PoolServerFunctionExecution(Pool pool) {
super();
Assert.notNull(pool, "pool cannot be null");
this.pool = pool;
}
public PoolServerFunctionExecution(String poolname) {
super();
Assert.notNull(poolname, "pool name cannot be null");
this.poolname = poolname;
protected Pool getPool() {
return this.pool;
}
@Override
protected Execution getExecution() {
return FunctionService.onServer(this.pool);
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
this.pool = PoolManager.find(poolname);
Assert.notNull(pool," pool " + poolname+ " does not exist");
return FunctionService.onServer(getPool());
}
}

View File

@@ -10,6 +10,7 @@
* 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;
import org.apache.geode.cache.client.Pool;
@@ -18,26 +19,32 @@ import org.apache.geode.cache.execute.FunctionService;
import org.springframework.util.Assert;
/**
* Creates a GemFire {@link Execution} using {code}FunctionService.onServers(Pool pool){code}
* @author David Turanski
* Constructs an {@link Execution} using {@link FunctionService#onServers(Pool)}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.FunctionService
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
class PoolServersFunctionExecution extends AbstractFunctionExecution {
private final Pool pool;
/**
* @param pool the {@link Pool}
*/
public PoolServersFunctionExecution(Pool pool ) {
super();
Assert.notNull(pool, "pool cannot be null");
PoolServersFunctionExecution(Pool pool) {
Assert.notNull(pool, "Pool must not be null");
this.pool = pool;
}
protected Pool getPool() {
return pool;
}
@Override
protected Execution getExecution() {
return FunctionService.onServers(this.pool);
return FunctionService.onServers(getPool());
}
}

View File

@@ -10,30 +10,41 @@
* 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;
import org.apache.geode.cache.RegionService;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.FunctionService;
import org.springframework.util.Assert;
import org.apache.shiro.util.Assert;
/**
* Creates a GemFire {@link Execution} using {code}FunctionService.onServer(RegionService regionService){code}
* @author David Turanski
* Constructs an {@link Execution} using {@link FunctionService#onServer(RegionService)}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.RegionService
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.FunctionService
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
class ServerFunctionExecution extends AbstractFunctionExecution {
private final RegionService regionService;
public ServerFunctionExecution(RegionService regionService) {
ServerFunctionExecution(RegionService regionService) {
Assert.notNull(regionService, "RegionService must not be null");
this.regionService = regionService;
}
protected RegionService getRegionService() {
return regionService;
}
@Override
protected Execution getExecution() {
return FunctionService.onServer(this.regionService);
return FunctionService.onServer(getRegionService());
}
}

View File

@@ -10,6 +10,7 @@
* 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;
import org.apache.geode.cache.RegionService;
@@ -18,29 +19,32 @@ import org.apache.geode.cache.execute.FunctionService;
import org.springframework.util.Assert;
/**
* Creates a GemFire {@link Execution} using {code}FunctionService.onServers(RegionService regionService){code}
* @author David Turanski
* Constructs an {@link Execution} using {@link FunctionService#onServers(RegionService)}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.RegionService
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.FunctionService
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
class ServersFunctionExecution extends AbstractFunctionExecution {
private final RegionService regionService;
/**
*
* @param regionService e.g., Cache,Client, or GemFireCache
* @param function
* @param args
*/
public ServersFunctionExecution(RegionService regionService ) {
super();
Assert.notNull(regionService,"regionService cannot be null");
ServersFunctionExecution(RegionService regionService) {
Assert.notNull(regionService, "RegionService must not be null");
this.regionService = regionService;
}
protected RegionService getRegionService() {
return regionService;
}
@Override
protected Execution getExecution() {
return FunctionService.onServers(this.regionService);
return FunctionService.onServers(getRegionService());
}
}

View File

@@ -105,6 +105,14 @@ public abstract class SpringUtils {
return (obj1 != null && obj1.equals(obj2));
}
public static String nullSafeName(Class<?> type) {
return type != null ? type.getName() : null;
}
public static String nullSafeSimpleName(Class<?> type) {
return type != null ? type.getSimpleName() : null;
}
public static <T> T safeGetValue(Supplier<T> valueSupplier) {
return safeGetValue(valueSupplier, (T) null);
}

View File

@@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -82,8 +83,8 @@ public class FunctionGemfireAdminTemplateUnitTests {
this.template = spy(new FunctionGemfireAdminTemplate(this.mockClientCache));
when(this.template.newGemfireFunctionOperations(any(ClientCache.class)))
.thenReturn(this.mockFunctionOperations);
doReturn(this.mockFunctionOperations).when(this.template)
.newGemfireFunctionOperations(any(ClientCache.class));
when(this.mockIndex.getName()).thenReturn("MockIndex");
when(this.mockRegion.getName()).thenReturn("MockRegion");

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2018 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 org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
/**
* Unit tests for {@link MemberBasedFunctionExecutionBeanDefinitionBuilder}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.function.config.MemberBasedFunctionExecutionBeanDefinitionBuilder
* @since 1.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class MemberBasedFunctionExecutionBeanDefinitionBuilderUnitTests {
@Mock
private FunctionExecutionConfiguration mockFunctionExecutionConfiguration;
private MemberBasedFunctionExecutionBeanDefinitionBuilder beanDefinitionBuilder;
@Before
public void setup() {
this.beanDefinitionBuilder =
new TestMemberBasedFunctionExecutionBeanDefinitionBuilder(this.mockFunctionExecutionConfiguration);
}
@Test
public void getGemfireFunctionOperationsBeanDefinitionBuilderIsSuccessful() {
when(this.mockFunctionExecutionConfiguration.getAttribute(eq("groups")))
.thenReturn(" TestGroupOne, TestGroupTwo ");
BeanDefinitionBuilder builder =
this.beanDefinitionBuilder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
assertThat(builder).isNotNull();
BeanDefinition beanDefinition = builder.getRawBeanDefinition();
assertThat(beanDefinition).isNotNull();
assertThat(beanDefinition.getBeanClassName()).isEqualTo(Object.class.getName());
assertThat(beanDefinition.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
ConstructorArgumentValues.ValueHolder constructorArgumentValue =
beanDefinition.getConstructorArgumentValues().getArgumentValue(0, String[].class);
assertThat(constructorArgumentValue).isNotNull();
assertThat((String[]) constructorArgumentValue.getValue()).containsExactly("TestGroupOne", "TestGroupTwo");
verify(this.mockFunctionExecutionConfiguration, times(1))
.getAttribute(eq("groups"));
}
private static final class TestMemberBasedFunctionExecutionBeanDefinitionBuilder
extends MemberBasedFunctionExecutionBeanDefinitionBuilder {
private TestMemberBasedFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) {
super(configuration);
}
@Override
protected Class<?> getGemfireOperationsClass() {
return Object.class;
}
}
}

View File

@@ -16,40 +16,30 @@
package org.springframework.data.gemfire.function.config;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
/**
* The ServerBasedExecutionBeanDefinitionBuilderTest class is test suite of test cases testing the contract
* and functionality of the ServerBasedExecutionBeanDefinitionBuilder class.
* Unit tests for {@link ServerBasedFunctionExecutionBeanDefinitionBuilder}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.function.config.ServerBasedExecutionBeanDefinitionBuilder
* @see org.springframework.data.gemfire.function.config.ServerBasedFunctionExecutionBeanDefinitionBuilder
* @since 1.7.0
*/
public class ServerBasedExecutionBeanDefinitionBuilderTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
public class ServerBasedFunctionExecutionBeanDefinitionBuilderUnitTests {
@Test
@SuppressWarnings("unchecked")
@@ -59,11 +49,11 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration");
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn(null);
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" ");
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("");
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class);
ServerBasedExecutionBeanDefinitionBuilder builder =
new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
ServerBasedFunctionExecutionBeanDefinitionBuilder builder =
new ServerBasedFunctionExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
@Override
protected Class<?> getGemfireFunctionOperationsClass() {
@@ -71,21 +61,25 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
}
};
BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
BeanDefinitionBuilder beanDefinitionBuilder =
builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
assertThat(beanDefinitionBuilder, is(notNullValue()));
assertThat(beanDefinitionBuilder).isNotNull();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
assertThat(beanDefinition, is(notNullValue()));
assertThat(beanDefinition.getBeanClass(), is(equalTo(Object.class)));
assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues()
.getArgumentValue(0, RuntimeBeanReference.class).getValue()),
containsString(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
assertThat(beanDefinition).isNotNull();
assertThat(beanDefinition.getBeanClass()).isEqualTo(Object.class);
ConstructorArgumentValues.ValueHolder constructorArgumentValue =
beanDefinition.getConstructorArgumentValues().getArgumentValue(0, RuntimeBeanReference.class);
assertThat(constructorArgumentValue).isNotNull();
assertThat(((RuntimeBeanReference) constructorArgumentValue.getValue()).getBeanName()).isEqualTo("gemfireCache");
assertThat(beanDefinition.getPropertyValues().getPropertyValue("pool")).isNull();
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
}
@Test
@@ -96,11 +90,10 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration");
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn("TestCache");
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" ");
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class);
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" ");
ServerBasedExecutionBeanDefinitionBuilder builder =
new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
ServerBasedFunctionExecutionBeanDefinitionBuilder builder =
new ServerBasedFunctionExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
@Override
protected Class<?> getGemfireFunctionOperationsClass() {
@@ -108,20 +101,25 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
}
};
BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
BeanDefinitionBuilder beanDefinitionBuilder =
builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
assertThat(beanDefinitionBuilder, is(notNullValue()));
assertThat(beanDefinitionBuilder).isNotNull();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
assertThat(beanDefinition, is(notNullValue()));
assertThat(beanDefinition.getBeanClass(), is(equalTo(Object.class)));
assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues()
.getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString("TestCache"));
assertThat(beanDefinition).isNotNull();
assertThat(beanDefinition.getBeanClass()).isEqualTo(Object.class);
ConstructorArgumentValues.ValueHolder constructorArgumentValue =
beanDefinition.getConstructorArgumentValues().getArgumentValue(0, RuntimeBeanReference.class);
assertThat(constructorArgumentValue).isNotNull();
assertThat(((RuntimeBeanReference) constructorArgumentValue.getValue()).getBeanName()).isEqualTo("TestCache");
assertThat(beanDefinition.getPropertyValues().getPropertyValue("pool")).isNull();
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
}
@Test
@@ -133,10 +131,9 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn(null);
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("TestPool");
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class);
ServerBasedExecutionBeanDefinitionBuilder builder =
new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
ServerBasedFunctionExecutionBeanDefinitionBuilder builder =
new ServerBasedFunctionExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
@Override
protected Class<?> getGemfireFunctionOperationsClass() {
@@ -144,20 +141,29 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
}
};
BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
BeanDefinitionBuilder beanDefinitionBuilder =
builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
assertThat(beanDefinitionBuilder, is(notNullValue()));
assertThat(beanDefinitionBuilder).isNotNull();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
assertThat(beanDefinition, is(notNullValue()));
assertThat(beanDefinition.getBeanClass(), is(equalTo(Object.class)));
assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues()
.getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString("TestPool"));
assertThat(beanDefinition).isNotNull();
assertThat(beanDefinition.getBeanClass()).isEqualTo(Object.class);
ConstructorArgumentValues.ValueHolder constructorArgumentValue =
beanDefinition.getConstructorArgumentValues().getArgumentValue(0, RuntimeBeanReference.class);
assertThat(constructorArgumentValue).isNotNull();
assertThat(((RuntimeBeanReference) constructorArgumentValue.getValue()).getBeanName()).isEqualTo("gemfireCache");
PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue("pool");
assertThat(propertyValue).isNotNull();
assertThat(((RuntimeBeanReference) propertyValue.getValue()).getBeanName()).isEqualTo("TestPool");
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
}
@Test
@@ -169,10 +175,9 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn("TestCache");
when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("TestPool");
when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class);
ServerBasedExecutionBeanDefinitionBuilder builder =
new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
ServerBasedFunctionExecutionBeanDefinitionBuilder builder =
new ServerBasedFunctionExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) {
@Override
protected Class<?> getGemfireFunctionOperationsClass() {
@@ -180,15 +185,29 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest {
}
};
expectedException.expect(IllegalStateException.class);
expectedException.expectCause(is(nullValue(Throwable.class)));
expectedException.expectMessage(is(equalTo("Invalid configuration for interface [java.lang.Object];"
+ " cannot specify both 'pool' and 'cache'")));
builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
BeanDefinitionBuilder beanDefinitionBuilder =
builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null);
assertThat(beanDefinitionBuilder).isNotNull();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
assertThat(beanDefinition).isNotNull();
assertThat(beanDefinition.getBeanClass()).isEqualTo(Object.class);
ConstructorArgumentValues.ValueHolder constructorArgumentValue =
beanDefinition.getConstructorArgumentValues().getArgumentValue(0, RuntimeBeanReference.class);
assertThat(constructorArgumentValue).isNotNull();
assertThat(((RuntimeBeanReference) constructorArgumentValue.getValue()).getBeanName()).isEqualTo("TestCache");
PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue("pool");
assertThat(propertyValue).isNotNull();
assertThat(((RuntimeBeanReference) propertyValue.getValue()).getBeanName()).isEqualTo("TestPool");
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache"));
verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool"));
verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface();
}
}

View File

@@ -1,26 +1,20 @@
/*
* 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.execution;
/**
* @author David Turanski
*
*/
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,81 +28,92 @@ import org.aopalliance.intercept.MethodInvocation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.gemfire.function.annotation.FunctionId;
/**
*
* @author David Turanski
*
*/
public class GemfireFunctionProxyFactoryBeanTests {
/**
* Unit tests for {@link GemfireFunctionProxyFactoryBean}.
*
* @author David Turanski
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.aopalliance.intercept.MethodInvocation
* @see org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean
*/
public class GemfireFunctionProxyFactoryBeanUnitTests {
private GemfireFunctionOperations functionOperations;
@Before
public void setUp() {
functionOperations = mock(GemfireFunctionOperations.class);
this.functionOperations = mock(GemfireFunctionOperations.class);
}
@Test
public void testInvokeAndExtractWithAnnotatedFunctionId() throws Throwable {
GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class,functionOperations);
MethodInvocation invocation = new TestInvocation(IFoo.class).withMethodNameAndArgTypes("oneArg",String.class);
int results = 1;
when(functionOperations.executeAndExtract("oneArg",invocation.getArguments())).thenReturn(results);
public void invoke() throws Throwable {
MethodInvocation invocation = new TestMethodInvocation(IFoo.class)
.withMethodNameAndArgTypes("collections",List.class);
when(this.functionOperations.executeAndExtract("collections",invocation.getArguments()))
.thenReturn(Arrays.asList(1, 2, 3));
GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class, this.functionOperations);
Object result = proxy.invoke(invocation);
verify(functionOperations).executeAndExtract("oneArg",invocation.getArguments());
assertTrue(result.getClass().getName(), result instanceof Integer);
assertEquals(1,result);
assertThat(result).isInstanceOf(List.class);
assertThat((List) result).hasSize(3);
verify(this.functionOperations, times(1))
.executeAndExtract("collections",invocation.getArguments());
}
@SuppressWarnings({ "rawtypes" })
@Test
public void testInvoke() throws Throwable {
GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class, functionOperations);
MethodInvocation invocation = new TestInvocation(IFoo.class).withMethodNameAndArgTypes("collections",List.class);
List results = Arrays.asList(new Integer[]{1,2,3});
when(functionOperations.executeAndExtract("collections",invocation.getArguments())).thenReturn(results);
public void invokeAndExtractWithAnnotatedFunctionId() throws Throwable {
MethodInvocation invocation = new TestMethodInvocation(IFoo.class)
.withMethodNameAndArgTypes("oneArg", String.class);
when(this.functionOperations.executeAndExtract("oneArg",invocation.getArguments())).thenReturn(1);
GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class, this.functionOperations);
Object result = proxy.invoke(invocation);
verify(functionOperations).executeAndExtract("collections",invocation.getArguments()); ;
assertTrue(result instanceof List);
assertEquals(3,((List<?>)result).size());
assertThat(result).describedAs(result.getClass().getName()).isInstanceOf(Integer.class);
assertThat(result).isEqualTo(1);
verify(this.functionOperations, times(1))
.executeAndExtract("oneArg", invocation.getArguments());
}
static class TestInvocation implements MethodInvocation {
@SuppressWarnings("unused")
private static class TestMethodInvocation implements MethodInvocation {
private Class<?> type;
private Class<?>[] argTypes;
private Class<?> clazz;
private String methodName;
private Object[] arguments;
public TestInvocation(Class<?> clazz) {
this.clazz = clazz;
private String methodName;
public TestMethodInvocation(Class<?> type) {
this.type = type;
}
public TestInvocation withArguments(Object ...arguments){
public TestMethodInvocation withArguments(Object ...arguments){
this.arguments = arguments;
return this;
}
public TestInvocation withMethodNameAndArgTypes(String methodName,Class<?>... argTypes) {
public TestMethodInvocation withMethodNameAndArgTypes(String methodName,Class<?>... argTypes) {
this.methodName = methodName;
this.argTypes = argTypes;
return this;
}
@@ -117,7 +122,6 @@ public class GemfireFunctionProxyFactoryBeanTests {
*/
@Override
public Object[] getArguments() {
// TODO Auto-generated method stub
return this.arguments;
}
@@ -126,7 +130,6 @@ public class GemfireFunctionProxyFactoryBeanTests {
*/
@Override
public Object proceed() throws Throwable {
// TODO Auto-generated method stub
return null;
}
@@ -135,7 +138,6 @@ public class GemfireFunctionProxyFactoryBeanTests {
*/
@Override
public Object getThis() {
// TODO Auto-generated method stub
return null;
}
@@ -144,7 +146,6 @@ public class GemfireFunctionProxyFactoryBeanTests {
*/
@Override
public AccessibleObject getStaticPart() {
// TODO Auto-generated method stub
return null;
}
@@ -153,35 +154,27 @@ public class GemfireFunctionProxyFactoryBeanTests {
*/
@Override
public Method getMethod() {
Method method = null;
try {
method = clazz.getMethod(methodName, argTypes);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return this.type.getMethod(methodName, argTypes);
}
catch (NoSuchMethodException | SecurityException cause) {
return null;
}
return method;
}
}
@SuppressWarnings("unused")
public interface IFoo {
@FunctionId("oneArg")
public abstract Integer oneArg(String key);
Integer oneArg(String key);
public abstract Integer twoArg(String akey, String bkey);
Integer twoArg(String akey, String bkey);
public abstract List<Integer> collections(List<Integer> args);
List<Integer> collections(List<Integer> args);
public abstract Map<String, Integer> getMapWithNoArgs();
Map<String, Integer> getMapWithNoArgs();
}
}