diff --git a/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java b/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java index ffab5803..9c90122b 100644 --- a/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java +++ b/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java @@ -10,32 +10,47 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ + package org.springframework.data.gemfire.function; import java.lang.reflect.Method; import java.util.Map; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.geode.cache.Region; +import org.apache.geode.cache.execute.Function; import org.apache.geode.cache.execute.FunctionContext; import org.apache.geode.cache.execute.RegionFunctionContext; import org.apache.geode.cache.execute.ResultSender; import org.apache.geode.cache.partition.PartitionRegionHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.data.gemfire.function.annotation.Filter; import org.springframework.data.gemfire.function.annotation.RegionData; import org.springframework.data.gemfire.util.ArrayUtils; import org.springframework.util.Assert; /** - * @author David Turanski - * @since 1.3.0 + * {@link FunctionArgumentResolver} implementation capable of resolving the {@link FunctionContext} passed to + * a {@link Function} implementation during invocation. * + * @author David Turanski + * @author John Blum + * @see java.lang.reflect.Method + * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.execute.Function + * @see org.apache.geode.cache.execute.FunctionContext + * @see org.apache.geode.cache.execute.RegionFunctionContext + * @see org.apache.geode.cache.execute.ResultSender + * @see org.apache.geode.cache.partition.PartitionRegionHelper + * @see org.springframework.data.gemfire.function.annotation.Filter + * @see org.springframework.data.gemfire.function.annotation.RegionData + * @see org.springframework.data.gemfire.function.PdxFunctionArgumentResolver + * @since 1.3.0 */ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolver { - private static final Log logger = LogFactory.getLog(FunctionContextInjectingArgumentResolver.class); + private final Logger logger = LoggerFactory.getLogger(FunctionContextInjectingArgumentResolver.class); private final int filterParameterPosition; private final int functionContextParameterPosition; @@ -44,7 +59,7 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv private final Method method; - public FunctionContextInjectingArgumentResolver(Method method) { + FunctionContextInjectingArgumentResolver(Method method) { this.method = method; @@ -112,35 +127,36 @@ class FunctionContextInjectingArgumentResolver extends PdxFunctionArgumentResolv return args; } - /* - * (non-Javadoc) - * @see org.apache.geode.cache.execute.RegionFunctionContext - */ - private static Region getRegionForContext(RegionFunctionContext regionFunctionContext) { + private Region getRegionForContext(RegionFunctionContext regionFunctionContext) { + Region region = regionFunctionContext.getDataSet(); if (PartitionRegionHelper.isPartitionedRegion(region)) { + if (logger.isDebugEnabled()) { logger.debug("this is a partitioned region - filtering local data for context"); } + region = PartitionRegionHelper.getLocalDataForContext(regionFunctionContext); } if (logger.isDebugEnabled()) { - logger.debug("region contains " + region.size() + " items"); + logger.debug("Region contains {} items", region.size()); } return region; } - private static int getArgumentTypePosition(Method method, Class requiredType) { + int getArgumentTypePosition(Method method, Class requiredType) { + int index = 0; int position = -1; for (Class parameterType : method.getParameterTypes()) { - if (requiredType.equals(parameterType)) { - Assert.state(position < 0, String.format( - "Method %s signature cannot contain more than one parameter of type %s.", + if (requiredType.isAssignableFrom(parameterType)) { + + Assert.state(position < 0, + String.format("Method [%1$s] signature cannot contain more than one parameter of type [%2$s].", method.getName(), requiredType.getName())); position = index; diff --git a/src/test/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolverUnitTests.java new file mode 100644 index 00000000..12101254 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolverUnitTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire.function; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; + +import org.apache.geode.cache.execute.FunctionContext; +import org.apache.geode.cache.execute.RegionFunctionContext; +import org.junit.Test; +import org.springframework.data.gemfire.function.annotation.GemfireFunction; +import org.springframework.data.gemfire.util.ArrayUtils; + +/** + * Unit tests for {@link FunctionContextInjectingArgumentResolver}. + * + * @author John Blum + * @see java.lang.reflect.Method + * @see org.junit.Test + * @see org.apache.geode.cache.execute.FunctionContext + * @see org.apache.geode.cache.execute.RegionFunctionContext + * @see org.springframework.data.gemfire.function.FunctionContextInjectingArgumentResolver + * @since 1.0.0 + */ +@SuppressWarnings("unused") +public class FunctionContextInjectingArgumentResolverUnitTests { + + @Test + public void getArgumentTypePositionWithMethodHavingNoArgumentsReturnsMinusOne() throws Exception { + + Method functionOne = FunctionOne.class.getDeclaredMethod("functionOne"); + + FunctionContextInjectingArgumentResolver functionArgumentResolver = + new FunctionContextInjectingArgumentResolver(functionOne); + + assertThat(functionArgumentResolver.getArgumentTypePosition(functionOne, FunctionContext.class)).isEqualTo(-1); + } + + @Test + public void getArgumentTypePositionForExactArgumentTypeReturnsNonNegativeIndex() throws Exception { + + Method functionTwo = FunctionTwo.class + .getDeclaredMethod("functionTwo", ArrayUtils.asArray(FunctionContext.class)); + + FunctionContextInjectingArgumentResolver functionArgumentResolver = + new FunctionContextInjectingArgumentResolver(functionTwo); + + assertThat(functionArgumentResolver.getArgumentTypePosition(functionTwo, FunctionContext.class)).isEqualTo(0); + } + + @Test + public void getArgumentTypePositionForInexactArgumentTypeReturnsNonNegativeIndex() throws Exception { + + Method functionThree = FunctionThree.class + .getDeclaredMethod("functionThree", ArrayUtils.asArray(Object.class, RegionFunctionContext.class)); + + FunctionContextInjectingArgumentResolver functionArgumentResolver = + new FunctionContextInjectingArgumentResolver(functionThree); + + assertThat(functionArgumentResolver.getArgumentTypePosition(functionThree, FunctionContext.class)).isEqualTo(1); + } + + @Test + public void getArgumentTypePositionForNonMatchingArgumentTypeReturnsMinusOne() throws Exception { + + Method functionFour = FunctionFour.class + .getDeclaredMethod("functionFour", ArrayUtils.asArray(Object.class, String.class)); + + FunctionContextInjectingArgumentResolver functionArgumentResolver = + new FunctionContextInjectingArgumentResolver(functionFour); + + assertThat(functionArgumentResolver.getArgumentTypePosition(functionFour, FunctionContext.class)).isEqualTo(-1); + } + + static class FunctionOne { + + @GemfireFunction + void functionOne() { } + + } + + static class FunctionTwo { + + @GemfireFunction + void functionTwo(FunctionContext functionContext) { } + + } + + static class FunctionThree { + + @GemfireFunction + void functionThree(Object arg, RegionFunctionContext functionContext) { } + } + + static class FunctionFour { + + @GemfireFunction + void functionFour(Object functionContext, String arg) { } + + } +}