From 3a4f727334450a14e32c9aad6cf324e1a0da5ff6 Mon Sep 17 00:00:00 2001 From: David Turanski Date: Wed, 17 Apr 2013 09:58:40 -0400 Subject: [PATCH] SGF-173. Added NoResult methods to FunctionTemplate and checked for FunctionExecution exception related to Function.hasResult() = false --- .../execution/AbstractFunctionExecution.java | 133 ++++++++++-------- .../execution/AbstractFunctionTemplate.java | 14 ++ .../execution/GemfireFunctionOperations.java | 7 + .../GemfireOnMemberFunctionTemplate.java | 1 - .../GemfireOnRegionFunctionTemplate.java | 67 ++++----- .../execution/GemfireOnRegionOperations.java | 1 + .../execution/FunctionIntegrationTests.java | 17 ++- 7 files changed, 145 insertions(+), 95 deletions(-) diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecution.java index 53e93aec..84b572b5 100644 --- a/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecution.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionExecution.java @@ -35,30 +35,33 @@ import com.gemstone.gemfire.cache.execute.ResultCollector; */ abstract class AbstractFunctionExecution { + + private final static String NO_RESULT_MESSAGE = "Cannot return any result as the Function#hasResult() is false"; + protected final Log logger = LogFactory.getLog(this.getClass()); - + private volatile ResultCollector resultCollector; private Object[] args; - private Function function; - private String functionId; + private Function function; + private String functionId; private long timeout; public AbstractFunctionExecution(Function function, Object... args) { - Assert.notNull(function,"function cannot be null"); - this.function = function; + Assert.notNull(function, "function cannot be null"); + this.function = function; this.functionId = function.getId(); this.args = args; } - + public AbstractFunctionExecution(String functionId, Object... args) { - Assert.isTrue(StringUtils.hasLength(functionId),"functionId cannot be null or empty"); - this.functionId = functionId; + Assert.isTrue(StringUtils.hasLength(functionId), "functionId cannot be null or empty"); + this.functionId = functionId; this.args = args; } - + AbstractFunctionExecution() { } - + ResultCollector getCollector() { return resultCollector; } @@ -70,17 +73,21 @@ abstract class AbstractFunctionExecution { String getFunctionId() { return functionId; } - + Function getFunction() { return function; } - + long getTimeout() { return timeout; - } - - @SuppressWarnings("unchecked") + } + Iterable execute() { + return execute(true); + } + + @SuppressWarnings("unchecked") + Iterable execute(Boolean returnResult) { Execution execution = this.getExecution(); if (getKeys() != null) { execution = execution.withFilter(getKeys()); @@ -88,107 +95,119 @@ abstract class AbstractFunctionExecution { if (getCollector() != null) { execution = execution.withCollector(getCollector()); } - - ResultCollector resultCollector = null; - + + ResultCollector resultCollector = null; + execution = execution.withArgs(getArgs()); - - if (isRegisteredFunction()){ - - resultCollector = (ResultCollector) execution.execute(functionId); + + if (isRegisteredFunction()) { + resultCollector = (ResultCollector) execution.execute(functionId); } else { - resultCollector = (ResultCollector) execution.execute(function); + resultCollector = (ResultCollector) execution.execute(function); + if (!function.hasResult()) { + return (Iterable) null; + } } + if (!returnResult) { + return (Iterable) null; + } + if (logger.isDebugEnabled()) { logger.debug("using ResultsCollector:" + resultCollector.getClass().getName()); } - + Iterable results = null; - - if (this.timeout > 0 ){ - try { - results= (Iterable)resultCollector.getResult(this.timeout, TimeUnit.MILLISECONDS); + + try { + if (this.timeout > 0) { + try { + results = (Iterable) resultCollector.getResult(this.timeout, TimeUnit.MILLISECONDS); + } catch (FunctionException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } else { + + results = (Iterable) resultCollector.getResult(); } - catch (FunctionException e) { - throw new RuntimeException(e); + + return replaceSingletonNullCollectionWithEmptyList(results); + + } catch (FunctionException e) { + //TODO: Come up with a better way to determine that the function should not return a result; + if (!e.getMessage().equals(NO_RESULT_MESSAGE)) { + throw e; } - catch (InterruptedException e) { - throw new RuntimeException(e); - } - } else { - - results = (Iterable) resultCollector.getResult(); } - return replaceSingletonNullCollectionWithEmptyList(results); - + return results; } - + T executeAndExtract() { Iterable results = this.execute(); if (results == null || !results.iterator().hasNext()) { return null; } - + return results.iterator().next(); } - + protected abstract Execution getExecution(); - + protected AbstractFunctionExecution setFunctionId(String functionId) { this.functionId = functionId; return this; } - + protected AbstractFunctionExecution setFunction(Function function) { this.function = function; return this; } - + protected AbstractFunctionExecution setArgs(Object... args) { this.args = args; return this; } - + protected Set getKeys() { return null; } - + protected AbstractFunctionExecution setTimeout(long timeout) { this.timeout = timeout; return this; } - - protected AbstractFunctionExecution setResultCollector(ResultCollector resultCollector) { + + protected AbstractFunctionExecution setResultCollector(ResultCollector resultCollector) { this.resultCollector = resultCollector; return this; } - /** * @return */ private boolean isRegisteredFunction() { - return function == null; + return function == null; } - + private Iterable replaceSingletonNullCollectionWithEmptyList(Iterable results) { if (results == null) { return results; } Iterator it = results.iterator(); - + if (!it.hasNext()) { return results; } - - if (it.next()==null && !it.hasNext()) { + + if (it.next() == null && !it.hasNext()) { return new ArrayList(); } - + return results; - + } - + } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java index 0addd2ce..213e15e2 100644 --- a/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java @@ -56,6 +56,14 @@ abstract class AbstractFunctionTemplate implements GemfireFunctionOperations { .setFunctionId(functionId); return execute(functionExecution); } + + @Override + public void executeWithNoResult(String functionId, Object... args) { + AbstractFunctionExecution functionExecution = getFunctionExecution() + .setArgs(args) + .setFunctionId(functionId); + execute(functionExecution,false); + } @Override public T executeAndExtract(String functionId, Object... args) { @@ -78,6 +86,12 @@ abstract class AbstractFunctionTemplate implements GemfireFunctionOperations { return execution.execute(); } + protected Iterable execute(AbstractFunctionExecution execution, boolean returnResult) { + execution.setTimeout(timeout) + .setResultCollector(resultCollector); + return execution.execute(returnResult); + } + protected T executeAndExtract(AbstractFunctionExecution execution) { execution.setTimeout(timeout) .setResultCollector(resultCollector); diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java index b5ac9375..f54a32be 100644 --- a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java @@ -49,6 +49,13 @@ public interface GemfireFunctionOperations { */ public abstract Iterable execute(String functionId, Object... args); + /** + * Execute a function registered with an ID with no return value + * @param functionId the function ID + * @param args the calling arguments + */ + public void executeWithNoResult(String functionId, Object... args); + /** * Execute a function registered with an ID and with an expected singleton result * @param functionId the function ID diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java index 31ac69a0..dcbe099f 100644 --- a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java @@ -50,5 +50,4 @@ public class GemfireOnMemberFunctionTemplate extends AbstractFunctionTemplate { } return new DistributedMemberFunctionExecution(this.distributedMember); } - } diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java index 1afd624f..35aabe4b 100644 --- a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java @@ -23,51 +23,46 @@ import com.gemstone.gemfire.cache.execute.Function; * @author David Turanski * */ -public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate implements GemfireOnRegionOperations { - +public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate implements GemfireOnRegionOperations { + private Region region; - + /** * * @param region */ - public GemfireOnRegionFunctionTemplate(Region region) { - Assert.notNull(region, "Region cannot be null"); - this.region = region; - } - - - @Override - public Iterable execute(Function function, Set keys, Object... args) { - return execute(new RegionFunctionExecution(region) - .setKeys(keys) - .setFunction(function) - .setTimeout(timeout) - .setArgs(args) ); - } - - - @Override - public Iterable execute(String functionId, Set keys, Object... args) { - return execute(new RegionFunctionExecution(region) - .setKeys(keys) - .setFunctionId(functionId) - .setTimeout(timeout) - .setArgs(args) ); - } - - @Override - public T executeAndextract(String functionId, Set keys, Object... args) { - return this. executeAndExtract(new RegionFunctionExecution(region) - .setKeys(keys) - .setFunctionId(functionId) - .setTimeout(timeout) - .setArgs(args) ); + public GemfireOnRegionFunctionTemplate(Region region) { + Assert.notNull(region, "Region cannot be null"); + this.region = region; } @Override - protected AbstractFunctionExecution getFunctionExecution() { + public Iterable execute(Function function, Set keys, Object... args) { + return execute(new RegionFunctionExecution(region).setKeys(keys).setFunction(function).setTimeout(timeout) + .setArgs(args)); + } + + @Override + public Iterable execute(String functionId, Set keys, Object... args) { + return execute(new RegionFunctionExecution(region).setKeys(keys).setFunctionId(functionId).setTimeout(timeout) + .setArgs(args)); + } + + @Override + public T executeAndextract(String functionId, Set keys, Object... args) { + return this. executeAndExtract(new RegionFunctionExecution(region).setKeys(keys).setFunctionId(functionId) + .setTimeout(timeout).setArgs(args)); + } + + @Override + protected AbstractFunctionExecution 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); + } + } diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java index 8617a52e..e9beb8c9 100644 --- a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java @@ -25,6 +25,7 @@ public interface GemfireOnRegionOperations extends GemfireFunctionOperations { public abstract Iterable execute(String functionId, Set keys, Object... args); public abstract Iterable execute(Function function, Set keys, Object... args); + public abstract void executeWithNoResult(String functionId, Set keys, Object... args); public abstract T executeAndextract(String functionId, Set keys, Object... args); } \ No newline at end of file diff --git a/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java index f60111f7..987d5b63 100644 --- a/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java @@ -69,6 +69,14 @@ public class FunctionIntegrationTests { region.put("three",3); } + @Test + public void testVoidReturnType() { + GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region); + //Either way should work but the first one traps an exception if there is a result. + template.execute("noResult"); + template.executeWithNoResult("noResult"); + } + @Test public void testOnRegionFunctionExecution() { @@ -118,6 +126,8 @@ public class FunctionIntegrationTests { Object result = template.executeAndExtract("arrays",new int[]{1,2,3,4,5}); assertTrue(result.getClass().getName(),result instanceof int[]); } + + /* * This gets wrapped in a GemFire Function and registered on the forked server. */ @@ -151,8 +161,13 @@ public class FunctionIntegrationTests { } @GemfireFunction(id="arrays",batchSize=2) - public int[] collections(int[] args) { + public int[] collections(int[] args) { return args; } + + @GemfireFunction + public void noResult() { + + } } }