com.infomaximum.cluster.graphql.executor.component.GraphQLComponentExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cluster-graphql Show documentation
Show all versions of cluster-graphql Show documentation
Library for creating a light cluster
The newest version!
package com.infomaximum.cluster.graphql.executor.component;
import com.infomaximum.cluster.core.remote.struct.RemoteObject;
import com.infomaximum.cluster.graphql.anotation.GraphQLName;
import com.infomaximum.cluster.graphql.anotation.GraphQLSource;
import com.infomaximum.cluster.graphql.anotation.GraphQLTypeInput;
import com.infomaximum.cluster.graphql.exception.GraphQLExecutorDataFetcherException;
import com.infomaximum.cluster.graphql.exception.GraphQLExecutorException;
import com.infomaximum.cluster.graphql.exception.GraphQLExecutorInvalidSyntaxException;
import com.infomaximum.cluster.graphql.fieldargument.custom.CustomFieldArgument;
import com.infomaximum.cluster.graphql.preparecustomfield.PrepareCustomField;
import com.infomaximum.cluster.graphql.schema.GraphQLSchemaType;
import com.infomaximum.cluster.graphql.schema.build.graphqltype.TypeGraphQLBuilder;
import com.infomaximum.cluster.graphql.schema.build.graphqltype.TypeGraphQLFieldConfigurationBuilder;
import com.infomaximum.cluster.graphql.schema.scalartype.GraphQLTypeScalar;
import com.infomaximum.cluster.graphql.schema.struct.RGraphQLType;
import com.infomaximum.cluster.graphql.struct.ContextRequest;
import com.infomaximum.cluster.graphql.struct.GOptional;
import com.infomaximum.cluster.graphql.struct.GRequest;
import com.infomaximum.cluster.graphql.struct.GSubscribeEvent;
import com.infomaximum.cluster.graphql.utils.ReflectionUtils;
import com.infomaximum.cluster.graphql.utils.Utils;
import com.infomaximum.cluster.struct.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
public class GraphQLComponentExecutor {
private final static Logger log = LoggerFactory.getLogger(GraphQLComponentExecutor.class);
private final GraphQLSchemaType graphQLSchemaType;
private ArrayList rTypeGraphQLs;
private Map classSchemas;
public GraphQLComponentExecutor(Component component, TypeGraphQLFieldConfigurationBuilder fieldConfigurationBuilder, GraphQLSchemaType graphQLSchemaType) throws GraphQLExecutorException {
this.graphQLSchemaType = graphQLSchemaType;
TypeGraphQLBuilder typeGraphQLBuilder = new TypeGraphQLBuilder(component, graphQLSchemaType)
.withFieldConfigurationBuilder(fieldConfigurationBuilder);
build(typeGraphQLBuilder);
}
public GraphQLComponentExecutor(String packageName, TypeGraphQLFieldConfigurationBuilder fieldConfigurationBuilder, GraphQLSchemaType graphQLSchemaType) throws GraphQLExecutorException {
this.graphQLSchemaType = graphQLSchemaType;
TypeGraphQLBuilder typeGraphQLBuilder = new TypeGraphQLBuilder(packageName, graphQLSchemaType)
.withFieldConfigurationBuilder(fieldConfigurationBuilder);
build(typeGraphQLBuilder);
}
private void build(TypeGraphQLBuilder typeGraphQLBuilder) throws GraphQLExecutorException {
Map rTypeGraphQLItems = typeGraphQLBuilder.build();
rTypeGraphQLs = new ArrayList<>(typeGraphQLBuilder.build().values());
classSchemas = new HashMap();
for (Map.Entry entryTypeGraphQL : rTypeGraphQLItems.entrySet()) {
Class classRTypeGraphQL = entryTypeGraphQL.getKey();
RGraphQLType rGraphQLType = entryTypeGraphQL.getValue();
if (classSchemas.containsKey(rGraphQLType.getName()))
throw new RuntimeException("not unique query schema: " + rGraphQLType.getName());
classSchemas.put(rGraphQLType.getName(), classRTypeGraphQL);
}
}
public ArrayList getGraphQLTypes() {
return rTypeGraphQLs;
}
public Serializable prepare(Component component, String keyField, String graphQLTypeName, String graphQLTypeFieldName, Map arguments, ContextRequest context) throws GraphQLExecutorDataFetcherException {
Object prepareResultObject = executeGraphQLMethod(null, graphQLTypeName, graphQLTypeFieldName, arguments, context);
if (prepareResultObject == null) {
throw new GraphQLExecutorException("Class: " + classSchemas.get(graphQLTypeName) + ", method: " + graphQLTypeFieldName + " returning is null prepare object");
}
for (PrepareCustomField prepareCustomField : graphQLSchemaType.prepareCustomFields) {
if (prepareCustomField.isSupport(prepareResultObject.getClass())) {
return prepareCustomField.requestPrepare(component, keyField, prepareResultObject, context);
}
}
throw new GraphQLExecutorException("Not found prepare handler for: " + prepareResultObject);
}
public Serializable executePrepare(String keyField, RemoteObject source, ContextRequest context) {
if (graphQLSchemaType.prepareCustomFields.size() != 1)
throw new RuntimeException("Not implemented support many prepareCustomFields");
PrepareCustomField prepareCustomField = graphQLSchemaType.prepareCustomFields.iterator().next();
return prepareCustomField.execute(keyField, source, context);
}
public Serializable execute(RemoteObject source, String graphQLTypeName, String graphQLTypeFieldName, Map arguments, ContextRequest context) throws GraphQLExecutorDataFetcherException {
Object result = executeGraphQLMethod(source, graphQLTypeName, graphQLTypeFieldName, arguments, context);
if (result instanceof GSubscribeEvent) {
return ((GSubscribeEvent) result).getSubscribeValue();
} else {
return (Serializable) result;
}
}
private Object executeGraphQLMethod(Object source, String graphQLTypeName, String graphQLTypeFieldName, Map arguments, ContextRequest context) throws GraphQLExecutorDataFetcherException {
try {
Method method = getMethod(graphQLTypeName, graphQLTypeFieldName);
Class classSchema = classSchemas.get(graphQLTypeName);
Object object = null;
if (source == null || classSchema.isAssignableFrom(source.getClass())) {
object = source;
} else if (source instanceof Optional) {
//Подписки возврощаются в обертках, т.к. null плохо работает с подписками
object = ((Optional) source).get();
}
Class[] methodParameterTypes = method.getParameterTypes();
Annotation[][] parametersAnnotations = method.getParameterAnnotations();
Object[] methodParameters = new Object[methodParameterTypes.length];
for (int index = 0; index < methodParameters.length; index++) {
//Собираем аннотации
GraphQLSource aGraphQLTarget = null;
GraphQLName graphQLAnnotation = null;
for (Annotation annotation : parametersAnnotations[index]) {
if (annotation.annotationType() == GraphQLSource.class) {
aGraphQLTarget = (GraphQLSource) annotation;
} else if (annotation.annotationType() == GraphQLName.class) {
graphQLAnnotation = (GraphQLName) annotation;
}
}
Object argumentValue = null;
if (aGraphQLTarget != null) {
argumentValue = source;
} else if (graphQLAnnotation != null) {
String argumentName = graphQLAnnotation.value();
boolean isPresent = arguments.containsKey(argumentName);
argumentValue = getInputValue(method.getGenericParameterTypes()[index], arguments.get(argumentName), isPresent);
} else {
//возможно особый аргумент
Class classType = methodParameterTypes[index];
if (GRequest.class.isAssignableFrom(classType)) {
argumentValue = context.getRequest();
} else {
boolean isSuccessFindEnvironment = false;
if (graphQLSchemaType != null) {
for (CustomFieldArgument customArgument : graphQLSchemaType.customArguments) {
if (customArgument.isSupport(classType)) {
argumentValue = customArgument.getValue(classType, method, context);
isSuccessFindEnvironment = true;
}
}
}
if (!isSuccessFindEnvironment) {
throw new RuntimeException("Nothing argument type: " + classType + ", index: " + index + ", method: " + method + ", class: " + classSchema);
}
}
}
methodParameters[index] = argumentValue;
}
try {
return method.invoke(object, methodParameters);
} catch (InvocationTargetException te) {
throw new GraphQLExecutorDataFetcherException(te.getTargetException());
} catch (Throwable e) {
throw new RuntimeException(e);
}
} catch (ReflectiveOperationException re) {
throw new RuntimeException(re);
}
}
private Object getInputValue(Type type, Object inputValue, boolean isPresent) throws ReflectiveOperationException {
Class clazz;
if (type instanceof ParameterizedType) {
clazz = (Class) ((ParameterizedType) type).getRawType();
} else {
clazz = (Class) type;
}
if (inputValue == null) {
if (clazz.isPrimitive()) return Utils.defaultValue(clazz);
if (clazz == GOptional.class) return new GOptional(null, isPresent);
return null;
}
//Проверяем на скалярный тип объекта
GraphQLTypeScalar graphQLTypeScalar = graphQLSchemaType.getTypeScalarByClass(clazz);
if (graphQLTypeScalar != null) {
return graphQLTypeScalar.getGraphQLScalarType().getCoercing().parseValue(inputValue);
}
if (clazz.isEnum()) {
try {
return Enum.valueOf(clazz, (String) inputValue);
} catch (Exception e) {
throw new GraphQLExecutorInvalidSyntaxException(e);
}
} else if (clazz == GOptional.class) {
return new GOptional(getInputValue(((ParameterizedType) type).getActualTypeArguments()[0], inputValue, true), isPresent);
} else if (Collection.class.isAssignableFrom(clazz)) {
if (!Collection.class.isAssignableFrom(inputValue.getClass())) {
throw new GraphQLExecutorInvalidSyntaxException();
}
if (clazz.isAssignableFrom(ArrayList.class)) {
List list = new ArrayList();
for (Object iObject : (Collection) inputValue) {
Object element = getInputValue(((ParameterizedType) type).getActualTypeArguments()[0], iObject, true);
list.add(element);
}
return list;
} else if (clazz.isAssignableFrom(HashSet.class)) {
Set set = new HashSet();
for (Object iObject : (Collection) inputValue) {
Object element = getInputValue(((ParameterizedType) type).getActualTypeArguments()[0], iObject, true);
if (element == null) continue;
set.add(element);
}
return set;
} else {
throw new RuntimeException("Not support type collection: " + clazz);
}
} else if (clazz.getAnnotation(GraphQLTypeInput.class) != null) {
if (!Map.class.isAssignableFrom(inputValue.getClass())) {
throw new GraphQLExecutorInvalidSyntaxException();
}
Map fieldValues = (Map) inputValue;
Constructor constructor = ReflectionUtils.getGConstructor(clazz);
if (constructor == null) {
throw new RuntimeException("Not found constructor from GraphQLTypeInput: " + clazz.getName());
}
constructor.setAccessible(true);
Object[] args = new Object[constructor.getParameterCount()];
Annotation[][] annotations = constructor.getParameterAnnotations();
Type[] fieldTypes = constructor.getGenericParameterTypes();
for (int index = 0; index < args.length; index++) {
String nameField = null;
for (Annotation iAnnotation : annotations[index]) {
if (iAnnotation.annotationType() == GraphQLName.class) {
nameField = ((GraphQLName) iAnnotation).value();
}
}
args[index] = getInputValue(fieldTypes[index], fieldValues.get(nameField), fieldValues.containsKey(nameField));
}
try {
return constructor.newInstance(args);
} catch (InvocationTargetException ite) {
throw new GraphQLExecutorDataFetcherException(ite.getCause());
}
} else {
throw new GraphQLExecutorException("Not support type: " + type);
}
}
//TODO Ulitin V. Если когда нибудь у нас появится перегрузка методов, переписать
private Method getMethod(String graphQLTypeName, String graphQLTypeFieldName) {
Class classSchema = classSchemas.get(graphQLTypeName);
if (classSchema == null) {
throw new RuntimeException("not support scheme from: " + graphQLTypeName);
}
Method findMethod = findMethod(classSchema, graphQLTypeFieldName);
if (findMethod == null) {
for (Class subInterface : classSchema.getInterfaces()) {
findMethod = findMethod(subInterface, graphQLTypeFieldName);
if (findMethod != null) break;
}
}
if (findMethod == null) {
throw new RuntimeException("not found method: " + graphQLTypeFieldName + " in " + classSchema);
}
return findMethod;
}
private static Method findMethod(Class classSchema, String graphQLTypeFieldName) {
Method findMethod = null;
for (Method method : classSchema.getMethods()) {
if (method.isSynthetic()) continue; //Игнорируем генерируемые методы
if (method.getName().equals(graphQLTypeFieldName)) {
if (findMethod == null) {
findMethod = method;
} else {
throw new RuntimeException("not support overload method: " + graphQLTypeFieldName + " in class: " + classSchema);
}
}
}
return findMethod;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy