blob: 8ea7193a3275ee0033292553b9af54da94cd0d91 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.unomi.graphql.schema;
import graphql.annotations.AnnotationsSchemaCreator;
import graphql.annotations.processor.GraphQLAnnotations;
import graphql.annotations.processor.ProcessingElementsContainer;
import graphql.language.InputObjectTypeDefinition;
import graphql.schema.DataFetcher;
import graphql.schema.FieldCoordinates;
import graphql.schema.GraphQLCodeRegistry;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
import org.apache.unomi.api.EventType;
import org.apache.unomi.api.PropertyType;
import org.apache.unomi.api.services.EventTypeRegistry;
import org.apache.unomi.api.services.ProfileService;
import org.apache.unomi.graphql.CDPGraphQLConstants;
import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter;
import org.apache.unomi.graphql.fetchers.CustomEventOrSetPropertyDataFetcher;
import org.apache.unomi.graphql.fetchers.CustomerPropertyDataFetcher;
import org.apache.unomi.graphql.fetchers.DynamicFieldDataFetcher;
import org.apache.unomi.graphql.fetchers.event.EventListenerSubscriptionFetcher;
import org.apache.unomi.graphql.fetchers.event.UnomiEventPublisher;
import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider;
import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider;
import org.apache.unomi.graphql.providers.GraphQLExtensionsProvider;
import org.apache.unomi.graphql.providers.GraphQLFieldVisibilityProvider;
import org.apache.unomi.graphql.providers.GraphQLMutationProvider;
import org.apache.unomi.graphql.providers.GraphQLQueryProvider;
import org.apache.unomi.graphql.providers.GraphQLSubscriptionProvider;
import org.apache.unomi.graphql.providers.GraphQLTypeFunctionProvider;
import org.apache.unomi.graphql.types.input.CDPEventFilterInput;
import org.apache.unomi.graphql.types.input.CDPEventInput;
import org.apache.unomi.graphql.types.input.CDPEventProcessor;
import org.apache.unomi.graphql.types.input.CDPPersonaInput;
import org.apache.unomi.graphql.types.input.CDPProfilePropertiesFilterInput;
import org.apache.unomi.graphql.types.input.CDPProfileUpdateEventFilterInput;
import org.apache.unomi.graphql.types.input.CDPProfileUpdateEventInput;
import org.apache.unomi.graphql.types.input.CDPUnomiEventInput;
import org.apache.unomi.graphql.types.input.EventFilterInputMarker;
import org.apache.unomi.graphql.types.output.CDPEventInterface;
import org.apache.unomi.graphql.types.output.CDPPersona;
import org.apache.unomi.graphql.types.output.CDPProfile;
import org.apache.unomi.graphql.types.output.RootMutation;
import org.apache.unomi.graphql.types.output.RootQuery;
import org.apache.unomi.graphql.utils.ReflectionUtil;
import org.apache.unomi.graphql.utils.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static graphql.schema.FieldCoordinates.coordinates;
import static graphql.schema.GraphQLArgument.newArgument;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
import static graphql.schema.GraphQLObjectType.newObject;
public class GraphQLSchemaProvider {
private final ProfileService profileService;
private final EventTypeRegistry eventTypeRegistry;
private final List<GraphQLTypeFunctionProvider> typeFunctionProviders;
private final List<GraphQLExtensionsProvider> extensionsProviders;
private final List<GraphQLAdditionalTypesProvider> additionalTypesProviders;
private final List<GraphQLQueryProvider> queryProviders;
private final List<GraphQLMutationProvider> mutationProviders;
private final List<GraphQLSubscriptionProvider> subscriptionProviders;
private final GraphQLFieldVisibilityProvider fieldVisibilityProvider;
private final GraphQLCodeRegistryProvider codeRegistryProvider;
private final UnomiEventPublisher eventPublisher;
private GraphQLAnnotations graphQLAnnotations;
private Set<Class<?>> additionalTypes = new HashSet<>();
private GraphQLSchemaProvider(final Builder builder) {
this.profileService = builder.profileService;
this.eventTypeRegistry = builder.eventTypeRegistry;
this.eventPublisher = builder.eventPublisher;
this.typeFunctionProviders = builder.typeFunctionProviders;
this.extensionsProviders = builder.extensionsProviders;
this.additionalTypesProviders = builder.additionalTypesProviders;
this.queryProviders = builder.queryProviders;
this.mutationProviders = builder.mutationProviders;
this.subscriptionProviders = builder.subscriptionProviders;
this.codeRegistryProvider = builder.codeRegistryProvider;
this.fieldVisibilityProvider = builder.fieldVisibilityProvider;
}
public GraphQLSchema createSchema() {
this.graphQLAnnotations = new GraphQLAnnotations();
final GraphQLSchema.Builder schemaBuilder = GraphQLSchema.newSchema();
registerTypeFunctions();
configureElementsContainer();
registerDynamicFields(schemaBuilder);
registerExtensions();
registerAdditionalTypes();
transformQuery();
transformMutations();
configureFieldVisibility();
configureCodeRegister();
final AnnotationsSchemaCreator.Builder annotationsSchema = AnnotationsSchemaCreator.newAnnotationsSchema();
if (additionalTypes != null) {
annotationsSchema.additionalTypes(additionalTypes);
}
createSubscriptionSchema(schemaBuilder);
return annotationsSchema
.setGraphQLSchemaBuilder(schemaBuilder)
.query(RootQuery.class)
.mutation(RootMutation.class)
.setAnnotationsProcessor(graphQLAnnotations)
.build();
}
private void createSubscriptionSchema(final GraphQLSchema.Builder schemaBuilder) {
final GraphQLInputObjectType eventFilterInputType = (GraphQLInputObjectType) getFromTypeRegistry(CDPEventFilterInput.TYPE_NAME);
final GraphQLInterfaceType eventInterfaceType = (GraphQLInterfaceType) getFromTypeRegistry(CDPEventInterface.TYPE_NAME);
// creating subscriptions dynamically because annotations
// doesn't seem to be able to handle data fetchers returning publishers
GraphQLObjectType cdpSubscription = newObject()
.name("CDP_Subscription")
.field(newFieldDefinition()
.argument(newArgument()
.name("filter")
.type(eventFilterInputType)
.build())
.name("eventListener")
.type(eventInterfaceType)
.build())
.build();
// register data fetcher in annotations instead of codeRegistry
// because annotations will overwrite it on schema build
graphQLAnnotations.getContainer().getCodeRegistryBuilder()
.dataFetcher(
coordinates("CDP_Subscription", "eventListener"),
new EventListenerSubscriptionFetcher(eventPublisher));
if (subscriptionProviders != null && !subscriptionProviders.isEmpty()) {
for (GraphQLSubscriptionProvider subscriptionProvider : subscriptionProviders) {
final Set<GraphQLFieldDefinition> subscriptions = subscriptionProvider.getSubscriptions(graphQLAnnotations);
if (subscriptions != null) {
cdpSubscription = cdpSubscription.transform(builder -> subscriptions.forEach(builder::field));
}
}
}
schemaBuilder.subscription(cdpSubscription);
}
public Set<Class<?>> getAdditionalTypes() {
return additionalTypes;
}
private void registerTypeFunctions() {
if (typeFunctionProviders != null && !typeFunctionProviders.isEmpty()) {
for (GraphQLTypeFunctionProvider provider : typeFunctionProviders) {
if (provider != null && provider.getTypeFunctions() != null) {
provider.getTypeFunctions().forEach(graphQLAnnotations::registerTypeFunction);
}
}
}
}
private void registerDynamicFields(GraphQLSchema.Builder schemaBuilder) {
if (additionalTypesProviders != null && !additionalTypesProviders.isEmpty()) {
for (final GraphQLAdditionalTypesProvider typeProvider : additionalTypesProviders) {
if (typeProvider != null && typeProvider.getAdditionalInputTypes() != null) {
typeProvider.getAdditionalInputTypes().forEach(additionalType -> {
final String typeName = ReflectionUtil.resolveTypeName(additionalType);
final GraphQLInputObjectType.Builder builder = GraphQLInputObjectType.newInputObject()
.name(typeName)
.fields(getInputObjectType(additionalType).getFieldDefinitions());
registerInTypeRegistry(typeName, builder.build());
});
}
}
}
final Collection<PropertyType> propertyTypes = profileService.getTargetPropertyTypes("profiles");
// Profile
registerDynamicInputFilterFields(CDPProfilePropertiesFilterInput.TYPE_NAME, CDPProfilePropertiesFilterInput.class, propertyTypes);
registerDynamicInputFilterFields(CDPProfileUpdateEventFilterInput.TYPE_NAME, CDPProfileUpdateEventFilterInput.class, propertyTypes);
registerDynamicInputFields(CDPProfileUpdateEventInput.TYPE_NAME, CDPProfileUpdateEventInput.class, propertyTypes);
registerDynamicEventFilterInputFields();
// Profile
registerDynamicOutputFields(CDPProfile.TYPE_NAME, CDPProfile.class, CustomerPropertyDataFetcher.class, propertyTypes);
// Persona
registerDynamicInputFields(CDPPersonaInput.TYPE_NAME, CDPPersonaInput.class, propertyTypes);
registerDynamicOutputFields(CDPPersona.TYPE_NAME, CDPPersona.class, CustomerPropertyDataFetcher.class, propertyTypes);
// Events
registerDynamicUnomiInputEvents(schemaBuilder);
registerDynamicUnomiOutputEvents(schemaBuilder);
registerDynamicEventInputFields();
}
private void registerDynamicUnomiInputEvents(GraphQLSchema.Builder schemaBuilder) {
final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll();
if (!unomiEventTypes.isEmpty()) {
for (EventType unomiEventType : unomiEventTypes) {
final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getType()) + "Input";
final GraphQLInputObjectType objectType;
if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
objectType = createDynamicEventInputType(unomiEventType);
} else {
objectType = (GraphQLInputObjectType) getFromTypeRegistry(typeName);
registerDynamicInputFields(typeName, objectType, unomiEventType.getPropertyTypes());
}
schemaBuilder.additionalType(objectType);
}
}
}
private void registerDynamicUnomiOutputEvents(GraphQLSchema.Builder schemaBuilder) {
final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll();
if (!unomiEventTypes.isEmpty()) {
final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder();
for (EventType unomiEventType : unomiEventTypes) {
final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getType());
final GraphQLObjectType objectType;
if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
objectType = createDynamicEventOutputType(unomiEventType, codeRegisterBuilder);
} else {
objectType = (GraphQLObjectType) getFromTypeRegistry(typeName);
registerDynamicOutputFields(typeName, objectType, CustomerPropertyDataFetcher.class, unomiEventType.getPropertyTypes());
}
schemaBuilder.additionalType(objectType);
}
}
}
private void registerDynamicInputFilterFields(final String typeName,
final Class<?> annotatedClass,
final Collection<PropertyType> propertyTypes) {
final GraphQLInputObjectType originalObject = getInputObjectType(annotatedClass);
final List<GraphQLInputObjectField> inputObjectFields =
PropertyFilterUtils.buildInputPropertyFilters(propertyTypes, graphQLAnnotations);
final GraphQLInputObjectType transformedObjectType =
originalObject.transform(builder -> inputObjectFields.forEach(builder::field));
registerInTypeRegistry(typeName, transformedObjectType);
}
private void registerDynamicOutputFields(final String graphQLTypeName,
final Class<?> annotatedClass,
final Class<? extends DynamicFieldDataFetcher> fetcherClass,
final Collection<PropertyType> propertyTypes) {
final GraphQLObjectType objectType = graphQLAnnotations.object(annotatedClass);
registerDynamicOutputFields(graphQLTypeName, objectType, fetcherClass, propertyTypes);
}
private void registerDynamicOutputFields(final String graphQLTypeName,
final GraphQLObjectType graphQLObjectType,
final Class<? extends DynamicFieldDataFetcher> fetcherClass,
final Collection<PropertyType> propertyTypes) {
final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder();
final List<GraphQLFieldDefinition> fieldDefinitions = new ArrayList<>();
propertyTypes.forEach(propertyType -> {
final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId());
if ("set".equals(propertyType.getValueTypeId())) {
final String typeName = StringUtils.capitalize(propertyName);
GraphQLObjectType objectType;
if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
objectType = createDynamicSetOutputType(propertyType, codeRegisterBuilder, null);
} else {
objectType = (GraphQLObjectType) getFromTypeRegistry(typeName);
}
fieldDefinitions.add(GraphQLFieldDefinition.newFieldDefinition()
.type(objectType)
.name(propertyName).build());
} else {
fieldDefinitions.add(GraphQLFieldDefinition.newFieldDefinition()
.type((GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getValueTypeId()))
.name(propertyName).build());
}
try {
final DataFetcher dataFetcher = fetcherClass.getConstructor(String.class, String.class).newInstance(propertyName, propertyType.getValueTypeId());
codeRegisterBuilder.dataFetcher(FieldCoordinates.coordinates(graphQLTypeName, propertyName), dataFetcher);
} catch (Exception e) {
throw new RuntimeException(String.format("Error creating a data fetcher with class %s for field %s", fetcherClass.getName(), propertyName), e);
}
});
final GraphQLObjectType transformedObjectType = graphQLObjectType.transform(builder -> fieldDefinitions.forEach(builder::field));
registerInTypeRegistry(graphQLTypeName, transformedObjectType);
}
private GraphQLObjectType createDynamicSetOutputType(
final PropertyType propertyType, final GraphQLCodeRegistry.Builder codeRegisterBuilder, final String parentName) {
return createDynamicOutputType(parentName != null ? parentName : propertyType.getItemId(), propertyType.getChildPropertyTypes(), null, codeRegisterBuilder);
}
private GraphQLObjectType createDynamicEventOutputType(
final EventType eventType, final GraphQLCodeRegistry.Builder codeRegisterBuilder) {
final Set<Class> interfaces = new HashSet<>();
interfaces.add(CDPEventInterface.class);
return createDynamicOutputType(UnomiToGraphQLConverter.convertEventType(eventType.getType()), eventType.getPropertyTypes(), interfaces, codeRegisterBuilder);
}
private GraphQLObjectType createDynamicOutputType(final String name, final Set<PropertyType> propertyTypes, final Set<Class> interfaces, final GraphQLCodeRegistry.Builder codeRegisterBuilder) {
final String typeName = StringUtils.capitalize(PropertyNameTranslator.translateFromUnomiToGraphQL(name));
final GraphQLObjectType.Builder dynamicTypeBuilder = GraphQLObjectType.newObject()
.name(typeName);
if (interfaces != null && !interfaces.isEmpty()) {
for (Class anInterface : interfaces) {
final GraphQLInterfaceType graphQLInterface = (GraphQLInterfaceType) getOutputType(anInterface);
if (graphQLInterface != null) {
dynamicTypeBuilder.withInterface(graphQLInterface);
graphQLInterface.getFieldDefinitions().forEach(fieldDefinition -> {
dynamicTypeBuilder.field(fieldDefinition);
final String propertyName = fieldDefinition.getName();
final DataFetcher dataFetcher = new CustomEventOrSetPropertyDataFetcher(propertyName);
codeRegisterBuilder.dataFetcher(FieldCoordinates.coordinates(typeName, propertyName), dataFetcher);
});
}
}
}
if (propertyTypes != null && !propertyTypes.isEmpty()) {
propertyTypes.forEach(childPropertyType -> {
final boolean isSet = "set".equals(childPropertyType.getValueTypeId());
String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getItemId());
final GraphQLFieldDefinition.Builder fieldBuilder = GraphQLFieldDefinition.newFieldDefinition()
.name(childPropertyName);
if (isSet) {
fieldBuilder.type(createDynamicSetOutputType(childPropertyType, codeRegisterBuilder, typeName + "_" + childPropertyName));
} else {
fieldBuilder.type((GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getValueTypeId()));
}
codeRegisterBuilder.dataFetcher(FieldCoordinates.coordinates(typeName, childPropertyName),
new CustomEventOrSetPropertyDataFetcher(childPropertyName));
dynamicTypeBuilder.field(fieldBuilder.build());
});
}
final GraphQLObjectType objectType = dynamicTypeBuilder.build();
registerInTypeRegistry(typeName, objectType);
return objectType;
}
private GraphQLInputObjectType createDynamicEventInputType(final EventType eventType) {
return createDynamicInputType(UnomiToGraphQLConverter.convertEventType(eventType.getType()), eventType.getPropertyTypes(), true);
}
private GraphQLInputObjectType createDynamicSetInputType(final PropertyType propertyType, final String parentName) {
return createDynamicInputType(parentName != null ? parentName : propertyType.getItemId(), propertyType.getChildPropertyTypes(), false);
}
private GraphQLInputObjectType createDynamicInputType(final String name, final Set<PropertyType> propertyTypes, final boolean isEvent) {
final String typeName = StringUtils.capitalize(PropertyNameTranslator.translateFromUnomiToGraphQL(name)) + "Input";
final GraphQLInputObjectType.Builder dynamicTypeBuilder = GraphQLInputObjectType.newInputObject()
.name(typeName);
if (isEvent) {
dynamicTypeBuilder.definition(InputObjectTypeDefinition.newInputObjectDefinition()
.additionalData(CDPGraphQLConstants.EVENT_PROCESSOR_CLASS, CDPUnomiEventInput.class.getName()).build()
);
}
if (propertyTypes != null && !propertyTypes.isEmpty()) {
propertyTypes.forEach(childPropertyType -> {
final boolean isSet = "set".equals(childPropertyType.getValueTypeId());
String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getItemId());
final GraphQLInputObjectField.Builder fieldBuilder = GraphQLInputObjectField.newInputObjectField()
.name(childPropertyName);
if (isSet) {
fieldBuilder.type(createDynamicSetInputType(childPropertyType, typeName + "_" + childPropertyName));
} else {
fieldBuilder.type((GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getValueTypeId()));
}
dynamicTypeBuilder.field(fieldBuilder.build());
});
}
final GraphQLInputObjectType objectType = dynamicTypeBuilder.build();
registerInTypeRegistry(typeName, objectType);
return objectType;
}
private void registerDynamicInputFields(final String graphQLTypeName,
final Class<?> clazz,
final Collection<PropertyType> propertyTypes) {
final GraphQLInputObjectType inputObjectType = getInputObjectType(clazz);
registerDynamicInputFields(graphQLTypeName, inputObjectType, propertyTypes);
}
private void registerDynamicInputFields(final String graphQLTypeName,
final GraphQLInputObjectType graphQLInputObjectType,
final Collection<PropertyType> propertyTypes) {
final List<GraphQLInputObjectField> fieldDefinitions = new ArrayList<>();
propertyTypes.forEach(propertyType -> {
final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId());
if ("set".equals(propertyType.getValueTypeId())) {
final String typeName = StringUtils.capitalize(propertyName) + "Input";
if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
.name(propertyName)
.type(createDynamicSetInputType(propertyType, null))
.build());
} else {
fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
.name(propertyName)
.type((GraphQLInputType) getFromTypeRegistry(typeName))
.build());
}
} else {
fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
.type((GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getValueTypeId()))
.name(propertyName)
.build());
}
});
final GraphQLInputObjectType transformedObjectType = graphQLInputObjectType
.transform(builder -> fieldDefinitions.forEach(builder::field));
registerInTypeRegistry(graphQLTypeName, transformedObjectType);
}
private void registerDynamicEventInputFields() {
final GraphQLInputObjectType.Builder builder = GraphQLInputObjectType.newInputObject()
.name(CDPEventInput.TYPE_NAME)
.fields(getInputObjectType(CDPEventInput.class).getFieldDefinitions());
if (!additionalTypesProviders.isEmpty()) {
additionalTypesProviders.forEach(provider -> {
if (provider != null && provider.getAdditionalInputTypes() != null) {
provider.getAdditionalInputTypes().stream()
.filter(CDPEventProcessor.class::isAssignableFrom)
.forEach(additionalType -> {
final String typeName = ReflectionUtil.resolveTypeName(additionalType);
final GraphQLInputObjectType.Builder eventInput = GraphQLInputObjectType.newInputObject()
.name(typeName)
.fields(getInputObjectType(additionalType).getFieldDefinitions())
.definition(InputObjectTypeDefinition.newInputObjectDefinition()
.additionalData(CDPGraphQLConstants.EVENT_PROCESSOR_CLASS, additionalType.getName()).build()
);
builder.field(GraphQLInputObjectField.newInputObjectField()
.name(generateFieldName(typeName))
.type(eventInput)
.build());
});
}
});
}
// now add all unomi defined event types
final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll();
unomiEventTypes.forEach(eventType -> {
final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getType());
builder.field(GraphQLInputObjectField.newInputObjectField()
.name(StringUtils.decapitalize(typeName))
.type((GraphQLInputType) getFromTypeRegistry(typeName + "Input"))
.build());
});
registerInTypeRegistry(CDPEventInput.TYPE_NAME, builder.build());
}
private void registerDynamicEventFilterInputFields() {
final List<GraphQLInputObjectField> fieldDefinitions = new ArrayList<>();
final List<String> registeredFieldNames = getInputObjectType(CDPEventFilterInput.class).getFieldDefinitions()
.stream()
.map(GraphQLInputObjectField::getName)
.collect(Collectors.toList());
if (!additionalTypesProviders.isEmpty()) {
additionalTypesProviders.forEach(provider -> {
if (provider != null && provider.getAdditionalInputTypes() != null) {
provider.getAdditionalInputTypes().stream()
.filter(EventFilterInputMarker.class::isAssignableFrom)
.forEach(additionalType -> {
final String typeName = ReflectionUtil.resolveTypeName(additionalType);
final String fieldName = generateFieldName(typeName.replace("FilterInput", ""));
if (!registeredFieldNames.contains(fieldName)) {
fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
.type(getInputObjectType(additionalType))
.name(fieldName)
.build());
}
});
}
});
}
final GraphQLInputObjectType transformedObjectType = getInputObjectType(CDPEventFilterInput.class)
.transform(builder -> fieldDefinitions.forEach(builder::field));
registerInTypeRegistry(CDPEventFilterInput.TYPE_NAME, transformedObjectType);
}
private String generateFieldName(final String typeName) {
final int index = typeName.indexOf("_");
char[] chars = typeName.substring(index + 1).toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
final String eventName = typeName.substring(0, index).toLowerCase() + "_" + new String(chars);
return eventName.replace("Filter", "")
.replace("Input", "");
}
private void registerInTypeRegistry(final String name, final GraphQLType type) {
graphQLAnnotations.getContainer().getTypeRegistry().put(name, type);
}
private GraphQLType getFromTypeRegistry(final String name) {
return graphQLAnnotations.getContainer().getTypeRegistry().get(name);
}
private void configureElementsContainer() {
final ProcessingElementsContainer container = graphQLAnnotations.getContainer();
container.setInputPrefix("");
container.setInputSuffix("");
}
private void registerExtensions() {
if (extensionsProviders != null && !extensionsProviders.isEmpty()) {
for (GraphQLExtensionsProvider extensionsProvider : extensionsProviders) {
if (extensionsProvider.getExtensions() != null) {
extensionsProvider.getExtensions().forEach(graphQLAnnotations::registerTypeExtension);
}
}
}
}
private void transformQuery() {
final Map<String, GraphQLType> typeRegistry = graphQLAnnotations.getContainer().getTypeRegistry();
if (queryProviders != null && !queryProviders.isEmpty()) {
for (GraphQLQueryProvider queryProvider : queryProviders) {
final Set<GraphQLFieldDefinition> queries = queryProvider.getQueries(graphQLAnnotations);
if (queries != null) {
final GraphQLObjectType transformedType = graphQLAnnotations.object(RootQuery.class)
.transform(builder -> queries.forEach(builder::field));
typeRegistry.put(RootQuery.TYPE_NAME, transformedType);
}
}
}
}
private void transformMutations() {
final Map<String, GraphQLType> typeRegistry = graphQLAnnotations.getContainer().getTypeRegistry();
if (mutationProviders != null && !mutationProviders.isEmpty()) {
for (GraphQLMutationProvider mutationProvider : mutationProviders) {
final Set<GraphQLFieldDefinition> mutations = mutationProvider.getMutations(graphQLAnnotations);
if (mutations != null) {
final GraphQLObjectType transformedMutationType = graphQLAnnotations.object(RootMutation.class)
.transform(builder -> mutations.forEach(builder::field));
typeRegistry.put(RootMutation.TYPE_NAME, transformedMutationType);
}
}
}
}
private void registerAdditionalTypes() {
if (additionalTypesProviders == null || additionalTypesProviders.isEmpty()) {
return;
}
for (final GraphQLAdditionalTypesProvider typesProvider : additionalTypesProviders) {
if (typesProvider.getAdditionalOutputTypes() != null) {
additionalTypes.addAll(typesProvider.getAdditionalOutputTypes());
}
}
}
private void configureCodeRegister() {
if (codeRegistryProvider != null) {
graphQLAnnotations.getContainer().setCodeRegistryBuilder(
codeRegistryProvider.getCodeRegistry(
graphQLAnnotations.getContainer().getCodeRegistryBuilder().build()
));
}
}
private void configureFieldVisibility() {
if (fieldVisibilityProvider != null) {
graphQLAnnotations.getContainer().getCodeRegistryBuilder()
.fieldVisibility(fieldVisibilityProvider.getGraphQLFieldVisibility());
}
}
public GraphQLInputObjectType getInputObjectType(final Class<?> annotatedClass) {
return (GraphQLInputObjectType) graphQLAnnotations.getObjectHandler().getTypeRetriever()
.getGraphQLType(annotatedClass, graphQLAnnotations.getContainer(), true);
}
public GraphQLType getOutputType(final Class<?> annotatedClass) {
return graphQLAnnotations.getObjectHandler().getTypeRetriever()
.getGraphQLType(annotatedClass, graphQLAnnotations.getContainer(), false);
}
public static Builder create(final ProfileService profileService, final EventTypeRegistry eventTypeRegistry) {
return new Builder(profileService, eventTypeRegistry);
}
static class Builder {
final ProfileService profileService;
final EventTypeRegistry eventTypeRegistry;
List<GraphQLTypeFunctionProvider> typeFunctionProviders;
List<GraphQLExtensionsProvider> extensionsProviders;
List<GraphQLAdditionalTypesProvider> additionalTypesProviders;
List<GraphQLQueryProvider> queryProviders;
List<GraphQLMutationProvider> mutationProviders;
List<GraphQLSubscriptionProvider> subscriptionProviders;
GraphQLFieldVisibilityProvider fieldVisibilityProvider;
GraphQLCodeRegistryProvider codeRegistryProvider;
UnomiEventPublisher eventPublisher;
private Builder(final ProfileService profileService, final EventTypeRegistry eventTypeRegistry) {
this.profileService = profileService;
this.eventTypeRegistry = eventTypeRegistry;
}
public Builder typeFunctionProviders(List<GraphQLTypeFunctionProvider> typeFunctionProviders) {
this.typeFunctionProviders = typeFunctionProviders;
return this;
}
public Builder extensionsProviders(List<GraphQLExtensionsProvider> extensionsProviders) {
this.extensionsProviders = extensionsProviders;
return this;
}
public Builder additionalTypesProviders(List<GraphQLAdditionalTypesProvider> additionalTypesProviders) {
this.additionalTypesProviders = additionalTypesProviders;
return this;
}
public Builder queryProviders(List<GraphQLQueryProvider> queryProviders) {
this.queryProviders = queryProviders;
return this;
}
public Builder mutationProviders(List<GraphQLMutationProvider> mutationProviders) {
this.mutationProviders = mutationProviders;
return this;
}
public Builder subscriptionProviders(List<GraphQLSubscriptionProvider> subscriptionProviders) {
this.subscriptionProviders = subscriptionProviders;
return this;
}
public Builder codeRegistryProvider(GraphQLCodeRegistryProvider codeRegistryProvider) {
this.codeRegistryProvider = codeRegistryProvider;
return this;
}
public Builder eventPublisher(UnomiEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
return this;
}
public Builder fieldVisibilityProvider(GraphQLFieldVisibilityProvider fieldVisibilityProvider) {
this.fieldVisibilityProvider = fieldVisibilityProvider;
return this;
}
void validate() {
Objects.requireNonNull(profileService, "Profile service can not be null");
}
public GraphQLSchemaProvider build() {
validate();
return new GraphQLSchemaProvider(this);
}
}
}