SGF-787 - Add 'requiredPermissions' to @GemfireFunction annotation.
This commit is contained in:
@@ -24,11 +24,13 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.execute.FunctionService;
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -50,6 +52,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class GemfireFunctionUtils {
|
||||
|
||||
private static final String DEFAULT_FUNCTION_ID = null;
|
||||
|
||||
private static Log log = LogFactory.getLog(GemfireFunctionUtils.class);
|
||||
|
||||
/**
|
||||
@@ -61,19 +65,39 @@ public abstract class GemfireFunctionUtils {
|
||||
* @see java.lang.reflect.Method
|
||||
*/
|
||||
public static boolean isGemfireFunction(Method method) {
|
||||
return (method != null && method.isAnnotationPresent(GemfireFunction.class));
|
||||
return method != null && method.isAnnotationPresent(GemfireFunction.class);
|
||||
}
|
||||
|
||||
private static boolean isMatchingGemfireFunction(Method method, String functionId) {
|
||||
/**
|
||||
* Determines whether the given {@link Method} is a POJO, {@link GemfireFunction} annotated {@link Method}
|
||||
* having an ID matching the given {@code functionId}.
|
||||
*
|
||||
* @param method {@link Method} to evaluate.
|
||||
* @param functionId {@link String} containing the {@link Function#getId() ID} to match.
|
||||
* @return a boolean indicating whether the given {@link Method} is a POJO, {@link GemfireFunction} annotated
|
||||
* {@link Method} with the given {@code functionId}.
|
||||
* @see #getGemfireFunctionId(Method)
|
||||
* @see java.lang.reflect.Method
|
||||
*/
|
||||
public static boolean isMatchingGemfireFunction(Method method, String functionId) {
|
||||
return getGemfireFunctionId(method).filter(methodFunctionId ->
|
||||
ObjectUtils.nullSafeEquals(methodFunctionId, functionId)).isPresent();
|
||||
}
|
||||
|
||||
private static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element,
|
||||
static Annotation getAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
return AnnotationUtils.getAnnotation(element, annotationType);
|
||||
}
|
||||
|
||||
static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, Annotation annotation) {
|
||||
return AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(element, annotation));
|
||||
}
|
||||
|
||||
static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return AnnotationAttributes.fromMap(
|
||||
AnnotationUtils.getAnnotationAttributes(element, element.getAnnotation(annotationType)));
|
||||
return element.isAnnotationPresent(annotationType)
|
||||
? getAnnotationAttributes(element, getAnnotation(element, annotationType))
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,24 +107,24 @@ public abstract class GemfireFunctionUtils {
|
||||
* If the {@link Method} is not {@literal null} and annotated with {@link GemfireFunction} then this method
|
||||
* tries to determine the {@link Function#getId()} from the {@link GemfireFunction#id()} attribute.
|
||||
*
|
||||
* If the {@link GemfireFunction#id()} attribute was not set, then the {@link Method#getName()}
|
||||
* If the {@link GemfireFunction#id()} attribute was not explicitly set, then the {@link Method#getName()}
|
||||
* is returned as the {@link Function#getId() Function ID}.
|
||||
*
|
||||
* @param method {@link GemfireFunction} annotated POJO {@link Method} containing the implementation
|
||||
* for a Pivotal GemFire/Apache Geode {@link Function}.
|
||||
* @return the Pivotal GemFire/Apache Geode Function ID of the given {@link Method}, or an empty {@link Optional}
|
||||
* if the {@link Method} is not a Pivotal GemFire/Apache Geode {@link Function}.
|
||||
* of the GemFire/Geode {@link Function}.
|
||||
* @return the GemFire/Geode {@link Function#getId() Function ID} of the given {@link Method},
|
||||
* or an empty {@link Optional} if the {@link Method} is not a GemFire/Geode {@link Function}.
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see java.lang.reflect.Method
|
||||
* @see #isGemfireFunction(Method)
|
||||
*/
|
||||
private static Optional<String> getGemfireFunctionId(Method method) {
|
||||
@SuppressWarnings("all")
|
||||
public static Optional<String> getGemfireFunctionId(Method method) {
|
||||
|
||||
return Optional.ofNullable(method)
|
||||
.filter(GemfireFunctionUtils::isGemfireFunction)
|
||||
.map(it ->
|
||||
Optional.of(it.getAnnotation(GemfireFunction.class))
|
||||
.map(annotation -> getAnnotationAttributes(it, annotation.getClass()))
|
||||
Optional.ofNullable(getAnnotationAttributes(it, GemfireFunction.class))
|
||||
.filter(annotationAttributes -> annotationAttributes.containsKey("id"))
|
||||
.map(annotationAttributes -> annotationAttributes.getString("id"))
|
||||
.filter(StringUtils::hasText)
|
||||
@@ -114,7 +138,8 @@ public abstract class GemfireFunctionUtils {
|
||||
.map(constructor -> BeanUtils.instantiateClass(constructor, constructorArguments))
|
||||
.orElseThrow(() -> newIllegalArgumentException(
|
||||
"No suitable constructor was found for type [%s] having parameters [%s]", type.getName(),
|
||||
stream(nullSafeArray(constructorArguments, Object.class)).map(ObjectUtils::nullSafeClassName)
|
||||
stream(nullSafeArray(constructorArguments, Object.class))
|
||||
.map(ObjectUtils::nullSafeClassName)
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
@@ -160,6 +185,7 @@ public abstract class GemfireFunctionUtils {
|
||||
* @see #registerFunctionForPojoMethod(Object, Method, AnnotationAttributes, boolean)
|
||||
* @see #isMatchingGemfireFunction(Method, String)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void registerFunctionForPojoMethod(Object target, String functionId) {
|
||||
|
||||
Assert.notNull(target, "Target object is required");
|
||||
@@ -183,6 +209,7 @@ public abstract class GemfireFunctionUtils {
|
||||
* @see #registerFunctionForPojoMethod(Object, Method, AnnotationAttributes, boolean)
|
||||
* @see #isGemfireFunction(Method)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void registerFunctionForPojoMethod(Object target, Method method, boolean overwrite) {
|
||||
|
||||
Assert.notNull(target, "Target object is required");
|
||||
@@ -206,48 +233,153 @@ public abstract class GemfireFunctionUtils {
|
||||
public static void registerFunctionForPojoMethod(Object target, Method method,
|
||||
AnnotationAttributes gemfireFunctionAttributes, boolean overwrite) {
|
||||
|
||||
String id = gemfireFunctionAttributes.containsKey("id")
|
||||
? gemfireFunctionAttributes.getString("id") : "";
|
||||
PojoFunctionWrapper function =
|
||||
new PojoFunctionWrapper(target, method, resolveFunctionId(gemfireFunctionAttributes));
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(target, method, id);
|
||||
configureBatchSize(target, method, gemfireFunctionAttributes, function);
|
||||
configureHighAvailability(gemfireFunctionAttributes, function);
|
||||
configureHasResult(gemfireFunctionAttributes, function);
|
||||
configureOptimizeForWrite(gemfireFunctionAttributes, function);
|
||||
configureRequiredPermissions(gemfireFunctionAttributes, function);
|
||||
|
||||
doFunctionRegistration(function, overwrite);
|
||||
}
|
||||
|
||||
static String resolveFunctionId(AnnotationAttributes gemfireFunctionAttributes) {
|
||||
|
||||
return gemfireFunctionAttributes.containsKey("id")
|
||||
? gemfireFunctionAttributes.getString("id")
|
||||
: DEFAULT_FUNCTION_ID;
|
||||
}
|
||||
|
||||
static void configureBatchSize(Object target, Method method, AnnotationAttributes gemfireFunctionAttributes,
|
||||
PojoFunctionWrapper function) {
|
||||
|
||||
if (gemfireFunctionAttributes.containsKey("batchSize")) {
|
||||
|
||||
int batchSize = gemfireFunctionAttributes.getNumber("batchSize");
|
||||
|
||||
Assert.isTrue(batchSize >= 0,
|
||||
String.format("batchSize [%1$d] specified on [%2$s.%3$s] must be a non-negative value",
|
||||
batchSize, target.getClass().getName(), method.getName()));
|
||||
String.format("%1$s.batchSize [%2$d] specified on [%3$s.%4$s] must be a non-negative value",
|
||||
GemfireFunction.class.getSimpleName(), batchSize, target.getClass().getName(), method.getName()));
|
||||
|
||||
function.setBatchSize(batchSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void configureHighAvailability(AnnotationAttributes gemfireFunctionAttributes,
|
||||
PojoFunctionWrapper function) {
|
||||
|
||||
if (gemfireFunctionAttributes.containsKey("HA")) {
|
||||
function.setHA(gemfireFunctionAttributes.getBoolean("HA"));
|
||||
}
|
||||
}
|
||||
|
||||
static void configureHasResult(AnnotationAttributes gemfireFunctionAttributes, PojoFunctionWrapper function) {
|
||||
|
||||
if (gemfireFunctionAttributes.containsKey("hasResult")) {
|
||||
if (Boolean.TRUE.equals(gemfireFunctionAttributes.getBoolean("hasResult"))) {
|
||||
function.setHasResult(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void configureOptimizeForWrite(AnnotationAttributes gemfireFunctionAttributes,
|
||||
PojoFunctionWrapper function) {
|
||||
|
||||
if (gemfireFunctionAttributes.containsKey("optimizeForWrite")) {
|
||||
function.setOptimizeForWrite(gemfireFunctionAttributes.getBoolean("optimizeForWrite"));
|
||||
}
|
||||
}
|
||||
|
||||
static void configureRequiredPermissions(AnnotationAttributes gemfireFunctionAttributes,
|
||||
PojoFunctionWrapper function) {
|
||||
|
||||
String[] requiredPermissionStrings = nullSafeArray(gemfireFunctionAttributes.containsKey("requiredPermissions")
|
||||
? gemfireFunctionAttributes.getStringArray("requiredPermissions")
|
||||
: null, String.class);
|
||||
|
||||
Stream<String> requiredPermissionsStream = Arrays.stream(requiredPermissionStrings);
|
||||
|
||||
Optional.of(requiredPermissionsStream
|
||||
.filter(StringUtils::hasText)
|
||||
.map(GemfireFunctionUtils::parseResourcePermission)
|
||||
.collect(Collectors.toList()))
|
||||
.filter(requiredPermissions -> !requiredPermissions.isEmpty())
|
||||
.ifPresent(function::setRequiredPermissions);
|
||||
}
|
||||
|
||||
static ResourcePermission parseResourcePermission(String resourcePermissionString) {
|
||||
|
||||
Assert.hasText(resourcePermissionString,
|
||||
String.format("ResourcePermission [%s] is required", resourcePermissionString));
|
||||
|
||||
ResourcePermission.Resource resource = ResourcePermission.Resource.DATA;
|
||||
ResourcePermission.Operation operation = ResourcePermission.Operation.WRITE;
|
||||
|
||||
String key = null;
|
||||
String target = null;
|
||||
|
||||
String[] resourcePermissionStringComponents = resourcePermissionString.split(":");
|
||||
|
||||
if (resourcePermissionStringComponents.length > 0) {
|
||||
resource = parseEnum(resourcePermissionStringComponents[0], ResourcePermission.Resource.class,
|
||||
ResourcePermission.Resource.values());
|
||||
}
|
||||
if (resourcePermissionStringComponents.length > 1) {
|
||||
operation = parseEnum(resourcePermissionStringComponents[1], ResourcePermission.Operation.class,
|
||||
ResourcePermission.Operation.values());
|
||||
}
|
||||
if (resourcePermissionStringComponents.length > 2) {
|
||||
target = nullSafeTrim(resourcePermissionStringComponents[2]);
|
||||
}
|
||||
if (resourcePermissionStringComponents.length > 3) {
|
||||
key = nullSafeTrim(resourcePermissionStringComponents[3]);
|
||||
}
|
||||
|
||||
return new ResourcePermission(resource, operation, target, key);
|
||||
}
|
||||
|
||||
private static String nullSafeToUpperCase(String value) {
|
||||
return StringUtils.hasText(value) ? value.trim().toUpperCase() : "null";
|
||||
}
|
||||
|
||||
private static String nullSafeTrim(String value) {
|
||||
return value != null ? value.trim() : null;
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> T parseEnum(String name, Class<T> enumType, Enum[] enumeratedValues) {
|
||||
|
||||
name = nullSafeToUpperCase(name);
|
||||
|
||||
try {
|
||||
return Enum.valueOf(enumType, name);
|
||||
}
|
||||
catch (IllegalArgumentException cause) {
|
||||
throw newIllegalArgumentException(cause, "[%1$s] is not a valid [%2$s] type; must be 1 of %3$s",
|
||||
name, enumType.getName(), Arrays.toString(enumeratedValues));
|
||||
}
|
||||
}
|
||||
|
||||
static void doFunctionRegistration(PojoFunctionWrapper function, boolean overwrite) {
|
||||
|
||||
if (FunctionService.isRegistered(function.getId())) {
|
||||
if (overwrite) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Unregistering Function [%s]", function.getId()));
|
||||
log.debug(String.format("Overwrite enabled; Unregistering Function [%s]", function.getId()));
|
||||
}
|
||||
|
||||
FunctionService.unregisterFunction(function.getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (!FunctionService.isRegistered(function.getId())) {
|
||||
if (FunctionService.isRegistered(function.getId())) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Function [%s] is already registered", function.getId()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
FunctionService.registerFunction(function);
|
||||
|
||||
@@ -255,11 +387,6 @@ public abstract class GemfireFunctionUtils {
|
||||
log.debug(String.format("Registered Function [%s]", function.getId()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Function [%s] is already registered", function.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
*/
|
||||
package org.springframework.data.gemfire.function;
|
||||
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -20,6 +24,8 @@ 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.ResultSender;
|
||||
import org.apache.geode.management.internal.security.ResourcePermissions;
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -52,6 +58,8 @@ public class PojoFunctionWrapper implements Function {
|
||||
|
||||
private volatile int batchSize;
|
||||
|
||||
private Collection<ResourcePermission> requiredPermissions = asSet(ResourcePermissions.DATA_WRITE);
|
||||
|
||||
private final FunctionArgumentResolver functionArgumentResolver;
|
||||
|
||||
private final Method method;
|
||||
@@ -60,21 +68,41 @@ public class PojoFunctionWrapper implements Function {
|
||||
|
||||
private final String id;
|
||||
|
||||
public PojoFunctionWrapper(Object target, Method method) {
|
||||
this(target, method, null);
|
||||
}
|
||||
|
||||
public PojoFunctionWrapper(Object target, Method method, String id) {
|
||||
|
||||
this.target = target;
|
||||
this.method = method;
|
||||
this.id = StringUtils.hasText(id) ? id : method.getName();
|
||||
this.functionArgumentResolver = new FunctionContextInjectingArgumentResolver(method);
|
||||
this.id = resolveId(method, id);
|
||||
this.functionArgumentResolver = newFunctionArgumentResolver(method);
|
||||
this.HA = false;
|
||||
this.hasResult = !method.getReturnType().equals(void.class);
|
||||
this.hasResult = resolveHasResult(method);
|
||||
this.optimizeForWrite = false;
|
||||
}
|
||||
|
||||
protected FunctionArgumentResolver newFunctionArgumentResolver(Method method) {
|
||||
return new FunctionContextInjectingArgumentResolver(method);
|
||||
}
|
||||
|
||||
protected boolean resolveHasResult(Method method) {
|
||||
return !method.getReturnType().equals(void.class);
|
||||
}
|
||||
|
||||
protected String resolveId(Method method, String id) {
|
||||
return StringUtils.hasText(id) ? id : method.getName();
|
||||
}
|
||||
|
||||
public void setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return this.batchSize;
|
||||
}
|
||||
|
||||
public void setHA(boolean HA) {
|
||||
this.HA = HA;
|
||||
}
|
||||
@@ -107,6 +135,15 @@ public class PojoFunctionWrapper implements Function {
|
||||
return this.optimizeForWrite;
|
||||
}
|
||||
|
||||
public void setRequiredPermissions(Collection<ResourcePermission> requiredPermissions) {
|
||||
this.requiredPermissions = requiredPermissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourcePermission> getRequiredPermissions(String regionName) {
|
||||
return Collections.unmodifiableCollection(this.requiredPermissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute(FunctionContext functionContext) {
|
||||
|
||||
@@ -17,37 +17,33 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.execute.ResultSender;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to declare a concrete method as a Pivotal GemFire function implementation
|
||||
* Used to declare a concrete method as a Pivotal GemFire {@link Function} implementation.
|
||||
*
|
||||
* @author David Turanski
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface GemfireFunction {
|
||||
|
||||
String DEFAULT_RESOURCE_PERMISSION = "DATA:WRITE";
|
||||
|
||||
/**
|
||||
* The name of the registered function. If not provided the simple method name will be used
|
||||
* @return the function id
|
||||
* The {@link String name} of the registered {@link Function}.
|
||||
*
|
||||
* If not provided the simple {@link String method name} will be used.
|
||||
*
|
||||
* @return the {@link Function} {@link Function#getId() id}.
|
||||
* @see org.apache.geode.cache.execute.Function#getId()
|
||||
*/
|
||||
String id() default "";
|
||||
|
||||
/**
|
||||
* Attribute to determine whether the Pivotal GemFire Function is HA (Highly Available).
|
||||
*
|
||||
* @return a boolean value indicating whether the defined Pivotal GemFire Function is HA.
|
||||
*/
|
||||
boolean HA() default false;
|
||||
|
||||
/**
|
||||
* Attribute to determine whether the Pivotal GemFire Function is optimized for write operations.
|
||||
*
|
||||
* @return a boolean value indicating if the Pivotal GemFire Function is configured for optimized write operations.
|
||||
*/
|
||||
boolean optimizeForWrite() default false;
|
||||
|
||||
/**
|
||||
* Controls the maximum number of results sent at one time.
|
||||
*
|
||||
@@ -56,11 +52,31 @@ public @interface GemfireFunction {
|
||||
int batchSize() default 0;
|
||||
|
||||
/**
|
||||
* Normally follows the method return type, i.e., false if void, true otherwise. This allows overriding
|
||||
* a void method which uses the resultSender directly.
|
||||
* Attribute used to configure whether the {@link Function} is HA (Highly Available).
|
||||
*
|
||||
* @return a boolean value indicating if the Pivotal GemFire Function is expected to return a result.
|
||||
* @return a boolean value configuring whether the defined {@link Function} is HA.
|
||||
* @see org.apache.geode.cache.execute.Function#isHA()
|
||||
*/
|
||||
boolean HA() default false;
|
||||
|
||||
/**
|
||||
* Normally follows the method return type, i.e. {@literal false} if {@code void}, {@literal true} otherwise.
|
||||
*
|
||||
* This allows overriding a {@code void} method which uses the {@link ResultSender} directly.
|
||||
*
|
||||
* @return a boolean value indicating if the {@link Function} is expected to return a result.
|
||||
* @see org.apache.geode.cache.execute.Function#hasResult()
|
||||
*/
|
||||
boolean hasResult() default false;
|
||||
|
||||
/**
|
||||
* Attribute to configure whether the {@link Function} is optimized for write operations.
|
||||
*
|
||||
* @return a boolean value indicating if the {@link Function} is configured for optimized write operations.
|
||||
* @see org.apache.geode.cache.execute.Function#optimizeForWrite()
|
||||
*/
|
||||
boolean optimizeForWrite() default false;
|
||||
|
||||
String[] requiredPermissions() default { DEFAULT_RESOURCE_PERMISSION };
|
||||
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@ package org.springframework.data.gemfire.function.config;
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
@@ -28,17 +30,21 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Spring {@link BeanPostProcessor} that discovers bean components wired as Function implementations,
|
||||
* i.e. beans containing methods annotated with {@link GemfireFunction}.
|
||||
* Spring {@link BeanPostProcessor} that discovers bean components configured as {@link Function} implementations,
|
||||
* i.e. beans containing {@link Method methods} annotated with {@link GemfireFunction}.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see java.lang.annotation.Annotation
|
||||
* @see java.lang.reflect.Method
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
*/
|
||||
public class GemfireFunctionBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@@ -61,11 +67,17 @@ public class GemfireFunctionBeanPostProcessor implements BeanPostProcessor {
|
||||
String.format("The bean [%s] method [%s] annotated with [%s] must be public",
|
||||
bean.getClass().getName(), method.getName(), GemfireFunction.class.getName()));
|
||||
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(
|
||||
AnnotationUtils.getAnnotationAttributes(gemfireFunctionAnnotation,false,true));
|
||||
AnnotationAttributes gemfireFunctionAttributes = resolveAnnotationAttributes(gemfireFunctionAnnotation);
|
||||
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(bean, method, annotationAttributes, false);
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(bean, method,
|
||||
gemfireFunctionAttributes, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private AnnotationAttributes resolveAnnotationAttributes(Annotation annotation) {
|
||||
|
||||
return AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(annotation,
|
||||
false, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ public class GemfireFunctionBeanPostProcessorRegistrar implements ImportBeanDefi
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(GemfireFunctionBeanPostProcessor.class);
|
||||
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(GemfireFunctionBeanPostProcessor.class);
|
||||
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.annotation.Annotation;
|
||||
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.execute.FunctionService;
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
import org.springframework.data.gemfire.function.config.EnableGemfireFunctions;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration tests testing the registration of Apache Geode/Pivotal GemFire {@link Function Functions}
|
||||
* with required permissions specified using the {@link GemfireFunction} {@link Annotation}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see org.springframework.data.gemfire.function.config.EnableGemfireFunctions
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
public class FunctionWithRequiredPermissionsRegistrationIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void functionsRegisteredWithRequiredPermissionsSuccessfully() {
|
||||
|
||||
Function function = FunctionService.getFunction("testFunctionWithRequiredPermissions");
|
||||
|
||||
assertThat(function).isNotNull();
|
||||
assertThat(function.getRequiredPermissions("test")).containsExactly(
|
||||
new ResourcePermission(ResourcePermission.Resource.CLUSTER, ResourcePermission.Operation.MANAGE),
|
||||
new ResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.READ, "Example")
|
||||
);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGemfireFunctions
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
TestFunctions testFunctions() {
|
||||
return new TestFunctions();
|
||||
}
|
||||
}
|
||||
|
||||
static class TestFunctions {
|
||||
|
||||
@GemfireFunction(requiredPermissions = { "CLUSTER:MANAGE", "DATA:READ:Example" })
|
||||
public void testFunctionWithRequiredPermissions() { }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* 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 java.util.Arrays;
|
||||
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GemfireFunctionUtils}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.function.GemfireFunctionUtils
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GemfireFunctionUtilsUnitTests {
|
||||
|
||||
private final TestFunctions testFunctions = new TestFunctions();
|
||||
|
||||
private ResourcePermission newResourcePermission(ResourcePermission.Resource resource,
|
||||
ResourcePermission.Operation operation, ResourcePermission.Target target, String key) {
|
||||
|
||||
return new ResourcePermission(resource, operation, target.name(), key);
|
||||
}
|
||||
|
||||
private ResourcePermission newResourcePermission(ResourcePermission.Resource resource,
|
||||
ResourcePermission.Operation operation, String target, String key) {
|
||||
|
||||
return new ResourcePermission(resource, operation, target, key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gemfireFunctionAnnotatedMethodIsGemFireFunction() throws Exception {
|
||||
assertThat(GemfireFunctionUtils.isGemfireFunction(TestFunctions.class.getDeclaredMethod("testFunction")))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonGemfireFunctionAnnotatedMethodIsNotGemFireFunction() throws Exception {
|
||||
assertThat(GemfireFunctionUtils.isGemfireFunction(TestFunctions.class.getDeclaredMethod("nonFunction")))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchingGemFireFunctionReturnsTrue() throws Exception {
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("identifiedFunction"), "MyFunction")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonMatchingGemFireFunctionReturnsFalse() throws Exception {
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("identifiedFunction"), "YourFunction"))
|
||||
.isFalse();
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("nonFunction"), "nonFunction"))
|
||||
.isFalse();
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("requiredPermissionsFunction"), "MyFunction"))
|
||||
.isFalse();
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("testFunction"), "MockFunction"))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvesFunctionIdFromGemfireFunctionIdAttribute() {
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes = new AnnotationAttributes();
|
||||
|
||||
gemfireFunctionAttributes.put("id", "2");
|
||||
|
||||
assertThat(GemfireFunctionUtils.resolveFunctionId(gemfireFunctionAttributes)).isEqualTo("2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unresolvableFunctionIdReturnsNull() {
|
||||
assertThat(GemfireFunctionUtils.resolveFunctionId(new AnnotationAttributes())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithBatchSize() throws Exception {
|
||||
|
||||
Method functionWithBatchSize = TestFunctions.class.getDeclaredMethod("functionWithBatchSize");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithBatchSize, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithBatchSize);
|
||||
|
||||
GemfireFunctionUtils.configureBatchSize(this.testFunctions, functionWithBatchSize,
|
||||
gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getBatchSize()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void configureWithInvalidBatchSizeThrowsIllegalArgumentException() throws Exception {
|
||||
|
||||
Method functionWithInvalidBatchSize =
|
||||
TestFunctions.class.getDeclaredMethod("functionWithInvalidBatchSize");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithInvalidBatchSize, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithInvalidBatchSize);
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.configureBatchSize(this.testFunctions, functionWithInvalidBatchSize,
|
||||
gemfireFunctionAttributes, function);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("GemfireFunction.batchSize [-5] specified on [%1$s.%2$s] must be a non-negative value",
|
||||
testFunctions.getClass().getName(), functionWithInvalidBatchSize.getName());
|
||||
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoBatchSize() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureBatchSize(this.testFunctions, testFunction, gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getBatchSize()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithHighAvailability() throws Exception {
|
||||
|
||||
Method functionWithHighAvailability = TestFunctions.class.getDeclaredMethod("functionWithHighAvailability");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithHighAvailability, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithHighAvailability);
|
||||
|
||||
GemfireFunctionUtils.configureHighAvailability(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.isHA()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoHighAvailability() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureHighAvailability(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.isHA()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithResult() throws Exception {
|
||||
|
||||
Method functionWithResult = TestFunctions.class.getDeclaredMethod("functionWithResult");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithResult, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithResult);
|
||||
|
||||
GemfireFunctionUtils.configureHasResult(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.hasResult()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoResult() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureHasResult(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.hasResult()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithOptimizeForWrite() throws Exception {
|
||||
|
||||
Method functionOptimizedForWrite = TestFunctions.class.getDeclaredMethod("functionOptimizedForWrite");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionOptimizedForWrite, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionOptimizedForWrite);
|
||||
|
||||
GemfireFunctionUtils.configureOptimizeForWrite(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.optimizeForWrite()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoOptimizeForWrite() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureOptimizeForWrite(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.optimizeForWrite()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cofigureWithDefaultRequiredPermissions() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureRequiredPermissions(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getRequiredPermissions("test")).containsExactly(
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.WRITE, (String) null, null)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithRequiredPermissions() throws Exception {
|
||||
|
||||
Method requiredPermissionsFunction = TestFunctions.class.getDeclaredMethod("requiredPermissionsFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(requiredPermissionsFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, requiredPermissionsFunction);
|
||||
|
||||
GemfireFunctionUtils.configureRequiredPermissions(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getRequiredPermissions("Example")).containsExactly(
|
||||
newResourcePermission(ResourcePermission.Resource.CLUSTER, ResourcePermission.Operation.MANAGE, (String) null, null),
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.MANAGE, "System", null),
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.READ, ResourcePermission.Target.QUERY, "ALL"),
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.WRITE, "Example", "123")
|
||||
);
|
||||
}
|
||||
|
||||
public void testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException(
|
||||
String resourcePermissionString) {
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.parseResourcePermission(resourcePermissionString);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("ResourcePermission [%s] is required", resourcePermissionString);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithNullStringThrowsIllegalArgumentException() {
|
||||
testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithEmptyStringThrowsIllegalArgumentException() {
|
||||
testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException("");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithBlankStringThrowsIllegalArgumentException() {
|
||||
testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException(" ");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithInvalidResourceThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.parseResourcePermission("SOCKET:OPEN");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("[SOCKET] is not a valid [%1$s] type; must be 1 of %2$s",
|
||||
ResourcePermission.Resource.class.getName(), Arrays.toString(ResourcePermission.Resource.values()));
|
||||
|
||||
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithInvalidOperationThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.parseResourcePermission("DATA:COPY");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("[COPY] is not a valid [%1$s] type; must be 1 of %2$s",
|
||||
ResourcePermission.Operation.class.getName(), Arrays.toString(ResourcePermission.Operation.values()));
|
||||
|
||||
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourcePermissionIsSuccessful() {
|
||||
|
||||
ResourcePermission resourcePermission =
|
||||
GemfireFunctionUtils.parseResourcePermission("CLUSTER:MANAGE");
|
||||
|
||||
assertThat(resourcePermission).isNotNull();
|
||||
assertThat(resourcePermission.getResource()).isEqualTo(ResourcePermission.Resource.CLUSTER);
|
||||
assertThat(resourcePermission.getOperation()).isEqualTo(ResourcePermission.Operation.MANAGE);
|
||||
}
|
||||
|
||||
static class TestFunctions {
|
||||
|
||||
@GemfireFunction(batchSize = 10)
|
||||
void functionWithBatchSize() { }
|
||||
|
||||
@GemfireFunction(batchSize = -5)
|
||||
void functionWithInvalidBatchSize() { }
|
||||
|
||||
@GemfireFunction(HA = true)
|
||||
void functionWithHighAvailability() { }
|
||||
|
||||
@GemfireFunction(hasResult = true)
|
||||
void functionWithResult() { }
|
||||
|
||||
@GemfireFunction(optimizeForWrite = true)
|
||||
void functionOptimizedForWrite() { }
|
||||
|
||||
@GemfireFunction(id = "MyFunction")
|
||||
void identifiedFunction() { }
|
||||
|
||||
void nonFunction() { }
|
||||
|
||||
@GemfireFunction(requiredPermissions = {
|
||||
"CLUSTER:MANAGE",
|
||||
"DATA:MANAGE:System",
|
||||
"DATA:READ:QUERY:ALL",
|
||||
"DATA:WRITE:Example:123"
|
||||
})
|
||||
void requiredPermissionsFunction() { }
|
||||
|
||||
@GemfireFunction
|
||||
void testFunction() { }
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user