DATAGEODE-295 - Polish.

Resolves gh-37.
This commit is contained in:
John Blum
2020-02-27 21:45:51 -08:00
parent ae69760bf6
commit 513afaa3c9
27 changed files with 745 additions and 412 deletions

View File

@@ -759,7 +759,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport<GemFireCache>
* @see #getCacheXmlFile()
*/
private boolean isCacheXmlAvailable() {
return SpringUtils.safeGetValue(() -> getCacheXml() != null, false);
return getCacheXml() != null;
}
/**

View File

@@ -23,7 +23,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import org.apache.geode.GemFireCheckedException;
import org.apache.geode.GemFireException;
@@ -426,7 +425,7 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation
if (RegionUtils.isLocal(region)) {
Supplier<Boolean> hasServerProxyMethod = () ->
SpringUtils.ValueReturningThrowableOperation<Boolean> hasServerProxyMethod = () ->
Optional.ofNullable(ReflectionUtils.findMethod(region.getClass(), "hasServerProxy"))
.map(method -> ReflectionUtils.invokeMethod(method, region))
.map(Boolean.FALSE::equals)

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2020 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
*
* https://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;
import org.apache.geode.cache.execute.FunctionException;
/**
* A {@link FunctionException} indicating a timeout during execution.
*
* @author John Blum
* @see org.apache.geode.cache.execute.FunctionException
* @since 2.3.0
*/
@SuppressWarnings("unused")
public class ExecutionTimeoutFunctionException extends FunctionException {
public ExecutionTimeoutFunctionException() { }
public ExecutionTimeoutFunctionException(String message) {
super(message);
}
public ExecutionTimeoutFunctionException(Throwable cause) {
super(cause);
}
public ExecutionTimeoutFunctionException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2020 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
*
* https://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;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionException;
/**
* An {@link FunctionException} indicating a {@link Function} {@link Execution} {@link RuntimeException}
* that has not be categorized, or identified by the framework.
*
* This {@link RuntimeException} was inspired by the {@link org.springframework.dao.UncategorizedDataAccessException}.
*
* @author John Blum
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.FunctionException
* @since 2.3.0
*/
@SuppressWarnings("unused")
public class UncategorizedFunctionException extends FunctionException {
public UncategorizedFunctionException() {
super(null, null);
}
public UncategorizedFunctionException(String message) {
super(message, null);
}
public UncategorizedFunctionException(Throwable cause) {
super(null, cause);
}
public UncategorizedFunctionException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2020 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
@@ -14,6 +14,7 @@ package org.springframework.data.gemfire.function.execution;
import java.util.Collections;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -23,167 +24,323 @@ import org.apache.geode.cache.execute.FunctionException;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultCollector;
import org.springframework.data.gemfire.function.ExecutionTimeoutFunctionException;
import org.springframework.data.gemfire.function.UncategorizedFunctionException;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.data.gemfire.util.SpringUtils.ValueReturningThrowableOperation;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
/**
* Base class for * Creating a GemFire {@link Execution} using {@link FunctionService}. Protected setters support
* method chaining.
* Abstract base class for creating a {@link Function} {@link Execution} using the {@link FunctionService}.
*
* @author David Turanski
* @author John Blum
* @author Patrick Johnson
* @see java.util.concurrent.TimeUnit
* @see org.apache.geode.cache.execute.Execution
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.FunctionService
* @see org.apache.geode.cache.execute.ResultCollector
*/
@SuppressWarnings("unused")
abstract class AbstractFunctionExecution {
private final static String NO_RESULT_MESSAGE = "Cannot return any result as the Function#hasResult() is false";
private static final boolean DEFAULT_RETURN_RESULT = true;
private static final String FUNCTION_EXECUTION_TIMEOUT_ERROR_MESSAGE =
"Failed to collect Function [%1$s] results in the configured timeout [%2$d ms]";
private static final String NO_RESULT_ERROR_MESSAGE =
"Cannot return any result as the Function#hasResult() is false";
private long timeout;
@SuppressWarnings("rawtypes")
private Function function;
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private Object[] args;
private Object[] arguments;
private volatile ResultCollector<?, ?> resultCollector;
private String functionId;
public AbstractFunctionExecution(Function function, Object... args) {
@SuppressWarnings("rawtypes")
public AbstractFunctionExecution(Function function, Object... arguments) {
Assert.notNull(function, "Function cannot be null");
this.function = function;
this.functionId = function.getId();
this.args = args;
this.arguments = arguments;
}
public AbstractFunctionExecution(String functionId, Object... args) {
public AbstractFunctionExecution(String functionId, Object... arguments) {
Assert.hasText(functionId, "Function ID must not be null or empty");
this.function = null;
this.functionId = functionId;
this.args = args;
this.arguments = arguments;
}
AbstractFunctionExecution() { }
Object[] getArgs() {
return this.args;
protected Object[] getArguments() {
return this.arguments;
}
ResultCollector<?, ?> getCollector() {
return this.resultCollector;
}
@SuppressWarnings("rawtypes")
protected abstract Execution getExecution();
Function getFunction() {
@SuppressWarnings("rawtypes")
protected Function getFunction() {
return this.function;
}
String getFunctionId() {
protected String getFunctionId() {
return this.functionId;
}
long getTimeout() {
protected Set<?> getKeys() {
return null;
}
protected Logger getLogger() {
return this.logger;
}
protected ResultCollector<?, ?> getResultCollector() {
return this.resultCollector;
}
protected long getTimeout() {
return this.timeout;
}
<T> Iterable<T> execute() {
return execute(true);
String resolveFunctionIdentifier() {
return Optional.ofNullable(getFunction())
.map(ObjectUtils::nullSafeClassName)
.orElseGet(() -> getFunctionId());
}
@SuppressWarnings("unchecked")
/**
* Executes the configured {@link Function}.
*
* @param <T> {@link Class type} of the result.
* @return an {@link Iterable} containing the results from the {@link Function} {@link Execution}.
* @see java.lang.Iterable
* @see #execute(Boolean)
*/
<T> Iterable<T> execute() {
return execute(DEFAULT_RETURN_RESULT);
}
/**
* Executes the configured {@link Function}.
*
* @param <T> {@link Class type} of the result.
* @param returnResult boolean value indicating whether the {@link Function} should return a result
* from the {@link Execution}.
* @return an {@link Iterable} containing the results from the {@link Function} {@link Execution}.
* @see java.lang.Iterable
* @see #getExecution()
* @see #getFunction()
* @see #getFunctionId()
* @see #getTimeout()
* @see #prepare(Execution)
*/
@SuppressWarnings({ "rawtypes" })
<T> Iterable<T> execute(Boolean returnResult) {
Execution execution = getExecution();
Execution execution = prepare(getExecution());
execution = execution.setArguments(getArgs());
execution = getCollector() != null ? execution.withCollector(getCollector()) : execution;
execution = getKeys() != null ? execution.withFilter(getKeys()) : execution;
Function function = getFunction();
ResultCollector<?, ?> resultCollector;
ResultCollector<?, ?> resultCollector = function != null
? execution.execute(function)
: execution.execute(getFunctionId());
if (isRegisteredFunction()) {
resultCollector = execution.execute(this.functionId);
}
else {
resultCollector = execution.execute(this.function);
if (!this.function.hasResult()) {
return null;
}
}
if (!returnResult) {
if (hasNoResult(returnResult, function, resultCollector)) {
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("Using ResultsCollector " + resultCollector.getClass().getName());
}
long timeout = getTimeout();
logDebug("Configured timeout is [{} ms]", timeout);
logDebug("Using ResultCollector [{}]", ObjectUtils.nullSafeClassName(resultCollector));
Iterable<T> results = null;
try {
if (this.timeout > 0) {
try {
results = (Iterable<T>) resultCollector.getResult(this.timeout, TimeUnit.MILLISECONDS);
}
catch (FunctionException | InterruptedException cause) {
throw new RuntimeException(cause);
}
}
else {
if(resultCollector.getResult() instanceof Iterable) {
results = (Iterable<T>) resultCollector.getResult();
} else {
results = (Iterable<T>) Collections.singleton(resultCollector.getResult());
}
}
return replaceSingletonNullCollectionWithEmptyList(results);
Object result = timeout > 0
? SpringUtils.<T>safeGetValue(getResultWithTimeoutThrowableOperation(resultCollector, timeout),
newFunctionAndInterruptedExceptionHandler(timeout))
: resultCollector.getResult();
results = processResult(result);
return results;
}
catch (FunctionException cause) {
// TODO Come up with a better way to determine that the function should not return a result;
if (!cause.getMessage().equals(NO_RESULT_MESSAGE)) {
// TODO: Use a more reliable way to determine that the Function does not return a result!
// This only applies to Functions registered by ID!
if (!cause.getMessage().contains(NO_RESULT_ERROR_MESSAGE)) {
throw cause;
}
return results;
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Execution prepare(Execution execution) {
execution = execution.setArguments(getArguments());
execution = getResultCollector() != null ? execution.withCollector(getResultCollector()) : execution;
execution = getKeys() != null ? execution.withFilter(getKeys()) : execution;
return execution;
}
@SuppressWarnings("rawtypes")
private boolean hasResult(boolean returnResult, Function function, ResultCollector resultCollector) {
return returnResult && (function == null || function.hasResult());
}
@SuppressWarnings("rawtypes")
private boolean hasNoResult(boolean returnResult, Function function, ResultCollector resultCollector) {
return !hasResult(returnResult, function, resultCollector);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private <T> ValueReturningThrowableOperation<T> getResultWithTimeoutThrowableOperation(
ResultCollector resultCollector, long timeout) {
return () -> (T) resultCollector.getResult(timeout, TimeUnit.MILLISECONDS);
}
private <T> java.util.function.Function<Throwable, T> newFunctionAndInterruptedExceptionHandler(long timeout) {
return cause -> {
if (cause instanceof FunctionException) {
throw (FunctionException) cause;
}
else if (cause instanceof InterruptedException) {
String message =
String.format(FUNCTION_EXECUTION_TIMEOUT_ERROR_MESSAGE, resolveFunctionIdentifier(), timeout);
throw new ExecutionTimeoutFunctionException(message, cause);
}
throw new UncategorizedFunctionException(cause);
};
}
private <T> Iterable<T> processResult(Object result) {
return replaceSingleNullElementIterableWithEmptyIterable(throwOnExceptionOrReturn(toIterable(
throwOnExceptionOrReturn(result))));
}
private <T> Iterable<T> replaceSingleNullElementIterableWithEmptyIterable(Iterable<T> results) {
if (results != null) {
Iterator<T> it = results.iterator();
if (!it.hasNext()) {
return results;
}
if (it.next() == null && !it.hasNext()) {
return Collections::emptyIterator;
}
}
return results;
}
private <T> Iterable<T> throwOnExceptionOrReturn(Iterable<T> result) {
Iterator<T> resultIterator = result.iterator();
if (resultIterator.hasNext()) {
throwOnExceptionOrReturn(resultIterator.next());
}
return result;
}
@SuppressWarnings("unchecked")
private <T> Iterable<T> toIterable(Object result) {
return result instanceof Iterable
? (Iterable<T>) result
: (Iterable<T>) Collections.singleton(result);
}
/**
* Executes the configured {@link Function} and extracts the result as a single value.
*
* @param <T> {@link Class type} of the result.
* @return the result of the {@link Function} {@link Execution} as a single value.
* @see #execute()
*/
<T> T executeAndExtract() {
Iterable<T> results = execute();
if (results == null || !results.iterator().hasNext()) {
if (isEmpty(results)) {
return null;
}
Object result = results.iterator().next();
T result = results.iterator().next();
if (result instanceof Throwable) {
throw new FunctionException(String.format("Execution of Function %s failed",
(this.function != null ? this.function.getClass().getName()
: String.format("with ID [%s]", this.functionId))), (Throwable) result);
}
return (T) result;
return throwOnExceptionOrReturn(result);
}
protected abstract Execution getExecution();
private boolean isEmpty(Iterable<?> iterable) {
return iterable == null || !iterable.iterator().hasNext();
}
private <T> T throwOnExceptionOrReturn(T result) {
if (result instanceof Throwable) {
Function<?> function = getFunction();
String message = String.format("Execution of Function [%s] failed", function != null
? function.getClass().getName()
: String.format("with ID [%s]", getFunctionId()));
throw new FunctionException(message, (Throwable) result);
}
return result;
}
@Deprecated
protected AbstractFunctionExecution setArgs(Object... args) {
this.args = args;
return setArguments(args);
}
protected AbstractFunctionExecution setArguments(Object... arguments) {
this.arguments = arguments;
return this;
}
@SuppressWarnings("rawtypes")
protected AbstractFunctionExecution setFunction(Function function) {
this.function = function;
return this;
@@ -204,29 +361,12 @@ abstract class AbstractFunctionExecution {
return this;
}
protected Set<?> getKeys() {
return null;
}
protected void logDebug(String message, Object... arguments) {
private boolean isRegisteredFunction() {
return this.function == null;
}
Logger logger = getLogger();
private <T> Iterable<T> replaceSingletonNullCollectionWithEmptyList(Iterable<T> results) {
if (results != null) {
Iterator<T> it = results.iterator();
if (!it.hasNext()) {
return results;
}
if (it.next() == null && !it.hasNext()) {
return Collections.emptyList();
}
if (logger.isDebugEnabled()) {
logger.debug(message, arguments);
}
return results;
}
}

View File

@@ -10,7 +10,6 @@
* 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.Function;
@@ -19,47 +18,77 @@ import org.apache.geode.cache.execute.ResultCollector;
import org.springframework.beans.factory.InitializingBean;
/**
* The base class for {@link Function} templates used to invoke Apache Geode/Pivotal GemFire {@link Function Functions}.
* Abstract base class for all {@link Function} templates, containing operations common to invoking Apache Geode
* or Pivotal GemFire {@link Function Functions}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.execute.Execution
* @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
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
*/
abstract class AbstractFunctionTemplate implements GemfireFunctionOperations, InitializingBean {
protected long timeout;
private volatile long timeout;
protected volatile ResultCollector<?, ?> resultCollector;
private volatile ResultCollector<?, ?> resultCollector;
@Override
public void afterPropertiesSet() throws Exception { }
@Override
@SuppressWarnings("rawtypes")
public <T> Iterable<T> execute(Function function, Object... args) {
return execute(getFunctionExecution().setArgs(args).setFunction(function));
AbstractFunctionExecution functionExecution = getFunctionExecution()
.setArguments(args)
.setFunction(function);
return execute(functionExecution);
}
@Override
@SuppressWarnings("rawtypes")
public <T> T executeAndExtract(Function function, Object... args) {
return executeAndExtract(getFunctionExecution().setArgs(args).setFunction(function));
AbstractFunctionExecution functionExecution = getFunctionExecution()
.setArguments(args)
.setFunction(function);
return executeAndExtract(functionExecution);
}
@Override
public <T> Iterable<T> execute(String functionId, Object... args) {
return execute(getFunctionExecution().setArgs(args).setFunctionId(functionId));
AbstractFunctionExecution functionExecution = getFunctionExecution()
.setArguments(args)
.setFunctionId(functionId);
return execute(functionExecution);
}
@Override
public <T> T executeAndExtract(String functionId, Object... args) {
return executeAndExtract(getFunctionExecution().setArgs(args).setFunctionId(functionId));
AbstractFunctionExecution functionExecution = getFunctionExecution()
.setArguments(args)
.setFunctionId(functionId);
return executeAndExtract(functionExecution);
}
@Override
public void executeWithNoResult(String functionId, Object... args) {
execute(getFunctionExecution().setArgs(args).setFunctionId(functionId), false);
AbstractFunctionExecution functionExecution = getFunctionExecution()
.setArguments(args)
.setFunctionId(functionId);
execute(functionExecution, false);
}
@Override
@@ -67,18 +96,27 @@ abstract class AbstractFunctionTemplate implements GemfireFunctionOperations, In
return callback.doInGemfire(getFunctionExecution().getExecution());
}
protected <T> Iterable<T> execute(AbstractFunctionExecution execution) {
return execution.setTimeout(timeout).setResultCollector(resultCollector).execute();
protected <T> Iterable<T> execute(AbstractFunctionExecution functionExecution) {
return prepare(functionExecution).execute();
}
protected <T> Iterable<T> execute(AbstractFunctionExecution execution, boolean returnResult) {
return execution.setTimeout(timeout).setResultCollector(resultCollector).execute(returnResult);
protected <T> Iterable<T> execute(AbstractFunctionExecution functionExecution, boolean returnResult) {
return prepare(functionExecution).execute(returnResult);
}
protected <T> T executeAndExtract(AbstractFunctionExecution execution) {
return execution.setTimeout(timeout).setResultCollector(resultCollector).executeAndExtract();
protected <T> T executeAndExtract(AbstractFunctionExecution functionExecution) {
return prepare(functionExecution).executeAndExtract();
}
AbstractFunctionExecution prepare(AbstractFunctionExecution functionExecution) {
return functionExecution
.setResultCollector(getResultCollector())
.setTimeout(getTimeout());
}
protected abstract AbstractFunctionExecution getFunctionExecution();
public void setResultCollector(ResultCollector<?,?> resultCollector) {
this.resultCollector = resultCollector;
}
@@ -91,6 +129,7 @@ abstract class AbstractFunctionTemplate implements GemfireFunctionOperations, In
this.timeout = timeout;
}
protected abstract AbstractFunctionExecution getFunctionExecution();
public long getTimeout() {
return this.timeout;
}
}

View File

@@ -18,7 +18,6 @@ import java.util.stream.StreamSupport;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.data.gemfire.function.annotation.OnServers;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -26,10 +25,6 @@ import org.springframework.util.ClassUtils;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
<<<<<<<HEAD
=======
>>>>>>>DATAGEODE-295-Functions return results from all servers.
/**
* A Proxy {@link FactoryBean} for all non-Region Function Execution interfaces.
*
@@ -105,7 +100,7 @@ public class GemfireFunctionProxyFactoryBean extends AbstractFactoryBeanSupport<
return String.format("Function Proxy for interface [%s]", getFunctionExecutionInterface().getName());
}
logDebug("Invoking method {}", invocation.getMethod().getName());
logDebug("Invoking method [{}]", invocation.getMethod().getName());
Object result = invokeFunction(invocation.getMethod(), invocation.getArguments());
@@ -114,17 +109,19 @@ public class GemfireFunctionProxyFactoryBean extends AbstractFactoryBeanSupport<
protected Object invokeFunction(Method method, Object[] args) {
GemfireFunctionOperations template = getGemfireFunctionOperations();
String functionId = getFunctionExecutionMethodMetadata()
.getMethodMetadata(method)
.getFunctionId();
return method.getDeclaringClass().isAnnotationPresent(OnServers.class)
? template.execute(getFunctionExecutionMethodMetadata().getMethodMetadata(method).getFunctionId(), args)
: template.executeAndExtract(getFunctionExecutionMethodMetadata().getMethodMetadata(method).getFunctionId(), args);
return getGemfireFunctionOperations().execute(functionId, args);
}
protected Object resolveResult(MethodInvocation invocation, Object result) {
// TODO: This conditional logic needs more work! For instance, this conditional logic fails if the result
// is a List, but the Function (Execution method) return type is a Set.
// TODO: The conditional logic needs more work!
// For example, this conditional logic will fail if the result is a List but the Function (Execution method)
// return type is a Set.
// TODO: Apply Spring Converters here???
return isIterable(result) && isNotInstanceOfFunctionReturnType(invocation, result)
? resolveSingleResultIfPossible((Iterable<?>) result)
: result;

View File

@@ -20,8 +20,14 @@ import org.apache.geode.cache.execute.Function;
import org.springframework.util.Assert;
/**
* An {@link AbstractFunctionTemplate} implementation for executing a {@link Function} on a target {@link Region}.
*
* @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.AbstractFunctionTemplate
* @see org.springframework.data.gemfire.function.execution.GemfireOnRegionOperations
*/
public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate implements GemfireOnRegionOperations {
@@ -31,7 +37,7 @@ public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate im
* Constructs a new instance of the {@link GemfireOnRegionFunctionTemplate} initialized with
* the given {@link Region}.
*
* @param region the {@link Region} upon which the {@link Function} will be executed.
* @param region {@link Region} on which the {@link Function} will be executed.
* @throws IllegalArgumentException if {@link Region} is {@literal null}.
* @see org.apache.geode.cache.Region
*/
@@ -44,7 +50,11 @@ public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate im
@Override
protected RegionFunctionExecution getFunctionExecution() {
return new RegionFunctionExecution(this.region);
return new RegionFunctionExecution(getRegion());
}
protected Region<?, ?> getRegion() {
return this.region;
}
@Override
@@ -52,9 +62,9 @@ public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate im
return execute(getFunctionExecution()
.setKeys(keys)
.setArguments(args)
.setFunctionId(functionId)
.setTimeout(this.timeout)
.setArgs(args));
.setTimeout(getTimeout()));
}
@Override
@@ -63,7 +73,7 @@ public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate im
return executeAndExtract(getFunctionExecution()
.setKeys(keys)
.setFunctionId(functionId)
.setTimeout(this.timeout).setArgs(args));
.setTimeout(getTimeout()).setArguments(args));
}
@Override
@@ -71,8 +81,8 @@ public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate im
execute(getFunctionExecution()
.setKeys(keys)
.setArguments(args)
.setFunctionId(functionId)
.setTimeout(this.timeout)
.setArgs(args), false);
.setTimeout(getTimeout()), false);
}
}

View File

@@ -16,14 +16,24 @@ import java.util.Set;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.shiro.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Creates a GemFire {@link Execution} using {code}FunctionService.onRegion(Region region){code}
* @author David Turanski
* {@link RegionFunctionExecution} creates a {@link Function} {@link Execution}
* using {@link FunctionService#onRegion(Region)}.
*
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.Region
* @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 RegionFunctionExecution extends AbstractFunctionExecution {
@@ -32,6 +42,9 @@ class RegionFunctionExecution extends AbstractFunctionExecution {
private volatile Set<?> keys;
public RegionFunctionExecution(Region<?, ?> region) {
Assert.notNull(region, "Region must not be null");
this.region = region;
}
@@ -44,20 +57,19 @@ class RegionFunctionExecution extends AbstractFunctionExecution {
return this.keys;
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.function.FunctionExecution#getExecution()
*/
protected Region<?, ?> getRegion() {
return this.region;
}
@Override
@SuppressWarnings("unchecked")
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Execution getExecution() {
Execution execution = FunctionService.onRegion(this.region);
Execution execution = FunctionService.onRegion(getRegion());
Set<?> keys = getKeys();
if (!CollectionUtils.isEmpty(keys) ) {
execution = execution.withFilter(keys);
}
execution = CollectionUtils.isEmpty(keys) ? execution : execution.withFilter(keys);
return execution;
}

View File

@@ -152,22 +152,23 @@ public abstract class SpringUtils {
}
}
public static <T> T safeGetValue(Supplier<T> valueSupplier) {
return safeGetValue(valueSupplier, (T) null);
public static <T> T safeGetValue(ValueReturningThrowableOperation<T> operation) {
return safeGetValue(operation, (T) null);
}
public static <T> T safeGetValue(Supplier<T> valueSupplier, T defaultValue) {
return safeGetValue(valueSupplier, (Supplier<T>) () -> defaultValue);
public static <T> T safeGetValue(ValueReturningThrowableOperation<T> operation, T defaultValue) {
return safeGetValue(operation, (Supplier<T>) () -> defaultValue);
}
public static <T> T safeGetValue(Supplier<T> valueSupplier, Supplier<T> defaultValueSupplier) {
return safeGetValue(valueSupplier, (Function<Throwable, T>) exception -> defaultValueSupplier.get());
public static <T> T safeGetValue(ValueReturningThrowableOperation<T> operation, Supplier<T> defaultValueSupplier) {
return safeGetValue(operation, (Function<Throwable, T>) exception -> defaultValueSupplier.get());
}
public static <T> T safeGetValue(Supplier<T> valueSupplier, Function<Throwable, T> exceptionHandler) {
public static <T> T safeGetValue(ValueReturningThrowableOperation<T> operation,
Function<Throwable, T> exceptionHandler) {
try {
return valueSupplier.get();
return operation.get();
}
catch (Throwable cause) {
return exceptionHandler.apply(cause);
@@ -189,6 +190,11 @@ public abstract class SpringUtils {
}
}
@FunctionalInterface
public interface ValueReturningThrowableOperation<T> {
T get() throws Throwable;
}
/**
* @deprecated use {@link VoidReturningThrowableOperation}.
*/

View File

@@ -13,24 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.fork;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.gemfire.process.support.ProcessUtils;
import org.springframework.data.gemfire.test.support.FileSystemUtils;
import org.springframework.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The ServerProcess class is a main Java class using Spring Data GemFire to configure and bootstrap
* a GemFire Cache Server process.
* The {@link ServerProcess} class is a main Java class using Spring Data for Apache Geode to configure and bootstrap
* an Apache Geode Server process.
*
* @author John Blum
* @see org.springframework.context.ConfigurableApplicationContext
@@ -42,15 +41,16 @@ public class ServerProcess {
private static final Logger logger = LoggerFactory.getLogger(ServerProcess.class);
public static void main(String[] args) throws Throwable {
ConfigurableApplicationContext applicationContext = null;
try {
applicationContext = newApplicationContext(args);
waitForShutdown();
}
catch (Throwable e) {
logger.debug("", e);
throw e;
catch (Throwable cause) {
logger.debug("", cause);
throw cause;
}
finally {
close(applicationContext);
@@ -58,6 +58,7 @@ public class ServerProcess {
}
private static ConfigurableApplicationContext newApplicationContext(String[] configLocations) {
Assert.notEmpty(configLocations, String.format("Usage: >java -cp ... %1$s %2$s",
ServerProcess.class.getName(), "classpath:/to/applicationContext.xml"));
@@ -69,8 +70,11 @@ public class ServerProcess {
}
private static boolean close(ConfigurableApplicationContext applicationContext) {
if (applicationContext != null) {
applicationContext.close();
return !(applicationContext.isRunning() || applicationContext.isActive());
}
@@ -78,9 +82,10 @@ public class ServerProcess {
}
private static void waitForShutdown() throws IOException {
ProcessUtils.writePid(new File(FileSystemUtils.WORKING_DIRECTORY, getServerProcessControlFilename()),
ProcessUtils.currentPid());
File serverProcessControlFile = new File(FileSystemUtils.WORKING_DIRECTORY, getServerProcessControlFilename());
ProcessUtils.writePid(serverProcessControlFile, ProcessUtils.currentPid());
ProcessUtils.waitForStopSignal();
}

View File

@@ -13,18 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.function;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.PdxInstanceFactory;
@@ -33,16 +36,10 @@ import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.PdxWriter;
import org.apache.geode.pdx.internal.PdxInstanceEnum;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.gemfire.fork.ServerProcess;
import org.springframework.data.gemfire.fork.SpringContainerProcess;
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
import org.springframework.data.gemfire.function.sample.ApplicationDomainFunctionExecutions;
import org.springframework.data.gemfire.process.ProcessWrapper;
@@ -53,27 +50,30 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* The ClientCacheFunctionExecutionWithPdxIntegrationTest class is a test suite of test cases testing Spring Data
* GemFire's Function annotation support and interaction between a GemFire client and server Cache
* when PDX is configured and read-serialized is set to true.
* Integration Test for SDG's Function annotation support and interaction between an Apache Geode client
* and server cache when PDX is configured and read-serialized is set to {@literal true}.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see SpringContainerProcess
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
* @see org.springframework.data.gemfire.function.sample.ApplicationDomainFunctionExecutions
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.pdx.PdxInstance
* @see org.apache.geode.pdx.PdxInstanceFactory
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxSerializer
* @see org.apache.geode.pdx.PdxWriter
* @see org.apache.geode.pdx.internal.PdxInstanceEnum
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
* @see org.springframework.data.gemfire.function.sample.ApplicationDomainFunctionExecutions
* @see org.springframework.data.gemfire.process.ProcessWrapper
* @see org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.5.2
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
// TODO: Convert to a ClientCache test.
public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientServerIntegrationTestsSupport {
private static ProcessWrapper gemfireServer;
@@ -107,7 +107,7 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private PdxInstance toPdxInstance(Map<String, Object> pdxData) {
PdxInstanceFactory pdxInstanceFactory =
gemfireClientCache.createPdxInstanceFactory(pdxData.get("@type").toString());
this.gemfireClientCache.createPdxInstanceFactory(pdxData.get("@type").toString());
for (Map.Entry<String, Object> entry : pdxData.entrySet()) {
pdxInstanceFactory.writeObject(entry.getKey(), entry.getValue());
@@ -119,79 +119,80 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@Test
public void convertedFunctionArgumentTypes() {
Class[] argumentTypes = functionExecutions.captureConvertedArgumentTypes("test", 1,
Boolean.TRUE, new Person("Jon", "Doe"), Gender.MALE);
Class<?>[] argumentTypes = this.functionExecutions
.captureConvertedArgumentTypes("test", 1, Boolean.TRUE, new Person("Jon", "Doe"),
Gender.MALE);
assertNotNull(argumentTypes);
assertEquals(5, argumentTypes.length);
assertEquals(String.class, argumentTypes[0]);
assertEquals(Integer.class, argumentTypes[1]);
assertEquals(Boolean.class, argumentTypes[2]);
assertEquals(Person.class, argumentTypes[3]);
assertEquals(Gender.class, argumentTypes[4]);
assertThat(argumentTypes).isNotNull();
assertThat(argumentTypes.length).isEqualTo(5);
assertThat(argumentTypes[0]).isEqualTo(String.class);
assertThat(argumentTypes[1]).isEqualTo(Integer.class);
assertThat(argumentTypes[2]).isEqualTo(Boolean.class);
assertThat(argumentTypes[3]).isEqualTo(Person.class);
assertThat(argumentTypes[4]).isEqualTo(Gender.class);
}
@Test
public void unconvertedFunctionArgumentTypes() {
Class[] argumentTypes = functionExecutions.captureUnconvertedArgumentTypes("test", 2,
Boolean.FALSE, new Person("Jane", "Doe"), Gender.FEMALE);
Class<?>[] argumentTypes = this.functionExecutions
.captureUnconvertedArgumentTypes("test", 2, Boolean.FALSE, new Person("Jane", "Doe"),
Gender.FEMALE);
assertNotNull(argumentTypes);
assertEquals(5, argumentTypes.length);
assertEquals(String.class, argumentTypes[0]);
assertEquals(Integer.class, argumentTypes[1]);
assertEquals(Boolean.class, argumentTypes[2]);
assertTrue(PdxInstance.class.isAssignableFrom(argumentTypes[3]));
assertEquals(PdxInstanceEnum.class, argumentTypes[4]);
assertThat(argumentTypes).isNotNull();
assertThat(argumentTypes.length).isEqualTo(5);
assertThat(argumentTypes[0]).isEqualTo(String.class);
assertThat(argumentTypes[1]).isEqualTo(Integer.class);
assertThat(argumentTypes[2]).isEqualTo(Boolean.class);
assertThat(PdxInstance.class).isAssignableFrom(argumentTypes[3]);
assertThat(argumentTypes[4]).isEqualTo(PdxInstanceEnum.class);
}
@Test
public void getAddressFieldValue() {
assertEquals("Portland", functionExecutions.getAddressField(new Address(
"100 Main St.", "Portland", "OR", "97205"), "city"));
Address address = new Address("100 Main St.", "Portland", "OR", "97205");
assertThat(this.functionExecutions.getAddressField(address, "city")).isEqualTo("Portland");
}
@Test
public void pdxDataFieldValue() {
Map<String, Object> pdxData = new HashMap<String, Object>(3);
Map<String, Object> pdxData = new HashMap<>(3);
pdxData.put("@type", "x.y.z.domain.MyApplicationDomainType");
pdxData.put("booleanField", Boolean.TRUE);
pdxData.put("integerField", 123);
pdxData.put("stringField", "test");
Integer value = (Integer) functionExecutions.getDataField(toPdxInstance(pdxData), "integerField");
Integer value = this.functionExecutions.getDataField(toPdxInstance(pdxData), "integerField");
assertEquals(pdxData.get("integerField"), value);
assertThat(value).isEqualTo(pdxData.get("integerField"));
}
public static class ApplicationDomainFunctions {
private Class[] getArgumentTypes(final Object... arguments) {
private Class<?>[] getArgumentTypes(Object... arguments) {
Class[] argumentTypes = new Class[arguments.length];
int index = 0;
List<Class<?>> argumentTypes = new ArrayList<>();
for (Object argument : arguments) {
argumentTypes[index] = arguments[index].getClass();
index++;
argumentTypes.add(argument.getClass());
}
return argumentTypes;
return argumentTypes.toArray(new Class[0]);
}
@GemfireFunction
public Class[] captureConvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
public Class<?>[] captureConvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Person person, Gender gender) {
return getArgumentTypes(stringValue, integerValue, booleanValue, person, gender);
}
@GemfireFunction
public Class[] captureUnconvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
public Class<?>[] captureUnconvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Object domainObject, Object enumValue) {
return getArgumentTypes(stringValue, integerValue, booleanValue, domainObject, enumValue);
@@ -199,7 +200,10 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@GemfireFunction
public String getAddressField(PdxInstance address, String fieldName) {
Assert.isTrue(Address.class.getName().equals(address.getClassName()), "Address is not the correct type");
Assert.isTrue(Address.class.getName().equals(address.getClassName()),
"Address is not the correct type");
return String.valueOf(address.getField(fieldName));
}
@@ -213,14 +217,15 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private final String street;
private final String city;
private final String state; // refactor; use Enum!
private final String state; // Refactor; use Enum!
private final String zipCode;
public Address(String street, String city, String state, String zipCode) {
Assert.hasText("The Address 'street' must be specified", street);
Assert.hasText("The Address 'city' must be specified", city);
Assert.hasText("The Address 'state' must be specified", state);
Assert.hasText("The Address 'zipCode' must be specified", zipCode);
Assert.hasText("Street is required", street);
Assert.hasText("City is required", city);
Assert.hasText("State is required", state);
Assert.hasText("ZipCode is required", zipCode);
this.street = street;
this.city = city;
@@ -293,8 +298,9 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private final String lastName;
public Person(String firstName, String lastName) {
Assert.hasText(firstName, "The person's first name must be specified!");
Assert.hasText(lastName, "The person's last name must be specified!");
Assert.hasText(firstName, "First name is required");
Assert.hasText(lastName, "Last name is required");
this.firstName = firstName;
this.lastName = lastName;
@@ -352,10 +358,11 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
public static PdxSerializer compose(PdxSerializer... pdxSerializers) {
return pdxSerializers == null ? null
: (pdxSerializers.length == 1
return pdxSerializers == null
? null
: pdxSerializers.length == 1
? pdxSerializers[0]
: new ComposablePdxSerializer(pdxSerializers));
: new ComposablePdxSerializer(pdxSerializers);
}
@Override
@@ -392,23 +399,23 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private PdxSerializer pdxSerializer;
public void setPdxSerializers(final List<PdxSerializer> pdxSerializers) {
public void setPdxSerializers(List<PdxSerializer> pdxSerializers) {
this.pdxSerializers = pdxSerializers;
}
@Override
public void afterPropertiesSet() throws Exception {
pdxSerializer = ComposablePdxSerializer.compose(pdxSerializers.toArray(new PdxSerializer[0]));
public void afterPropertiesSet() {
this.pdxSerializer = ComposablePdxSerializer.compose(this.pdxSerializers.toArray(new PdxSerializer[0]));
}
@Override
public PdxSerializer getObject() throws Exception {
return pdxSerializer;
public PdxSerializer getObject() {
return this.pdxSerializer;
}
@Override
public Class<?> getObjectType() {
return pdxSerializer != null ? pdxSerializer.getClass() : PdxSerializer.class;
return this.pdxSerializer != null ? this.pdxSerializer.getClass() : PdxSerializer.class;
}
@Override

View File

@@ -13,11 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.function;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.isA;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.io.IOException;
@@ -25,17 +23,15 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.execute.FunctionAdapter;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.cache.execute.FunctionException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.cache.execute.FunctionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.gemfire.fork.ServerProcess;
import org.springframework.data.gemfire.function.sample.ExceptionThrowingFunctionExecution;
@@ -48,21 +44,21 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;
/**
* The ExceptionThrowingFunctionExecutionIntegrationTest class is a test suite of test cases testing the invocation
* of a GemFire Function using Spring Data GemFire Function Execution Annotation support when that Function throws
* an Exception.
* Integration Tests testing the proper behavior of SDG's {@link Function} annotation support when the {@link Function}
* throws a {@link FunctionException}.
*
* @author John Blum
* @see org.junit.Rule
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.FunctionContext
* @see org.apache.geode.cache.execute.FunctionException
* @see org.springframework.data.gemfire.fork.ServerProcess
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
* @see org.springframework.data.gemfire.function.sample.ExceptionThrowingFunctionExecution
* @see org.springframework.data.gemfire.process.ProcessExecutor
* @see org.springframework.data.gemfire.process.ProcessWrapper
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.7.0
*/
@RunWith(SpringRunner.class)
@@ -72,9 +68,6 @@ public class ExceptionThrowingFunctionExecutionIntegrationTest {
private static ProcessWrapper gemfireServer;
@Rule
public ExpectedException exception = ExpectedException.none();
@Autowired
private ExceptionThrowingFunctionExecution exceptionThrowingFunctionExecution;
@@ -88,7 +81,7 @@ public class ExceptionThrowingFunctionExecutionIntegrationTest {
Assert.isTrue(serverWorkingDirectory.isDirectory() || serverWorkingDirectory.mkdirs(),
String.format("Failed to create working directory [%s]", serverWorkingDirectory));
List<String> arguments = new ArrayList<String>();
List<String> arguments = new ArrayList<>();
arguments.add("-Dgemfire.name=" + serverName);
arguments.add("-Dgemfire.log-level=error");
@@ -96,7 +89,7 @@ public class ExceptionThrowingFunctionExecutionIntegrationTest {
.concat("-server-context.xml"));
gemfireServer = ProcessExecutor.launch(serverWorkingDirectory, ServerProcess.class,
arguments.toArray(new String[arguments.size()]));
arguments.toArray(new String[0]));
waitForServerStart(TimeUnit.SECONDS.toMillis(20));
}
@@ -120,29 +113,37 @@ public class ExceptionThrowingFunctionExecutionIntegrationTest {
gemfireServer.shutdown();
if (Boolean.valueOf(System.getProperty("spring.gemfire.fork.clean", Boolean.TRUE.toString()))) {
if (Boolean.parseBoolean(System.getProperty("spring.gemfire.fork.clean", Boolean.TRUE.toString()))) {
org.springframework.util.FileSystemUtils.deleteRecursively(gemfireServer.getWorkingDirectory());
}
}
@Test
@Test(expected = FunctionException.class)
public void exceptionThrowingFunctionExecutionRethrowsException() {
exception.expect(FunctionException.class);
exception.expectCause(isA(IllegalArgumentException.class));
exception.expectMessage(containsString("Execution of Function with ID [exceptionThrowingFunction] failed"));
try {
this.exceptionThrowingFunctionExecution.exceptionThrowingFunction();
}
catch (FunctionException expected) {
exceptionThrowingFunctionExecution.exceptionThrowingFunction();
assertThat(expected).hasMessage("Execution of Function [with ID [exceptionThrowingFunction]] failed");
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
assertThat(expected.getCause()).hasMessage("TEST");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
}
public static class ExceptionThrowingFunction extends FunctionAdapter {
public static class ExceptionThrowingFunction implements Function<Object> {
@Override
public String getId() {
return "exceptionThrowingFunction";
}
@Override
public void execute(final FunctionContext context) {
public void execute(FunctionContext context) {
context.getResultSender().sendException(new IllegalArgumentException("TEST"));
}
}

View File

@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.function.execution;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.isA;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -33,18 +33,16 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionException;
import org.apache.geode.cache.execute.ResultCollector;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
/**
* The AbstractFunctionExecutionTest class is a test suite of test cases testing the contract and functionality
* of the AbstractFunctionExecution class.
@@ -59,11 +57,9 @@ import org.mockito.junit.MockitoJUnitRunner;
* @since 1.7.0
*/
@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings("rawtypes")
public class AbstractFunctionExecutionTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@Mock
private Execution mockExecution;
@@ -91,7 +87,7 @@ public class AbstractFunctionExecutionTest {
};
Iterable<Object> actualResults = functionExecution.setFunction(mockFunction)
.setArgs(args).setTimeout(500).execute();
.setArguments(args).setTimeout(500).execute();
assertThat(actualResults).isNotNull();
assertThat(actualResults).isEqualTo(results);
@@ -157,7 +153,6 @@ public class AbstractFunctionExecutionTest {
return mockExecution;
}
@SuppressWarnings("unchecked")
@Override <T> Iterable<T> execute() {
return null;
}
@@ -176,8 +171,8 @@ public class AbstractFunctionExecutionTest {
return mockExecution;
}
@SuppressWarnings("unchecked")
@Override <T> Iterable<T> execute() {
@Override
<T> Iterable<T> execute() {
return Collections.emptyList();
}
};
@@ -185,26 +180,28 @@ public class AbstractFunctionExecutionTest {
assertThat((Object) functionExecution.executeAndExtract()).isNull();
}
@Test
@Test(expected = FunctionException.class)
public void executeAndExtractWithThrowsException() {
AbstractFunctionExecution functionExecution = new AbstractFunctionExecution() {
AbstractFunctionExecution functionExecution = mock(AbstractFunctionExecution.class);
@Override
protected Execution getExecution() {
return mockExecution;
}
doReturn(Collections.singleton(new IllegalArgumentException("test"))).when(functionExecution).execute();
doCallRealMethod().when(functionExecution).setFunctionId(anyString());
doCallRealMethod().when(functionExecution).getFunctionId();
doCallRealMethod().when(functionExecution).executeAndExtract();
@SuppressWarnings("unchecked")
@Override <T> Iterable<T> execute() {
return Collections.singletonList((T) new IllegalArgumentException("test"));
}
};
try {
functionExecution.setFunctionId("TestFunction").executeAndExtract();
}
catch (Exception expected) {
exception.expect(FunctionException.class);
exception.expectCause(isA(IllegalArgumentException.class));
exception.expectMessage(containsString("Execution of Function with ID [TestFunction] failed"));
assertThat(expected).isInstanceOf(FunctionException.class);
assertThat(expected).hasMessage("Execution of Function [with ID [TestFunction]] failed");
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
assertThat(expected.getCause()).hasMessage("test");
assertThat(expected.getCause()).hasNoCause();
functionExecution.setFunctionId("TestFunction").executeAndExtract();
throw expected;
}
}
}

View File

@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.function.execution;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,28 +27,29 @@ import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.ResultCollector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.ResultCollector;
/**
* The AbstractFunctionTemplateTest class is a test suite of test cases testing the contract and functionality
* of the AbstractFunctionTemplate class.
* Unit Tests for {@link AbstractFunctionTemplate}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionTemplate
* @see org.apache.geode.cache.execute.Function
* @see org.apache.geode.cache.execute.ResultCollector
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionExecution
* @see org.springframework.data.gemfire.function.execution.AbstractFunctionTemplate
* @since 1.7.0
*/
@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings("rawtypes")
public class AbstractFunctionTemplateTest {
@Mock
@@ -63,17 +63,20 @@ public class AbstractFunctionTemplateTest {
@Test
public void executeWithFunctionAndArgs() {
Object[] args = { "test", "testing", "tested" };
List<Object> results = Arrays.asList(args);
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setArguments(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setFunction(mockFunction)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.execute()).thenReturn(results);
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
@Override protected AbstractFunctionExecution getFunctionExecution() {
@Override
protected AbstractFunctionExecution getFunctionExecution() {
return mockFunctionExecution;
}
};
@@ -85,9 +88,9 @@ public class AbstractFunctionTemplateTest {
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
assertThat(actualResults, is(notNullValue()));
assertThat(actualResults, is(equalTo((Iterable<Object>) results)));
assertThat(actualResults, is(equalTo((results))));
verify(mockFunctionExecution, times(1)).setArgs(args);
verify(mockFunctionExecution, times(1)).setArguments(args);
verify(mockFunctionExecution, times(1)).setFunction(mockFunction);
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
verify(mockFunctionExecution, times(1)).setTimeout(500);
@@ -96,16 +99,19 @@ public class AbstractFunctionTemplateTest {
@Test
public void executeAndExtractWithFunctionAndArgs() {
Object[] args = { "test", "testing", "tested" };
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setArguments(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setFunction(mockFunction)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.executeAndExtract()).thenReturn(args[0]);
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
@Override protected AbstractFunctionExecution getFunctionExecution() {
@Override
protected AbstractFunctionExecution getFunctionExecution() {
return mockFunctionExecution;
}
};
@@ -119,7 +125,7 @@ public class AbstractFunctionTemplateTest {
assertThat(result, is(notNullValue()));
assertThat(result, is(equalTo("test")));
verify(mockFunctionExecution, times(1)).setArgs(args);
verify(mockFunctionExecution, times(1)).setArguments(args);
verify(mockFunctionExecution, times(1)).setFunction(mockFunction);
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
verify(mockFunctionExecution, times(1)).setTimeout(500);
@@ -128,17 +134,20 @@ public class AbstractFunctionTemplateTest {
@Test
public void executeWithFunctionIdAndArgs() {
Object[] args = { "test", "testing", "tested" };
List<Object> results = Arrays.asList(args);
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setArguments(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setFunctionId("TestFunction")).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.execute()).thenReturn(results);
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
@Override protected AbstractFunctionExecution getFunctionExecution() {
@Override
protected AbstractFunctionExecution getFunctionExecution() {
return mockFunctionExecution;
}
};
@@ -150,9 +159,9 @@ public class AbstractFunctionTemplateTest {
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
assertThat(actualResults, is(notNullValue()));
assertThat(actualResults, is(equalTo((Iterable<Object>) results)));
assertThat(actualResults, is(equalTo(results)));
verify(mockFunctionExecution, times(1)).setArgs(args);
verify(mockFunctionExecution, times(1)).setArguments(args);
verify(mockFunctionExecution, times(1)).setFunctionId("TestFunction");
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
verify(mockFunctionExecution, times(1)).setTimeout(500);
@@ -161,16 +170,19 @@ public class AbstractFunctionTemplateTest {
@Test
public void executeAndExtractWithFunctionIdAndArgs() {
Object[] args = { "test", "testing", "tested" };
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setArguments(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setFunctionId("TestFunction")).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.executeAndExtract()).thenReturn(args[0]);
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
@Override protected AbstractFunctionExecution getFunctionExecution() {
@Override
protected AbstractFunctionExecution getFunctionExecution() {
return mockFunctionExecution;
}
};
@@ -184,7 +196,7 @@ public class AbstractFunctionTemplateTest {
assertThat(result, is(notNullValue()));
assertThat(result, is(equalTo("test")));
verify(mockFunctionExecution, times(1)).setArgs(args);
verify(mockFunctionExecution, times(1)).setArguments(args);
verify(mockFunctionExecution, times(1)).setFunctionId("TestFunction");
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
verify(mockFunctionExecution, times(1)).setTimeout(500);
@@ -193,16 +205,19 @@ public class AbstractFunctionTemplateTest {
@Test
public void executeWithNoResultWithFunctionIdAndArgs() {
Object[] args = { "test", "testing", "tested" };
when(mockFunctionExecution.setArgs(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setArguments(args)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setFunctionId("TestFunction")).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setResultCollector(mockResultCollector)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.setTimeout(500)).thenReturn(mockFunctionExecution);
when(mockFunctionExecution.execute(eq(false))).thenReturn(null);
AbstractFunctionTemplate functionTemplate = new AbstractFunctionTemplate() {
@Override protected AbstractFunctionExecution getFunctionExecution() {
@Override
protected AbstractFunctionExecution getFunctionExecution() {
return mockFunctionExecution;
}
};
@@ -214,11 +229,10 @@ public class AbstractFunctionTemplateTest {
assertThat(functionTemplate.getResultCollector(), is(equalTo(mockResultCollector)));
verify(mockFunctionExecution, times(1)).setArgs(args);
verify(mockFunctionExecution, times(1)).setArguments(args);
verify(mockFunctionExecution, times(1)).setFunctionId("TestFunction");
verify(mockFunctionExecution, times(1)).setResultCollector(eq(mockResultCollector));
verify(mockFunctionExecution, times(1)).setTimeout(500);
verify(mockFunctionExecution, times(1)).execute(eq(false));
}
}

View File

@@ -116,7 +116,10 @@ public class FunctionExecutionIntegrationTests extends ClientServerIntegrationTe
private void verifyFunctionExecution(AbstractFunctionExecution functionExecution) {
Iterable<String> results = functionExecution.setArgs("1", "2", "3").setFunctionId("echoFunction").execute();
Iterable<String> results = functionExecution
.setArguments("1", "2", "3")
.setFunctionId("echoFunction")
.execute();
int count = 1;

View File

@@ -10,7 +10,6 @@
* 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 static org.junit.Assert.assertEquals;
@@ -25,14 +24,15 @@ import java.util.Map;
import javax.annotation.Resource;
import org.apache.geode.cache.Region;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.Function;
import org.springframework.data.gemfire.fork.ServerProcess;
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
import org.springframework.data.gemfire.function.annotation.RegionData;
@@ -53,11 +53,12 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
private static ProcessWrapper gemfireServer;
@Resource(name = "test-region")
@Resource(name = "TestRegion")
private Region<String, Integer> region;
@BeforeClass
public static void startGemFireServer() throws Exception {
int availablePort = findAvailablePort();
gemfireServer = run(ServerProcess.class,
@@ -77,22 +78,23 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
@Before
public void initializeRegion() {
region.put("one", 1);
region.put("two", 2);
region.put("three", 3);
this.region.put("one", 1);
this.region.put("two", 2);
this.region.put("three", 3);
}
@Test
//@Ignore
public void testVoidReturnType() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region);
public void withVoidReturnType() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(this.region);
// Should work either way but the first invocation traps an exception if there is a result.
template.execute("noResult");
template.executeWithNoResult("noResult");
template.execute("noResult");
}
@Test
//@Ignore
@SuppressWarnings("unchecked")
public void testCollectionReturnTypes() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region);
@@ -126,7 +128,8 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
@Test
@SuppressWarnings("all")
public void testArrayReturnTypes() {
Object result = new GemfireOnRegionFunctionTemplate(region)
Object result = new GemfireOnRegionFunctionTemplate(this.region)
.executeAndExtract("arrays", new int[] { 1, 2, 3, 4, 5 });
assertTrue(result.getClass().getName(), result instanceof int[]);
@@ -136,7 +139,8 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
@Test
//@Ignore
public void testOnRegionFunctionExecution() {
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region);
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(this.region);
assertEquals(2, template.<Integer>execute("oneArg", "two").iterator().next().intValue());
assertFalse(template.<Integer>execute("oneArg", Collections.singleton("one"), "two").iterator().hasNext());
@@ -144,8 +148,8 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
assertEquals(5, template.<Integer>executeAndExtract("twoArg", "two", "three").intValue());
}
/*
* This gets wrapped in a GemFire Function and registered on the forked server.
/**
* This {@link Component} class gets wrapped in an Apache Geode {@link Function} and registered on the forked server.
*/
@Component
@SuppressWarnings("unused")
@@ -158,6 +162,7 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
@GemfireFunction(id = "twoArg")
public Integer twoArg(String keyOne, String keyTwo, @RegionData Map<String, Integer> region) {
if (region.get(keyOne) != null && region.get(keyTwo) != null) {
return region.get(keyOne) + region.get(keyTwo);
}
@@ -172,11 +177,12 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
@GemfireFunction(id = "getMapWithNoArgs")
public Map<String, Integer> getMapWithNoArgs(@RegionData Map<String, Integer> region) {
if (region.size() == 0) {
return null;
}
return new HashMap<String, Integer>(region);
return new HashMap<>(region);
}
@GemfireFunction(id = "arrays")
@@ -187,8 +193,7 @@ public class FunctionIntegrationTests extends ClientServerIntegrationTestsSuppor
}
@GemfireFunction
public void noResult() {
}
}
public void noResult() { }
}
}

View File

@@ -21,20 +21,24 @@ import static org.mockito.Mockito.when;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.gemfire.function.annotation.FunctionId;
import org.aopalliance.intercept.MethodInvocation;
/**
* Unit tests for {@link GemfireFunctionProxyFactoryBean}.
* Unit Tests for {@link GemfireFunctionProxyFactoryBean}.
*
* @author David Turanski
* @author John Blum
* @see java.lang.reflect.AccessibleObject
* @see java.lang.reflect.Method
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.aopalliance.intercept.MethodInvocation
@@ -50,34 +54,37 @@ public class GemfireFunctionProxyFactoryBeanUnitTests {
}
@Test
public void invoke() throws Throwable {
public void invoke() {
MethodInvocation invocation = new TestMethodInvocation(IFoo.class)
.withMethodNameAndArgTypes("collections",List.class);
.withMethodNameAndArgTypes("collections", List.class);
when(this.functionOperations.executeAndExtract("collections",invocation.getArguments()))
when(this.functionOperations.execute("collections", invocation.getArguments()))
.thenReturn(Arrays.asList(1, 2, 3));
GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class, this.functionOperations);
GemfireFunctionProxyFactoryBean proxy =
new GemfireFunctionProxyFactoryBean(IFoo.class, this.functionOperations);
Object result = proxy.invoke(invocation);
assertThat(result).isInstanceOf(List.class);
assertThat((List) result).hasSize(3);
assertThat((List<?>) result).hasSize(3);
verify(this.functionOperations, times(1))
.executeAndExtract("collections",invocation.getArguments());
.execute("collections", invocation.getArguments());
}
@Test
public void invokeAndExtractWithAnnotatedFunctionId() throws Throwable {
public void invokeAndExtractWithAnnotatedFunctionId() {
MethodInvocation invocation = new TestMethodInvocation(IFoo.class)
.withMethodNameAndArgTypes("oneArg", String.class);
when(this.functionOperations.executeAndExtract("oneArg",invocation.getArguments())).thenReturn(1);
when(this.functionOperations.execute("oneArg", invocation.getArguments()))
.thenReturn(Collections.singleton(1));
GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class, this.functionOperations);
GemfireFunctionProxyFactoryBean proxy =
new GemfireFunctionProxyFactoryBean(IFoo.class, this.functionOperations);
Object result = proxy.invoke(invocation);
@@ -85,7 +92,7 @@ public class GemfireFunctionProxyFactoryBeanUnitTests {
assertThat(result).isEqualTo(1);
verify(this.functionOperations, times(1))
.executeAndExtract("oneArg", invocation.getArguments());
.execute("oneArg", invocation.getArguments());
}
@SuppressWarnings("unused")
@@ -93,7 +100,7 @@ public class GemfireFunctionProxyFactoryBeanUnitTests {
private Class<?> type;
private Class<?>[] argTypes;
private Class<?>[] argumentTypes;
private Object[] arguments;
@@ -110,54 +117,39 @@ public class GemfireFunctionProxyFactoryBeanUnitTests {
return this;
}
public TestMethodInvocation withMethodNameAndArgTypes(String methodName,Class<?>... argTypes) {
public TestMethodInvocation withMethodNameAndArgTypes(String methodName, Class<?>... argTypes) {
this.methodName = methodName;
this.argTypes = argTypes;
this.argumentTypes = argTypes;
return this;
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.Invocation#getArguments()
*/
@Override
public Object[] getArguments() {
return this.arguments;
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.Joinpoint#proceed()
*/
@Override
public Object proceed() throws Throwable {
public Object proceed() {
return null;
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.Joinpoint#getThis()
*/
@Override
public Object getThis() {
return null;
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.Joinpoint#getStaticPart()
*/
@Override
public AccessibleObject getStaticPart() {
return null;
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInvocation#getMethod()
*/
@Override
public Method getMethod() {
try {
return this.type.getMethod(methodName, argTypes);
return this.type.getMethod(this.methodName, this.argumentTypes);
}
catch (NoSuchMethodException | SecurityException cause) {
return null;

View File

@@ -16,6 +16,18 @@
*/
package org.springframework.data.gemfire.function.execution.onservers;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.StatisticDescriptor;
import org.apache.geode.Statistics;
import org.apache.geode.StatisticsType;
@@ -27,32 +39,22 @@ import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.internal.statistics.StatisticsManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions;
import org.springframework.data.gemfire.process.ProcessWrapper;
import org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport;
import org.springframework.data.gemfire.transaction.config.EnableGemfireCacheTransactions;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Patrick Johnson
*/
@SuppressWarnings("unused")
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = FunctionsReturnResultsFromAllServersIntegrationTests.Config.class)
@ContextConfiguration(classes = FunctionsReturnResultsFromAllServersIntegrationTests.GeodeClientConfiguration.class)
@Ignore
public class FunctionsReturnResultsFromAllServersIntegrationTests extends ClientServerIntegrationTestsSupport {
private static final int PORT_1 = 40407;
@@ -81,12 +83,6 @@ public class FunctionsReturnResultsFromAllServersIntegrationTests extends Client
waitForServerToStart(DEFAULT_HOSTNAME, PORT_2);
}
@ClientCacheApplication(servers = {@ClientCacheApplication.Server(port = PORT_1), @ClientCacheApplication.Server(port = PORT_2)})
@Configuration
@EnableGemfireFunctionExecutions(basePackageClasses = AllServersAdminFunctions.class)
@EnableGemfireCacheTransactions
static class Config { }
@AfterClass
public static void stopGemFireServer() {
stop(gemfireServer1);
@@ -105,12 +101,18 @@ public class FunctionsReturnResultsFromAllServersIntegrationTests extends Client
assertThat(metrics.size()).isEqualTo(672);
}
@ClientCacheApplication(servers = {
@ClientCacheApplication.Server(port = PORT_1),
@ClientCacheApplication.Server(port = PORT_2)}
)
@EnableGemfireFunctionExecutions(basePackageClasses = AllServersAdminFunctions.class)
static class GeodeClientConfiguration { }
static class MetricsFunctionServerProcess {
private static final int DEFAULT_CACHE_SERVER_PORT = 40404;
private static final String CACHE_SERVER_PORT_PROPERTY = "spring.data.gemfire.cache.server.port";
private static final String GEMFIRE_LOG_LEVEL = "error";
private static final String GEMFIRE_NAME = "MetricsServer" + getCacheServerPort();
public static void main(String[] args) throws Exception {
@@ -121,7 +123,6 @@ public class FunctionsReturnResultsFromAllServersIntegrationTests extends Client
return new CacheFactory()
.set("name", GEMFIRE_NAME)
.set("log-level", GEMFIRE_LOG_LEVEL)
.create();
}

View File

@@ -35,15 +35,15 @@ import org.springframework.data.gemfire.function.annotation.OnServer;
@SuppressWarnings("unused")
public interface ApplicationDomainFunctionExecutions {
Class[] captureConvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Class<?>[] captureConvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
ClientCacheFunctionExecutionWithPdxIntegrationTest.Person person,
ClientCacheFunctionExecutionWithPdxIntegrationTest.Gender gender);
Class[] captureUnconvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Class<?>[] captureUnconvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Object person, Object gender);
String getAddressField(ClientCacheFunctionExecutionWithPdxIntegrationTest.Address address, String fieldName);
Object getDataField(PdxInstance data, String fieldName);
Integer getDataField(PdxInstance data, String fieldName);
}

View File

@@ -13,15 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.function.sample;
import org.apache.geode.cache.execute.Function;
import org.springframework.data.gemfire.function.annotation.OnServer;
/**
* The ExceptionThrowingFunctionExecution interface defines a GemFire Function that throws a RuntimeException.
* The {@link ExceptionThrowingFunctionExecution} interface defines a GemFire {@link Function}
* that throws a {@link RuntimeException}.
*
* @author John Blum
* @see org.apache.geode.cache.execute.Function
* @see org.springframework.data.gemfire.function.annotation.OnServer
* @since 1.7.0
*/

View File

@@ -50,11 +50,14 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.gemfire.util.SpringUtils.ValueReturningThrowableOperation;
/**
* Unit Tests for {@link SpringUtils}.
*
* @author John Blum
* @see java.util.function.Function
* @see java.util.function.Supplier
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
@@ -415,16 +418,19 @@ public class SpringUtilsUnitTests {
@Test
public void safeGetValueReturnsSuppliedDefaultValue() {
Supplier<String> exceptionThrowingSupplier = () -> { throw newRuntimeException("error"); };
ValueReturningThrowableOperation<String> exceptionThrowingOperation =
() -> { throw newRuntimeException("error"); };
Supplier<String> defaultValueSupplier = () -> "test";
assertThat(SpringUtils.safeGetValue(exceptionThrowingSupplier, defaultValueSupplier)).isEqualTo("test");
assertThat(SpringUtils.safeGetValue(exceptionThrowingOperation, defaultValueSupplier)).isEqualTo("test");
}
@Test
public void safeGetValueHandlesExceptionReturnsValue() {
Supplier<String> exceptionThrowingSupplier = () -> { throw newRuntimeException("error"); };
ValueReturningThrowableOperation<String> exceptionThrowingOperation =
() -> { throw newRuntimeException("error"); };
Function<Throwable, String> exceptionHandler = exception -> {
@@ -435,13 +441,14 @@ public class SpringUtilsUnitTests {
return "test";
};
assertThat(SpringUtils.safeGetValue(exceptionThrowingSupplier, exceptionHandler)).isEqualTo("test");
assertThat(SpringUtils.safeGetValue(exceptionThrowingOperation, exceptionHandler)).isEqualTo("test");
}
@Test(expected = IllegalStateException.class)
public void safeGetValueHandlesExceptionAndCanThrowException() {
Supplier<String> exceptionThrowingSupplier = () -> { throw newRuntimeException("error"); };
ValueReturningThrowableOperation<String> exceptionThrowingOperation =
() -> { throw newRuntimeException("error"); };
Function<Throwable, String> exceptionHandler = exception -> {
@@ -453,7 +460,7 @@ public class SpringUtilsUnitTests {
};
try {
SpringUtils.safeGetValue(exceptionThrowingSupplier, exceptionHandler);
SpringUtils.safeGetValue(exceptionThrowingOperation, exceptionHandler);
}
catch (IllegalStateException expected) {

View File

@@ -32,10 +32,10 @@
</property>
</bean>
<gfe:client-cache properties-ref="gemfireProperties" pool-name="serverConnectionPool"
<gfe:client-cache properties-ref="gemfireProperties" pool-name="serverPool"
pdx-serializer-ref="domainBasedPdxSerializer"/>
<gfe:pool id="serverConnectionPool">
<gfe:pool id="serverPool">
<gfe:server host="localhost" port="${spring.data.gemfire.cache.server.port:40404}"/>
</gfe:pool>

View File

@@ -36,7 +36,7 @@
<gfe:cache properties-ref="gemfireProperties" pdx-serializer-ref="domainBasedPdxSerializer"
pdx-read-serialized="true" pdx-ignore-unread-fields="false"/>
<gfe:cache-server auto-startup="true" max-connections="2" port="${spring.data.gemfire.cache.server.port:40404}"/>
<gfe:cache-server max-connections="2" port="${spring.data.gemfire.cache.server.port:40404}"/>
<gfe:annotation-driven/>

View File

@@ -26,7 +26,7 @@
<gfe:cache properties-ref="gemfireProperties"/>
<gfe:cache-server auto-startup="true" bind-address="${server.bind-address}" port="${server.port}"
<gfe:cache-server bind-address="${server.bind-address}" port="${server.port}"
host-name-for-clients="${server.hostname-for-clients}" max-connections="${server.max-connections}"/>
<gfe:function-service>

View File

@@ -17,12 +17,12 @@
<prop key="log-level">error</prop>
</util:properties>
<gfe:client-cache properties-ref="gemfireProperties" pool-name="serverBasedPool"/>
<gfe:client-cache properties-ref="gemfireProperties" pool-name="serverPool"/>
<gfe:pool id="serverBasedPool">
<gfe:pool id="serverPool">
<gfe:server host="localhost" port="${spring.data.gemfire.cache.server.port:40404}"/>
</gfe:pool>
<gfe:client-region id="test-region" pool-name="serverBasedPool" shortcut="PROXY"/>
<gfe:client-region id="TestRegion" pool-name="serverPool" shortcut="PROXY"/>
</beans>

View File

@@ -23,7 +23,7 @@
<gfe:cache-server port="${spring.data.gemfire.cache.server.port:40404}"/>
<gfe:partitioned-region id="test-region"/>
<gfe:partitioned-region id="TestRegion"/>
<gfe:annotation-driven/>