All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.stargate.sgv2.graphql.impl.GraphqlServiceServer Maven / Gradle / Ivy

There is a newer version: 2.0.0-ALPHA-17
Show newest version
/*
 * Copyright The Stargate Authors
 *
 * Licensed 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 io.stargate.sgv2.graphql.impl;

import io.dropwizard.Application;
import io.dropwizard.configuration.ResourceConfigurationSourceProvider;
import io.dropwizard.forms.MultiPartBundle;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.stargate.bridge.proto.Schema;
import io.stargate.core.metrics.api.HttpMetricsTagProvider;
import io.stargate.core.metrics.api.Metrics;
import io.stargate.core.metrics.api.MetricsScraper;
import io.stargate.sgv2.common.grpc.StargateBridgeClient;
import io.stargate.sgv2.common.grpc.StargateBridgeClientFactory;
import io.stargate.sgv2.common.http.CreateStargateBridgeClientFilter;
import io.stargate.sgv2.common.http.StargateBridgeClientJerseyFactory;
import io.stargate.sgv2.graphql.resources.HealthResource;
import io.stargate.sgv2.graphql.resources.MetricsResource;
import io.stargate.sgv2.graphql.web.resources.AdminResource;
import io.stargate.sgv2.graphql.web.resources.DdlResource;
import io.stargate.sgv2.graphql.web.resources.DmlResource;
import io.stargate.sgv2.graphql.web.resources.FilesResource;
import io.stargate.sgv2.graphql.web.resources.GraphqlCache;
import io.stargate.sgv2.graphql.web.resources.PlaygroundResource;
import java.util.Collections;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.glassfish.hk2.api.PerLookup;
import org.glassfish.hk2.utilities.binding.AbstractBinder;

public class GraphqlServiceServer extends Application {

  public static final String MODULE_NAME = "sgv2-graphqlapi";

  private final Metrics metrics;
  private final MetricsScraper metricsScraper;
  private final HttpMetricsTagProvider httpMetricsTagProvider;
  private final int timeoutSeconds;
  private final boolean disablePlayground;
  private final boolean disableDefaultKeyspace;

  public GraphqlServiceServer(
      Metrics metrics,
      MetricsScraper metricsScraper,
      HttpMetricsTagProvider httpMetricsTagProvider,
      int timeoutSeconds,
      boolean enableGraphqlPlayground,
      boolean disableDefaultKeyspace) {
    this.metrics = metrics;
    this.metricsScraper = metricsScraper;
    this.httpMetricsTagProvider = httpMetricsTagProvider;
    this.timeoutSeconds = timeoutSeconds;
    this.disablePlayground = enableGraphqlPlayground;
    this.disableDefaultKeyspace = disableDefaultKeyspace;
  }

  @Override
  public void run(GraphqlServiceServerConfiguration config, Environment environment) {

    JerseyEnvironment jersey = environment.jersey();

    StargateBridgeClientFactory clientFactory =
        StargateBridgeClientFactory.newInstance(
            config.stargate.bridge.buildChannel(),
            timeoutSeconds,
            Schema.SchemaRead.SourceApi.GRAPHQL);
    jersey.register(buildClientFilter(clientFactory));

    GraphqlCache graphqlCache = new GraphqlCache(disableDefaultKeyspace);

    jersey.register(
        new AbstractBinder() {
          @Override
          protected void configure() {
            bind(metricsScraper).to(MetricsScraper.class);
            bindFactory(StargateBridgeClientJerseyFactory.class)
                .to(StargateBridgeClient.class)
                // Note: this should really be `RequestScoped.class`, but using that causes HK2
                // errors.
                // In practice that won't make a difference because our resources look up the client
                // at most once.
                .in(PerLookup.class);
            bind(graphqlCache).to(GraphqlCache.class);
          }
        });
    environment.jersey().register(DdlResource.class);
    environment.jersey().register(DmlResource.class);
    environment.jersey().register(AdminResource.class);
    environment.jersey().register(FilesResource.class);

    if (!disablePlayground) {
      environment.jersey().register(PlaygroundResource.class);
    }

    environment.jersey().register(HealthResource.class);
    environment.jersey().register(MetricsResource.class);

    enableCors(environment);
  }

  private CreateStargateBridgeClientFilter buildClientFilter(
      StargateBridgeClientFactory clientFactory) {
    return new CreateStargateBridgeClientFilter(clientFactory) {
      @Override
      protected Response buildError(Response.Status status, String message, MediaType mediaType) {
        Object entity =
            mediaType != null
                    && ("json".equals(mediaType.getSubtype())
                        || "graphql".equals(mediaType.getSubtype()))
                ? Collections.singletonMap("errors", Collections.singletonList(message))
                : message;
        return Response.status(status).entity(entity).build();
      }
    };
  }

  @Override
  public void initialize(Bootstrap bootstrap) {
    super.initialize(bootstrap);
    bootstrap.setConfigurationSourceProvider(new ResourceConfigurationSourceProvider());
    bootstrap.setMetricRegistry(metrics.getRegistry(MODULE_NAME));
    bootstrap.addBundle(new MultiPartBundle());
  }

  private void enableCors(Environment environment) {
    FilterRegistration.Dynamic filter =
        environment.servlets().addFilter("cors", CrossOriginFilter.class);

    filter.setInitParameter(
        CrossOriginFilter.ALLOWED_METHODS_PARAM, "POST,GET,OPTIONS,PUT,DELETE,PATCH");
    filter.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
    filter.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
    filter.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "*");
    filter.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
    filter.setInitParameter(CrossOriginFilter.EXPOSED_HEADERS_PARAM, "Date");

    filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
  }

  @Override
  protected void bootstrapLogging() {
    // disable dropwizard logging, it will use external logback
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy