org.structr.core.graphql.GraphQLRequest.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.core.graphql.GraphQLRequest.java

Source

/**
 * Copyright (C) 2010-2018 Structr GmbH
 *
 * This file is part of Structr <http://structr.org>.
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Structr.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.structr.core.graphql;

import graphql.language.Document;
import graphql.language.Field;
import graphql.language.Node;
import graphql.language.OperationDefinition;
import graphql.language.Selection;
import graphql.language.SelectionSet;
import graphql.parser.Parser;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;

/**
 * A GraphQL request that contains a list of query objects.
 */
public class GraphQLRequest {

    private static final Logger logger = LoggerFactory.getLogger(GraphQLRequest.class);

    private final List<GraphQLQuery> queries = new LinkedList<>();
    private boolean hasSchemaQuery = false;
    private String originalQuery = null;

    public GraphQLRequest(final SecurityContext securityContext, final Document document,
            final String originalQuery) throws FrameworkException {

        this.originalQuery = originalQuery;

        initialize(securityContext, document);
        checkSchemaRequest();
    }

    public boolean hasSchemaQuery() {
        return hasSchemaQuery;
    }

    public Iterable<GraphQLQuery> getQueries() {
        return queries;
    }

    public String getOriginalQuery() {
        return originalQuery;
    }

    public static Document parse(final Parser parser, final String query) throws FrameworkException {

        try {

            return parser.parseDocument(query);

        } catch (Throwable t) {

            String message = t.getMessage();
            if (message == null) {

                message = t.getClass().getName();

                if (t instanceof ParseCancellationException) {

                    final Throwable cause = t.getCause();
                    if (cause instanceof RecognitionException) {

                        final RecognitionException err = (RecognitionException) cause;
                        final Token offendingToken = err.getOffendingToken();

                        if (offendingToken != null) {

                            final int line = offendingToken.getLine();
                            final int column = offendingToken.getCharPositionInLine();
                            final String text = offendingToken.getText();

                            message = "Parse error at " + text + " in line " + line + ", column " + column;
                        }
                    }

                }
            }

            final FrameworkException fex = new FrameworkException(422, message);
            final Map<String, String> data = new LinkedHashMap<>();

            // do not output an empty array of errors
            fex.setErrorBuffer(null);
            fex.setData(data);

            data.put("query", query);

            throw fex;
        }
    }

    // ----- private methods -----
    private void initialize(final SecurityContext securityContext, Document document) throws FrameworkException {

        for (final Node child : document.getChildren()) {

            if (child instanceof OperationDefinition) {

                final OperationDefinition operationDefinition = (OperationDefinition) child;
                final SelectionSet selectionSet = operationDefinition.getSelectionSet();

                for (final Selection selection : selectionSet.getSelections()) {

                    if (selection instanceof Field) {

                        queries.add(new GraphQLQuery(securityContext, (Field) selection));

                    } else {

                        logger.warn("Unknown selection set element {} in GraphQL query, ignoring.",
                                selection.getClass());
                    }
                }

            } else {

                logger.warn("Unknown document element {} in GraphQL query, ignoring.", child.getClass());
            }
        }
    }

    private void checkSchemaRequest() throws FrameworkException {

        boolean hasDataQuery = false;

        for (final GraphQLQuery query : queries) {

            if (query.isSchemaQuery()) {

                hasSchemaQuery = true;

            } else {

                hasDataQuery = true;
            }
        }

        if (hasSchemaQuery && hasDataQuery) {

            final FrameworkException fex = new FrameworkException(422,
                    "Unsupported query type, schema and data queries cannot be mixed.");
            final Map<String, String> data = new HashMap<>();

            fex.setData(data);

            data.put("query", originalQuery);

            throw fex;
        }
    }
}