org.sdase.commons.starter.SdaPlatformBundle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sda-commons-starter Show documentation
Show all versions of sda-commons-starter Show documentation
A libraries to bootstrap services easily that follow the patterns and specifications promoted by the SDA SE
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.");
}
}
}
}