io.engagingspaces.graphql.servicediscovery.consumer.SchemaConsumer.java Source code

Java tutorial

Introduction

Here is the source code for io.engagingspaces.graphql.servicediscovery.consumer.SchemaConsumer.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.servicediscovery.consumer;

import io.engagingspaces.graphql.events.SchemaAnnounceHandler;
import io.engagingspaces.graphql.events.SchemaReferenceData;
import io.engagingspaces.graphql.events.SchemaUsageHandler;
import io.engagingspaces.graphql.query.QueryResult;
import io.engagingspaces.graphql.servicediscovery.client.GraphQLClient;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.servicediscovery.Record;
import io.vertx.servicediscovery.ServiceDiscovery;
import io.vertx.servicediscovery.ServiceDiscoveryOptions;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * Interface that facilitates easy subscription to service discovery events related to graphql services.
 * <p>
 * Implementors only need to initialize the {@link SchemaConsumer#discoveryRegistrar()} with a new instance, and then
 * attach to a service discovery instance to listen for events.
 * <p>
 * Service discovery instances are automatically created and closed when needed.
 *
 * @author <a href="https://github.com/aschrijver/">Arnold Schrijver</a>
 */
public interface SchemaConsumer extends SchemaAnnounceHandler, SchemaUsageHandler {

    /**
     * Starts listening to discovery events of graphql services that occur in the default service discovery instance.
     * <p>
     * Any `announce` and `usage` events emitted by the service repository that are related to a graphql service
     * are forwarded to the {@link SchemaConsumer#schemaDiscoveryEvent(Record)}
     * and {@link SchemaConsumer#schemaReferenceEvent(SchemaReferenceData)} event handlers, to be handled by clients.
     * <p>
     * If the service discovery doesn't exist, a new instance is automatically created and managed by the
     * {@link DiscoveryRegistrar}.
     * <p>
     * Returns an {@link DiscoveryRegistration} that contains the registered message consumers.
     *
     * @param consumer the instance that will receive the discovery events
     * @return the discovery registration
     */
    static DiscoveryRegistration startDiscovery(SchemaConsumer consumer) {
        return startDiscovery(new ServiceDiscoveryOptions(), consumer);
    }

    /**
     * Starts listening to discovery events of graphql services that occur in the service discovery specified by the
     * {@code options} parameter.
     * <p>
     * Any `announce` and `usage` events emitted by the service repository that are related to a graphql service
     * are forwarded to the {@link SchemaConsumer#schemaDiscoveryEvent(Record)}
     * and {@link SchemaConsumer#schemaReferenceEvent(SchemaReferenceData)} event handlers, to be handled by clients.
     * <p>
     * If the service discovery doesn't exist, a new instance is automatically created and managed by the
     * {@link DiscoveryRegistrar}.
     * <p>
     * Returns an {@link DiscoveryRegistration} that contains the
     * registered message consumers.
     *
     * @param options  the service discovery options
     * @param consumer the consumer of the schema discovery events
     * @return the discovery registration
     */
    static DiscoveryRegistration startDiscovery(ServiceDiscoveryOptions options, SchemaConsumer consumer) {
        Objects.requireNonNull(options, "Service discovery options cannot be null");
        Objects.requireNonNull(consumer, "Schema consumer cannot be null");
        Objects.requireNonNull(consumer.discoveryRegistrar(), "Schema consumer registrar cannot be null");
        return consumer.discoveryRegistrar().startListening(options, consumer, consumer);
    }

    /**
     * Stops listening to discovery events of the service discovery associated with the {@link DiscoveryRegistration}.
     *
     * @param registration  the discovery registration
     * @param consumer      the consumer of the schema discovery events
     */
    static void stopDiscovery(DiscoveryRegistration registration, SchemaConsumer consumer) {
        Objects.requireNonNull(consumer, "Schema consumer cannot be null");
        Objects.requireNonNull(consumer.discoveryRegistrar(), "Schema consumer registrar cannot be null");
        Objects.requireNonNull(registration, "Discovery registration cannot be null");
        Objects.requireNonNull(registration.getDiscoveryOptions(), "Service discovery options cannot be null");

        consumer.discoveryRegistrar().stopListening(registration.getDiscoveryOptions());
    }

    /**
     * Stops listening to discovery events of the service discovery specified in the the
     * {@link ServiceDiscoveryOptions}.
     *
     * @param options  the service discovery options
     * @param consumer      the consumer of the schema discovery events
     */
    static void stopDiscovery(ServiceDiscoveryOptions options, SchemaConsumer consumer) {
        Objects.requireNonNull(consumer, "Schema consumer cannot be null");
        Objects.requireNonNull(consumer.discoveryRegistrar(), "Schema consumer registrar cannot be null");
        Objects.requireNonNull(options, "Service discovery options cannot be null");

        consumer.discoveryRegistrar().stopListening(options);
    }

    /**
     * Unregisters all event consumers associated with the managed service discoveries, then closes the service
     * discoveries.
     *
     * @param consumer the schema event consumer to close
     */
    static void close(SchemaConsumer consumer) {
        Objects.requireNonNull(consumer, "Schema consumer cannot be null");
        Objects.requireNonNull(consumer.discoveryRegistrar(), "Schema consumer registrar cannot be null");
        consumer.discoveryRegistrar().close();
    }

    /**
     * Executes the GraphQL query against the specified schema definition (aka the graphql service name)
     * that is published to the service discovery with the specified name.
     * <p>
     * On success a {@link QueryResult} is returned. The GraphQL query itself may still have failed, so
     * check {@link QueryResult#isSucceeded()} afterwards. If not successful parse errors can be retrieved
     * from {@link QueryResult#getErrors()}.
     * <p>
     * The top-level keys in the `variables` json represent the variable names that are used in the query string, and
     * are passed with their corresponding values to the query executor.
     *
     * @param discoveryName the name of the service discovery
     * @param schemaName    the name of the schema definition to query
     * @param query         the GraphQL query
     * @param resultHandler the result handler
     */
    default void executeQuery(String discoveryName, String schemaName, String query,
            Handler<AsyncResult<QueryResult>> resultHandler) {
        executeQuery(discoveryName, schemaName, query, null, resultHandler);
    }

    /**
     * Executes the parametrized GraphQL query and its variables against the specified schema definition
     * (aka the graphql service name) that is published to the service discovery with the specified name.
     * <p>
     * On success a {@link QueryResult} is returned. Note that at this point the GraphQL query may still have failed,
     * so be sure to check the {@link QueryResult#getErrors()} property afterwards.
     * <p>
     * The top-level keys in the `variables` json represent the variable names that are used in the query string, and
     * are passed with their corresponding values to the query executor.
     *
     * @param discoveryName the name of the service discovery
     * @param schemaName    the name of the schema definition to query
     * @param query         the GraphQL query
     * @param variables     the variables to pass to the query executor
     * @param resultHandler the result handler
     */
    default void executeQuery(String discoveryName, String schemaName, String query, JsonObject variables,
            Handler<AsyncResult<QueryResult>> resultHandler) {
        Objects.requireNonNull(schemaName, "Schema definition name cannot be null");
        Objects.requireNonNull(query, "GraphQL query cannot be null");
        Objects.requireNonNull(resultHandler, "Query result handler cannot be null");

        if (!managedDiscoveries().contains(discoveryName)) {
            resultHandler.handle(Future.failedFuture(
                    "Service discovery with name '" + discoveryName + "' is not managed by this schema consumer"));
            return;
        }
        ServiceDiscovery discovery = discoveryRegistrar().getDiscovery(discoveryName);
        discovery.getRecord(record -> schemaName.equals(record.getName()), rh -> {
            if (rh.succeeded() && rh.result() != null) {
                GraphQLClient.executeQuery(discovery, rh.result(), query, variables, resultHandler);
            } else {
                resultHandler.handle(Future.failedFuture(
                        "Failed to find published schema '" + schemaName + "' in repository: " + discoveryName));
            }
        });
    }

    /**
     * Gets the service discovery instance with the specified name, if the discoverer is managing it.
     *
     * @param discoveryName the name of the service discovery, or {@code null} to get the default service discovery
     * @return optional that contains the service discovery reference if found, otherwise empty
     */
    default Optional<ServiceDiscovery> getDiscovery(String discoveryName) {
        return Optional.ofNullable(discoveryRegistrar().getDiscovery(discoveryName));
    }

    /**
     * Gets the service discovery names of the discovery instances this consumer is listening to.
     *
     * @return the list of service discovery names
     */
    default List<String> managedDiscoveries() {
        return discoveryRegistrar().serviceDiscoveryNames();
    }

    /**
     * Gets the registrar that is used to manage consumer internal state.
     * <p>
     * Clients only need to create and return a valid instance when implementing a {@link SchemaConsumer}. The
     * registrar is controlled by the consumer interface. You only need to keep a reference to it for as long as it
     * is used.
     *
     * @return the discovery registrar
     */
    DiscoveryRegistrar discoveryRegistrar();
}