io.engagingspaces.graphql.marshaller.schema.impl.SchemaContextImpl.java Source code

Java tutorial

Introduction

Here is the source code for io.engagingspaces.graphql.marshaller.schema.impl.SchemaContextImpl.java

Source

/*
 * Copyright (c) 2016 The original author or authors
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 *      The Eclipse Public License is available at
 *      http://www.eclipse.org/legal/epl-v10.html
 *
 *      The Apache License v2.0 is available at
 *      http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */

package io.engagingspaces.graphql.marshaller.schema.impl;

import graphql.schema.*;
import io.engagingspaces.graphql.marshaller.SchemaMarshallerOptions;
import io.engagingspaces.graphql.marshaller.json.JsonReference;
import io.engagingspaces.graphql.marshaller.json.JsonSerializable;
import io.engagingspaces.graphql.marshaller.json.impl.JsonReferenceHelper;
import io.engagingspaces.graphql.marshaller.schema.decorators.GraphQLScalarTypeDO;
import io.engagingspaces.graphql.marshaller.schema.Marshaller;
import io.engagingspaces.graphql.marshaller.schema.SchemaContext;
import io.engagingspaces.graphql.marshaller.schema.SchemaDecorator;
import io.engagingspaces.graphql.marshaller.schema.Unmarshaller;
import io.engagingspaces.graphql.marshaller.schema.decorators.DataFetcherDO;
import io.engagingspaces.graphql.marshaller.schema.decorators.TypeResolverDO;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.*;
import java.util.stream.Collectors;

import static io.engagingspaces.graphql.marshaller.json.JsonReference.REF_KEY;
import static io.engagingspaces.graphql.marshaller.json.impl.JsonReferenceHelper.ROOT_REFERENCE;
import static io.engagingspaces.graphql.marshaller.json.impl.JsonReferenceHelper.SLASH;

/**
 * Implementation class of {@link SchemaContext}.
 *
 * @author <a href="https://github.com/aschrijver/">Arnold Schrijver</a>
 */
public class SchemaContextImpl implements SchemaContext {

    private final Map<Object, SchemaDecorator> decoratedTypes;
    private final Map<String, TypeResolver> typeResolvers;
    private final Map<String, DataFetcher> dataFetchers;
    private final Map<String, GraphQLScalarType> scalarTypes;
    private final SchemaMarshallerOptions options;
    private final JsonObject rootJson;

    /**
     * Constructor called from {@link SchemaContext}.
     *
     * @param options  the marshaller options
     * @param rootJson the root json object
     */
    public SchemaContextImpl(SchemaMarshallerOptions options, JsonObject rootJson) {
        this.decoratedTypes = new HashMap<>();
        this.typeResolvers = new HashMap<>();
        this.dataFetchers = new HashMap<>();
        this.scalarTypes = new HashMap<>();
        this.options = options;
        this.rootJson = rootJson;
    }

    /*
     * SchemaContext interface implementation
     */

    /**
     * {@inheritDoc}
     */
    @Override
    public SchemaMarshallerOptions options() {
        return options;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JsonReference registerTypeResolver(TypeResolverDO resolver) {
        Optional<TypeResolver> registeredResolver = typeResolvers.values().stream()
                .filter(typeResolver -> typeResolver.equals(resolver)).findAny();
        if (registeredResolver.isPresent()) {
            return ((TypeResolverDO) registeredResolver.get()).jsonReference();
        }
        typeResolvers.put(resolver.getId(), resolver);
        return registerDecorator(resolver);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JsonReference registerDataFetcher(DataFetcherDO dataFetcher) {
        Optional<DataFetcher> registeredDataFetcher = dataFetchers.values().stream()
                .filter(fetcher -> fetcher.equals(dataFetcher)).findAny();
        if (registeredDataFetcher.isPresent()) {
            return ((DataFetcherDO) registeredDataFetcher.get()).jsonReference();
        }
        dataFetchers.put(dataFetcher.getId(), dataFetcher);
        return registerDecorator(dataFetcher);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JsonReference registerScalarType(GraphQLScalarTypeDO scalarType) {
        scalarTypes.put(scalarType.getName(), scalarType);
        return registerDecorator(scalarType);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JsonReference registerDecorator(SchemaDecorator decorator) {
        decoratedTypes.put(decorator.original() == null ? decorator.toJson() : decorator.original(), decorator);
        return JsonReferenceHelper.createReference(decorator);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<Object, SchemaDecorator> getDecoratedTypes() {
        return decoratedTypes;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, TypeResolver> getTypeResolvers() {
        return typeResolvers;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, DataFetcher> getDataFetchers() {
        return dataFetchers;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, GraphQLScalarType> getScalarTypes() {
        return scalarTypes;
    }

    /*
     * Marshaller interface implementation
     */

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T decoratorOf(T schemaObject) {
        return decoratorOf(schemaObject, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T, U extends SchemaDecorator> T decoratorOf(T schemaObject, U parent) {
        if (schemaObject instanceof SchemaDecorator) {
            return schemaObject;
        }
        if (decoratedTypes.containsKey(schemaObject)) {
            return (T) decoratedTypes.get(schemaObject);
        }
        T decoratedType = Marshaller.createDecorator(schemaObject, this, parent);
        decoratedTypes.put(schemaObject, (SchemaDecorator) decoratedType);
        return decoratedType;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> JsonObject referenceTo(T schemaObject) {
        SchemaDecorator decorator = (SchemaDecorator) schemaObject;
        boolean inlineType = (schemaObject instanceof GraphQLList || schemaObject instanceof GraphQLNonNull)
                && ((GraphQLType) schemaObject).getName() == null;
        if (inlineType) {
            return marshall(schemaObject);
        } else if (decoratedTypes.containsValue(decorator)) {
            return decoratedTypes.get(decorator.original()).jsonReference().toJson();
        }
        throw new IllegalArgumentException("Failed to get Json reference. Unknown schema object: " + schemaObject);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> JsonObject marshall(T schemaObject) {
        if (decoratedTypes.containsKey(schemaObject)) {
            return decoratedTypes.get(schemaObject).toJson();
        } else if (schemaObject instanceof JsonSerializable) {
            return ((JsonSerializable) schemaObject).toJson();
        }
        String className = schemaObject.getClass().getName();
        throw new IllegalArgumentException(
                "Failed to marshal. Class '" + className + "' is not a known GraphQL schema class");
    }

    /*
     * Marshaller interface implementation
     */

    @Override
    @SuppressWarnings("unchecked")
    public <T extends SchemaDecorator, U extends SchemaDecorator> T dereference(Object jsonData, U parent) {
        if (decoratedTypes.containsKey(jsonData)) {
            return (T) decoratedTypes.get(jsonData);
        } else {
            JsonObject json = (JsonObject) jsonData;
            String reference = json.getString(REF_KEY);
            if (reference != null) {
                String[] referencePath = json.getString(REF_KEY).substring(ROOT_REFERENCE.length()).split(SLASH);
                json = rootJson;
                for (String ref : referencePath) {
                    json = json.getJsonObject(ref);
                }
                return unmarshall(json, parent);
            }
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T extends SchemaDecorator> T unmarshall(JsonObject json) {
        return unmarshall(json, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T extends SchemaDecorator, U extends SchemaDecorator> T unmarshall(JsonObject json, U parent) {
        if (json == null) {
            return null;
        }
        T decorator = dereference(json, parent);
        return decorator == null ? Unmarshaller.unmarshall(json, this, parent) : decorator;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> List<T> unmarshallList(JsonObject json, String listKey) {
        return unmarshallList(json, listKey, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T, U extends SchemaDecorator> List<T> unmarshallList(JsonObject json, String listKey, U parent) {
        if (json == null || !json.containsKey(listKey) || json.getValue(listKey) == null) {
            return Collections.emptyList();
        }
        Object list = json.getValue(listKey);
        if (list instanceof JsonObject) {
            return ((JsonObject) list).stream().map(entry -> (T) unmarshall((JsonObject) entry.getValue(), parent))
                    .collect(Collectors.toList());
        } else if (list instanceof JsonArray) {
            return ((JsonArray) list).stream().map(value -> (T) unmarshall((JsonObject) value, parent))
                    .collect(Collectors.toList());
        } else {
            throw new IllegalStateException(
                    "Failed to unmarshall type to list. Type: " + list.getClass().getName());
        }
    }
}