/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.data.gemfire.function;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geode.cache.execute.FunctionService;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author David Turanski
*/
public abstract class GemfireFunctionUtils {
private static Log log = LogFactory.getLog(GemfireFunctionUtils.class);
/**
* Wrap a target object and method in a GemFire Function and register the function to the {@link FunctionService}
*
* @param target the target object
* @param method the method bound to the function
* @param attributes function attributes
* @param overwrite if true, will replace the existing function
*/
public static void registerFunctionForPojoMethod(Object target, Method method, Map<String, Object> attributes,
boolean overwrite) {
String id = attributes.containsKey("id") ? (String) attributes.get("id") : "";
PojoFunctionWrapper function = new PojoFunctionWrapper(target, method, id);
if (attributes.containsKey("HA")) {
function.setHA((Boolean) attributes.get("HA"));
}
if (attributes.containsKey("optimizeForWrite")) {
function.setOptimizeForWrite((Boolean) attributes.get("optimizeForWrite"));
}
if (attributes.containsKey("batchSize")) {
int batchSize = (Integer) attributes.get("batchSize");
Assert.isTrue(batchSize >= 0, String.format("batchSize must be a non-negative value %1$s.%2$s",
target.getClass().getName(), method.getName()));
function.setBatchSize(batchSize);
}
if (attributes.containsKey("hasResult")) {
// only set if true TODO figure out why???
if (Boolean.TRUE.equals(attributes.get("hasResult"))) {
function.setHasResult(true);
}
}
if (FunctionService.isRegistered(function.getId())) {
if (overwrite) {
if (log.isDebugEnabled()) {
log.debug("unregistering function definition " + function.getId());
}
FunctionService.unregisterFunction(function.getId());
}
}
if (!FunctionService.isRegistered(function.getId())) {
FunctionService.registerFunction(function);
if (log.isDebugEnabled()) {
log.debug("registered function " + function.getId());
}
}
else {
if (log.isDebugEnabled()) {
log.debug("function " + function.getId() + "is already registered");
}
}
}
/**
* Determine the order position of a an annotated method parameter
*
* @param method the {@link Method} instance
* @param targetAnnotationType the annotation
* @param requiredTypes an array of valid parameter types for the annotation
* @return the parameter position or -1 if the annotated parameter is not found
*/
public static int getAnnotationParameterPosition(Method method, Class<?> targetAnnotationType,
Class<?>[] requiredTypes) {
int position = -1;
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations.length > 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
List<Class<?>> requiredTypesList = Arrays.asList(requiredTypes);
for (int index = 0; index < parameterAnnotations.length; index++) {
Annotation[] annotations = parameterAnnotations[index];
if (annotations.length > 0) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(targetAnnotationType)) {
Assert.state(position < 0, String.format(
"Method %s signature cannot contain more than one parameter annotated with type %s",
method.getName(), targetAnnotationType.getName()));
boolean isRequiredType = false;
for (Class<?> requiredType : requiredTypesList) {
if (requiredType.isAssignableFrom(parameterTypes[index])) {
isRequiredType = true;
break;
}
}
Assert.isTrue(isRequiredType, String.format(
"Parameter of type %s annotated with %s must be assignable from one of type %s in method %s",
parameterTypes[index], targetAnnotationType.getName(),
StringUtils.arrayToCommaDelimitedString(requiredTypes), method.getName()));
position = index;
}
}
}
}
}
return position;
}
}