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

org.sdase.commons.starter.SdaPlatformBundle Maven / Gradle / Ivy

Go to download

A libraries to bootstrap services easily that follow the patterns and specifications promoted by the SDA SE

There is a newer version: 7.0.87
Show newest version
package org.sdase.commons.starter;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.dropwizard.core.Configuration;
import io.dropwizard.core.ConfiguredBundle;
import io.dropwizard.core.setup.Bootstrap;
import io.dropwizard.core.setup.Environment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import org.sdase.commons.server.auth.AuthBundle;
import org.sdase.commons.server.auth.config.AuthConfigProvider;
import org.sdase.commons.server.consumer.ConsumerTokenBundle;
import org.sdase.commons.server.cors.CorsBundle;
import org.sdase.commons.server.cors.CorsConfigProvider;
import org.sdase.commons.server.dropwizard.bundles.ConfigurationSubstitutionBundle;
import org.sdase.commons.server.dropwizard.bundles.DefaultLoggingConfigurationBundle;
import org.sdase.commons.server.dropwizard.bundles.MetadataContextBundle;
import org.sdase.commons.server.healthcheck.InternalHealthCheckEndpointBundle;
import org.sdase.commons.server.jackson.JacksonConfigurationBundle;
import org.sdase.commons.server.opa.OpaBundle;
import org.sdase.commons.server.opa.OpaBundle.OpaBuilder;
import org.sdase.commons.server.opa.config.OpaConfigProvider;
import org.sdase.commons.server.openapi.OpenApiBundle;
import org.sdase.commons.server.opentelemetry.OpenTelemetryBundle;
import org.sdase.commons.server.prometheus.PrometheusBundle;
import org.sdase.commons.server.security.SecurityBundle;
import org.sdase.commons.server.trace.TraceTokenBundle;
import org.sdase.commons.starter.builder.CustomConfigurationProviders.AuthConfigProviderBuilder;
import org.sdase.commons.starter.builder.CustomConfigurationProviders.CorsConfigProviderBuilder;
import org.sdase.commons.starter.builder.InitialPlatformBundleBuilder;
import org.sdase.commons.starter.builder.OpenApiCustomizer.OpenApiFinalBuilder;
import org.sdase.commons.starter.builder.OpenApiCustomizer.OpenApiInitialBuilder;
import org.sdase.commons.starter.builder.PlatformBundleBuilder;

/**
 * A {@link ConfiguredBundle} that configures the application with the basics required for a SDA
 * platform compatible microservice.
 */
public class SdaPlatformBundle implements ConfiguredBundle {

  private final SecurityBundle.Builder securityBundleBuilder;
  private final JacksonConfigurationBundle.Builder jacksonConfigurationBundleBuilder;
  private final AuthBundle.AuthBuilder authBundleBuilder;
  private final OpaBuilder opaBundleBuilder;
  private final CorsBundle.FinalBuilder corsBundleBuilder;
  private final OpenApiBundle.FinalBuilder openApiBundleBuilder;

  private final List excludedTracingUrls =
      Arrays.asList(
          "/ping", "/healthcheck", "/healthcheck/internal", "/metrics", "/metrics/prometheus");

  private SdaPlatformBundle(
      SecurityBundle.Builder securityBundleBuilder,
      JacksonConfigurationBundle.Builder jacksonConfigurationBundleBuilder,
      AuthBundle.AuthBuilder authBundleBuilder,
      OpaBundle.OpaBuilder opaBundleBuilder,
      CorsBundle.FinalBuilder corsBundleBuilder,
      OpenApiBundle.FinalBuilder openApiBundleBuilder) {
    this.securityBundleBuilder = securityBundleBuilder;
    this.jacksonConfigurationBundleBuilder = jacksonConfigurationBundleBuilder;
    this.authBundleBuilder = authBundleBuilder;
    this.opaBundleBuilder = opaBundleBuilder;
    this.corsBundleBuilder = corsBundleBuilder;
    this.openApiBundleBuilder = openApiBundleBuilder;
  }

  public static InitialPlatformBundleBuilder builder() {
    return new InitialBuilder<>();
  }

  @Override
  public void initialize(Bootstrap bootstrap) {

    // add normal bundles
    bootstrap.addBundle(
        OpenTelemetryBundle.builder()
            .withAutoConfiguredTelemetryInstance()
            .withExcludedUrlsPattern(Pattern.compile(String.join("|", excludedTracingUrls)))
            .build());
    bootstrap.addBundle(ConfigurationSubstitutionBundle.builder().build());
    bootstrap.addBundle(DefaultLoggingConfigurationBundle.builder().build());
    bootstrap.addBundle(InternalHealthCheckEndpointBundle.builder().build());
    bootstrap.addBundle(PrometheusBundle.builder().build());
    bootstrap.addBundle(TraceTokenBundle.builder().build());
    bootstrap.addBundle(MetadataContextBundle.builder().build());

    // add configured bundles
    List> configuredBundles = new ArrayList<>();
    configuredBundles.add(jacksonConfigurationBundleBuilder.build());
    configuredBundles.add(securityBundleBuilder.build());
    if (openApiBundleBuilder != null) {
      configuredBundles.add(openApiBundleBuilder.build());
    }
    if (authBundleBuilder != null) {
      configuredBundles.add(authBundleBuilder.build());
    }
    if (opaBundleBuilder != null) {
      configuredBundles.add(opaBundleBuilder.build());
    }
    if (corsBundleBuilder != null) {
      configuredBundles.add(corsBundleBuilder.build());
    }
    configuredBundles.add(ConsumerTokenBundle.builder().withOptionalConsumerToken().build());
    configuredBundles.stream().map(ConfiguredBundle.class::cast).forEach(bootstrap::addBundle);
  }

  @Override
  public void run(C configuration, Environment environment) {
    // not needed for the platform bundle, created bundles are added in initialize
  }

  public static class InitialBuilder
      implements InitialPlatformBundleBuilder,
          AuthConfigProviderBuilder,
          CorsConfigProviderBuilder,
          OpenApiInitialBuilder,
          OpenApiFinalBuilder,
          PlatformBundleBuilder {

    private AuthBundle.AuthBuilder authBundleBuilder;
    private OpaBundle.OpaBuilder opaBundleBuilder;
    private SecurityBundle.Builder securityBundleBuilder = SecurityBundle.builder();
    private final JacksonConfigurationBundle.Builder jacksonBundleBuilder =
        JacksonConfigurationBundle.builder();
    private CorsBundle.FinalBuilder corsBundleBuilder;
    private OpenApiBundle.FinalBuilder openApiBundleBuilder;

    private InitialBuilder() {}

    // Final step

    @Override
    public SdaPlatformBundle build() {
      return new SdaPlatformBundle<>(
          securityBundleBuilder,
          jacksonBundleBuilder,
          authBundleBuilder,
          opaBundleBuilder,
          corsBundleBuilder,
          openApiBundleBuilder);
    }

    // InitialBuilder

    @Override
    public OpenApiInitialBuilder usingSdaPlatformConfiguration() {
      return usingSdaPlatformConfiguration(SdaPlatformConfiguration.class);
    }

    @Override
    public 
        OpenApiInitialBuilder usingSdaPlatformConfiguration(Class configurationClass) {
      return usingCustomConfig(configurationClass)
          .withOpaAuthorization(SdaPlatformConfiguration::getAuth, SdaPlatformConfiguration::getOpa)
          .withCorsConfigProvider(SdaPlatformConfiguration::getCors);
    }

    @Override
    public  AuthConfigProviderBuilder usingCustomConfig(
        Class configurationClass) {
      return new InitialBuilder<>();
    }

    // CustomConfigurationProviders and follow up configuration providers

    @Override
    public CorsConfigProviderBuilder withoutAuthentication() {
      return this;
    }

    @Override
    public CorsConfigProviderBuilder withAuthConfigProvider(
        AuthConfigProvider authConfigProvider) {
      this.authBundleBuilder =
          AuthBundle.builder()
              .withAuthConfigProvider(authConfigProvider)
              .withAnnotatedAuthorization();
      return this;
    }

    @Override
    public CorsConfigProviderBuilder withOpaAuthorization(
        AuthConfigProvider authConfigProvider, OpaConfigProvider opaConfigProvider) {
      this.authBundleBuilder =
          AuthBundle.builder()
              .withAuthConfigProvider(authConfigProvider)
              .withExternalAuthorization();
      this.opaBundleBuilder = OpaBundle.builder().withOpaConfigProvider(opaConfigProvider);
      return this;
    }

    @Override
    public OpenApiInitialBuilder withoutCorsSupport() {
      return this;
    }

    @Override
    public OpenApiInitialBuilder withCorsConfigProvider(
        CorsConfigProvider corsConfigProvider) {
      this.corsBundleBuilder = CorsBundle.builder().withCorsConfigProvider(corsConfigProvider);
      return this;
    }

    // PlatformBundleBuilder contains programmatic configuration

    @Override
    public PlatformBundleBuilder disableBufferLimitValidationSecurityFeature() {
      this.securityBundleBuilder = this.securityBundleBuilder.disableBufferLimitValidation();
      return this;
    }

    @Override
    public PlatformBundleBuilder withFrontendSupport() {
      this.securityBundleBuilder = this.securityBundleBuilder.withFrontendSupport();
      return this;
    }

    @Override
    public PlatformBundleBuilder withCorsAllowedMethods(String... httpMethods) {
      validateConfigureCors();
      this.corsBundleBuilder.withAllowedMethods(httpMethods);
      return this;
    }

    @Override
    public PlatformBundleBuilder withCorsAdditionalAllowedHeaders(
        String... additionalAllowedHeaders) {
      validateConfigureCors();
      this.corsBundleBuilder.withAdditionalAllowedHeaders(additionalAllowedHeaders);
      return this;
    }

    @Override
    public PlatformBundleBuilder withCorsAdditionalExposedHeaders(
        String... additionalExposedHeaders) {
      validateConfigureCors();
      this.corsBundleBuilder.withAdditionalExposedHeaders(additionalExposedHeaders);
      return this;
    }

    @Override
    public PlatformBundleBuilder withoutHalSupport() {
      this.jacksonBundleBuilder.withoutHalSupport();
      return this;
    }

    @Override
    public PlatformBundleBuilder withoutFieldFilter() {
      this.jacksonBundleBuilder.withoutFieldFilter();
      return this;
    }

    @Override
    public PlatformBundleBuilder withObjectMapperCustomization(
        Consumer customizer) {
      this.jacksonBundleBuilder.withCustomization(customizer);
      return this;
    }

    @Override
    public PlatformBundleBuilder alwaysWriteZonedDateTimeWithMillisInJson() {
      this.jacksonBundleBuilder.alwaysWriteZonedDateTimeWithMillis();
      return this;
    }

    @Override
    public PlatformBundleBuilder alwaysWriteZonedDateTimeWithoutMillisInJson() {
      this.jacksonBundleBuilder.alwaysWriteZonedDateTimeWithoutMillis();
      return this;
    }

    @Override
    public OpenApiFinalBuilder withExistingOpenAPI(String openApiJsonOrYaml) {
      this.openApiBundleBuilder = getOpenApiBuilder().withExistingOpenAPI(openApiJsonOrYaml);
      return this;
    }

    @Override
    public OpenApiFinalBuilder withExistingOpenAPIFromClasspathResource(String path) {
      this.openApiBundleBuilder =
          getOpenApiBuilder().withExistingOpenAPIFromClasspathResource(path);
      return this;
    }

    @Override
    public OpenApiFinalBuilder addOpenApiResourcePackage(String resourcePackage) {
      this.openApiBundleBuilder = getOpenApiBuilder().addResourcePackage(resourcePackage);
      return this;
    }

    @Override
    public OpenApiFinalBuilder addOpenApiResourcePackageClass(Class swaggerResourcePackage) {
      this.openApiBundleBuilder =
          getOpenApiBuilder().addResourcePackageClass(swaggerResourcePackage);
      return this;
    }

    // helper

    private OpenApiBundle.InitialBuilder getOpenApiBuilder() {
      return openApiBundleBuilder != null ? openApiBundleBuilder : OpenApiBundle.builder();
    }

    private void validateConfigureCors() {
      if (this.corsBundleBuilder == null) {
        throw new IllegalStateException(
            "Attempt to configure CORS details, but CORS is not active.");
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy