Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2017 Red Hat, Inc, and individual contributors.
*
* 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 io.smallrye.faulttolerance.config;
import static java.util.Arrays.asList;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
// this must be kept identical to io.smallrye.faulttolerance.SecurityActions
/**
* @author Martin Kouba
*/
final class SecurityActions {
private SecurityActions() {
}
static Method getAnnotationMethod(Class> clazz, String name) throws PrivilegedActionException, NoSuchMethodException {
if (System.getSecurityManager() == null) {
return clazz.getMethod(name);
}
return AccessController.doPrivileged((PrivilegedExceptionAction) () -> clazz.getMethod(name));
}
static Field getDeclaredField(Class> clazz, String name) throws NoSuchFieldException, PrivilegedActionException {
if (System.getSecurityManager() == null) {
return clazz.getDeclaredField(name);
}
return AccessController.doPrivileged((PrivilegedExceptionAction) () -> clazz.getDeclaredField(name));
}
static void setAccessible(final AccessibleObject accessibleObject) {
if (System.getSecurityManager() == null) {
accessibleObject.setAccessible(true);
}
AccessController.doPrivileged((PrivilegedAction) () -> {
accessibleObject.setAccessible(true);
return accessibleObject;
});
}
/**
* Get method of a given name from beanClass or one of its super-classes or interfaces.
* The method should have the same parameter types as a method it is intended to be a fallback for (let's call it the
* original method). The original method can be defined in a superclass and have parameter types provided with generics.
*
* @param beanClass the class of the bean that we search for the method for
* @param declaringClass the class that defines the method that we search for a counterpart for
* @param name name of the method
* @param parameterTypes parameters of the method
* @return the method in search
* @throws PrivilegedActionException
*/
static Method getDeclaredMethod(Class> beanClass, Class> declaringClass, String name, Type[] parameterTypes)
throws PrivilegedActionException {
if (System.getSecurityManager() == null) {
return doGetMethod(beanClass, declaringClass, name, parameterTypes);
}
return AccessController.doPrivileged(
(PrivilegedExceptionAction) () -> doGetMethod(beanClass, declaringClass, name, parameterTypes));
}
private static Method doGetMethod(final Class> beanClass, final Class> declaringClass, String name,
Type[] expectedParameters) {
Method method;
Class> current = beanClass;
ParametrizedParamsTranslator expectedParamsTranslator = prepareParamsTranslator(beanClass, declaringClass);
ParametrizedParamsTranslator actualParamsTranslator = new ParametrizedParamsTranslator();
// gather all interface methods based on declaring class
Set allInterfaceMethodNames = new HashSet<>();
for (Class> clazz : declaringClass.getInterfaces()) {
for (Method m : clazz.getMethods()) {
allInterfaceMethodNames.add(m.getName());
}
}
while (true) {
method = getMethodFromClass(beanClass, current, name, expectedParameters, actualParamsTranslator,
expectedParamsTranslator);
// fault tolerance spec is in 8.1.2; fallback method must be from same class, superclass, implemented interface
if (method != null
&& (current.isAssignableFrom(declaringClass) || allInterfaceMethodNames.contains(method.getName()))) {
return method;
} else {
if (current.getSuperclass() == null) {
break;
}
actualParamsTranslator = actualParamsTranslator.getSuperclassTranslator(current);
current = current.getSuperclass();
}
}
for (Class> anInterface : beanClass.getInterfaces()) {
method = getMethodFromClass(beanClass, anInterface, name, expectedParameters, actualParamsTranslator,
expectedParamsTranslator);
if (method != null) {
return method;
}
}
return null;
}
/**
* Bean class can be a sub-class of the class that defines the method.
* This method prepares a translator for the eventual generic types of the method
* to the types provided on the beanClass or any class between it and the class declaring the method
*
* @param beanClass class of the bean for which the fallback method has been declared
* @param clazz class that declares the method
* @return translator
*/
private static ParametrizedParamsTranslator prepareParamsTranslator(Class> beanClass, Class> clazz) {
ParametrizedParamsTranslator result = new ParametrizedParamsTranslator();
if (beanClass == clazz) {
return result;
}
Class> current = beanClass;
while (current != clazz && current != null) {
if (current.getSuperclass() == null) {
break;
}
result = result.getSuperclassTranslator(current);
current = current.getSuperclass();
}
return result;
}
private static List incomingTypesForSuperclass(Class> current, List typeParameters,
List incomingTypes) {
Type genericSuperclass = current.getGenericSuperclass();
List actualTypeParams = (genericSuperclass instanceof ParameterizedType)
? asList(((ParameterizedType) genericSuperclass).getActualTypeArguments())
: Collections.emptyList();
List result = new ArrayList<>(actualTypeParams.size());
for (Type type : actualTypeParams) {
if (type instanceof Class) {
result.add(type);
} else {
int paramIdx = typeParameters.indexOf(type);
result.add(paramIdx >= 0 ? incomingTypes.get(paramIdx) : type);
}
}
return result;
}
private static Method getMethodFromClass(Class> originatingClass,
Class> clazz, String name,
Type[] parameterTypes,
ParametrizedParamsTranslator translator,
ParametrizedParamsTranslator expectedParamsTranslator) {
Optional maybeMethod = Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> isAccessibleFrom(method, originatingClass))
.filter(method -> method.getName().equals(name))
.filter(parametersMatch(parameterTypes, translator, expectedParamsTranslator))
.findAny();
return maybeMethod.orElse(null);
}
private static boolean isAccessibleFrom(Method method, Class> originatingClass) {
if (isAccessible(method, Modifier.PUBLIC) || isAccessible(method, Modifier.PROTECTED)) {
return true;
}
if (isAccessible(method, Modifier.PRIVATE)) {
return method.getDeclaringClass() == originatingClass;
}
// not public and not protected and not private => default
// accessible only if in the same package
return method.getDeclaringClass().getPackage() == originatingClass.getPackage();
}
private static boolean isAccessible(Method method, int accessLevel) {
return (method.getModifiers() & accessLevel) != 0;
}
private static Predicate super Method> parametersMatch(Type[] parameterTypes,
ParametrizedParamsTranslator translator,
ParametrizedParamsTranslator expectedParamsTranslator) {
return method -> {
Type[] methodParams = method.getGenericParameterTypes();
if (parameterTypes.length != methodParams.length) {
return false;
}
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterMatches(methodParams[i], parameterTypes[i], translator, expectedParamsTranslator)) {
return false;
}
}
return true;
};
}
private static boolean parameterMatches(Type methodParam,
Type parameterType,
ParametrizedParamsTranslator translator,
ParametrizedParamsTranslator expectedParamsTranslator) {
methodParam = translator.translate(methodParam);
parameterType = expectedParamsTranslator.translate(parameterType);
if (methodParam instanceof Class) {
return parameterType == methodParam;
} else {
if (isArray(parameterType)) { // unwrap array
if (isArray(methodParam)) {
Type methodParamComponentType = getArrayComponentType(methodParam);
Type componentType = getArrayComponentType(parameterType);
return parameterMatches(methodParamComponentType, componentType, translator, expectedParamsTranslator);
} else {
return false;
}
}
if (methodParam instanceof ParameterizedType) {
if (parameterType instanceof ParameterizedType) {
return parameterizedTypeMatches((ParameterizedType) methodParam, (ParameterizedType) parameterType,
translator, expectedParamsTranslator);
} else {
return false;
}
}
if (methodParam instanceof WildcardType) {
if (parameterType instanceof WildcardType) {
return wildcardTypeMatches((WildcardType) methodParam, (WildcardType) parameterType, translator,
expectedParamsTranslator);
} else {
return false;
}
}
return false;
}
}
private static boolean wildcardTypeMatches(WildcardType methodParam,
WildcardType parameterType,
ParametrizedParamsTranslator translator,
ParametrizedParamsTranslator expectedParamsTranslator) {
boolean lowerBoundsMatch = typeArrayMatches(methodParam.getLowerBounds(), parameterType.getLowerBounds(), translator,
expectedParamsTranslator);
boolean upperBoundsMatch = typeArrayMatches(methodParam.getUpperBounds(), parameterType.getUpperBounds(), translator,
expectedParamsTranslator);
return lowerBoundsMatch && upperBoundsMatch;
}
private static boolean typeArrayMatches(Type[] methodTypes,
Type[] paramTypes,
ParametrizedParamsTranslator translator,
ParametrizedParamsTranslator expectedParamsTranslator) {
if (methodTypes.length != paramTypes.length) {
return false;
}
for (int i = 0; i < methodTypes.length; i++) {
if (!parameterMatches(methodTypes[i], paramTypes[i], translator, expectedParamsTranslator)) {
return false;
}
}
return true;
}
private static boolean parameterizedTypeMatches(ParameterizedType methodParam,
ParameterizedType parameterType,
ParametrizedParamsTranslator translator,
ParametrizedParamsTranslator expectedParamsTranslator) {
Type[] methodParameters = methodParam.getActualTypeArguments();
Type[] actualParameters = parameterType.getActualTypeArguments();
if (methodParameters.length != actualParameters.length) {
return false;
}
for (int i = 0; i < methodParameters.length; i++) {
if (!parameterMatches(methodParameters[i], actualParameters[i], translator, expectedParamsTranslator)) {
return false;
}
}
return true;
}
/**
* Accepts only Classes of arrays and GenericArrayType subclasses
*
* @param parameterType
* @return
*/
private static Type getArrayComponentType(Type parameterType) {
if (parameterType instanceof Class) {
return ((Class>) parameterType).getComponentType();
} else {
return ((GenericArrayType) parameterType).getGenericComponentType();
}
}
private static boolean isArray(Type parameterType) {
if (parameterType instanceof Class) {
return ((Class>) parameterType).isArray();
} else {
return parameterType instanceof GenericArrayType;
}
}
static Method[] getDeclaredMethods(Class> clazz) throws PrivilegedActionException {
if (System.getSecurityManager() == null) {
return clazz.getDeclaredMethods();
}
return AccessController.doPrivileged((PrivilegedExceptionAction) clazz::getDeclaredMethods);
}
private static class ParametrizedParamsTranslator {
private final List incomingTypes = new ArrayList<>();
private final List typeParameters = new ArrayList<>();
Type translate(Type paramType) {
int typeIdx = typeParameters.indexOf(paramType);
if (typeIdx >= 0) {
paramType = incomingTypes.get(typeIdx);
}
return paramType;
}
ParametrizedParamsTranslator getSuperclassTranslator(Class> current) {
ParametrizedParamsTranslator result = new ParametrizedParamsTranslator();
result.incomingTypes.addAll(incomingTypesForSuperclass(current, typeParameters, incomingTypes));
result.typeParameters.addAll(asList(current.getSuperclass().getTypeParameters()));
return result;
}
}
}