From 0866dd91f564f3e73d85f317fad02647500e5f49 Mon Sep 17 00:00:00 2001 From: luigi Date: Tue, 19 Aug 2025 15:37:59 -0700 Subject: [PATCH 1/7] change dir name --- .../AbstractConstraintTraitGenerator.kt | 2 +- .../{contraints => constraints}/ConstraintGenerator.kt | 2 +- .../{contraints => constraints}/ConstraintUtilsGenerator.kt | 2 +- .../{contraints => constraints}/LengthConstraintGenerator.kt | 2 +- .../{contraints => constraints}/PatternConstraintGenerator.kt | 2 +- .../{contraints => constraints}/RangeConstraintGenerator.kt | 2 +- .../RequiredConstraintGenerator.kt | 2 +- .../UniqueItemsConstraintGenerator.kt | 2 +- .../codegen/service/{contraints => constraints}/utils.kt | 2 +- .../smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt | 4 ++-- 10 files changed, 11 insertions(+), 11 deletions(-) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/AbstractConstraintTraitGenerator.kt (57%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/ConstraintGenerator.kt (97%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/ConstraintUtilsGenerator.kt (98%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/LengthConstraintGenerator.kt (94%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/PatternConstraintGenerator.kt (89%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/RangeConstraintGenerator.kt (93%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/RequiredConstraintGenerator.kt (88%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/UniqueItemsConstraintGenerator.kt (90%) rename codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/{contraints => constraints}/utils.kt (94%) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/AbstractConstraintTraitGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/AbstractConstraintTraitGenerator.kt similarity index 57% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/AbstractConstraintTraitGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/AbstractConstraintTraitGenerator.kt index 29650a459..fc9c0319c 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/AbstractConstraintTraitGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/AbstractConstraintTraitGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints internal abstract class AbstractConstraintTraitGenerator { abstract fun render() diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt similarity index 97% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt index e6af9bb15..be808c63e 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.GenerationContext import software.amazon.smithy.kotlin.codegen.core.KotlinDelegator diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintUtilsGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt similarity index 98% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintUtilsGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt index 5c7e81753..bda1a3b5b 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/ConstraintUtilsGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.GenerationContext import software.amazon.smithy.kotlin.codegen.core.KotlinDelegator diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/LengthConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/LengthConstraintGenerator.kt similarity index 94% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/LengthConstraintGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/LengthConstraintGenerator.kt index 15a0e7aa3..04cef3ea9 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/LengthConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/LengthConstraintGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.kotlin.codegen.service.ServiceTypes diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/PatternConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/PatternConstraintGenerator.kt similarity index 89% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/PatternConstraintGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/PatternConstraintGenerator.kt index 137e208dd..9c0227819 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/PatternConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/PatternConstraintGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.model.traits.PatternTrait diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/RangeConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/RangeConstraintGenerator.kt similarity index 93% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/RangeConstraintGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/RangeConstraintGenerator.kt index dea33967b..9c2eeeb27 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/RangeConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/RangeConstraintGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.model.traits.RangeTrait diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/RequiredConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/RequiredConstraintGenerator.kt similarity index 88% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/RequiredConstraintGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/RequiredConstraintGenerator.kt index 03b37ed2b..a0fc814a9 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/RequiredConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/RequiredConstraintGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.model.traits.RequiredTrait diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/UniqueItemsConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/UniqueItemsConstraintGenerator.kt similarity index 90% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/UniqueItemsConstraintGenerator.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/UniqueItemsConstraintGenerator.kt index c4c1552ee..644b2bc99 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/UniqueItemsConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/UniqueItemsConstraintGenerator.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.kotlin.codegen.service.ServiceTypes diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/utils.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/utils.kt similarity index 94% rename from codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/utils.kt rename to codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/utils.kt index 078655365..82985ac9f 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/contraints/utils.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/utils.kt @@ -1,4 +1,4 @@ -package software.amazon.smithy.kotlin.codegen.service.contraints +package software.amazon.smithy.kotlin.codegen.service.constraints import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.model.traits.LengthTrait diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt index 72a5c1269..aae041950 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt @@ -6,8 +6,8 @@ import software.amazon.smithy.kotlin.codegen.core.InlineCodeWriterFormatter import software.amazon.smithy.kotlin.codegen.core.KotlinDelegator import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.kotlin.codegen.service.AbstractStubGenerator -import software.amazon.smithy.kotlin.codegen.service.contraints.ConstraintGenerator -import software.amazon.smithy.kotlin.codegen.service.contraints.ConstraintUtilsGenerator +import software.amazon.smithy.kotlin.codegen.service.constraints.ConstraintGenerator +import software.amazon.smithy.kotlin.codegen.service.constraints.ConstraintUtilsGenerator import software.amazon.smithy.utils.AbstractCodeWriter class LoggingWriter(parent: LoggingWriter? = null) : AbstractCodeWriter() { From c10d1c8ac77161b313d97f98467eb28f6485b53e Mon Sep 17 00:00:00 2001 From: luigi Date: Tue, 19 Aug 2025 16:24:22 -0700 Subject: [PATCH 2/7] add comments --- .../service/ServiceStubConfigurations.kt | 16 +++++ .../codegen/service/ServiceStubGenerator.kt | 64 ++++++++++++++++--- .../constraints/ConstraintGenerator.kt | 30 +++++++++ .../constraints/ConstraintUtilsGenerator.kt | 29 +++++++++ .../codegen/service/ktor/Authentication.kt | 9 +++ .../codegen/service/ktor/AuthenticationAWS.kt | 32 ++++++++++ .../codegen/service/ktor/KtorStubGenerator.kt | 23 +++++-- .../codegen/service/ktor/OperationHandlers.kt | 12 ++++ .../kotlin/codegen/service/ktor/Plugins.kt | 28 ++++++++ .../kotlin/codegen/service/ktor/Routing.kt | 37 +++++++++++ .../ktor/ServerFrameworkImplementation.kt | 8 +++ .../kotlin/codegen/service/ktor/Utils.kt | 16 +++++ .../smithy/kotlin/codegen/service/utils.kt | 4 ++ 13 files changed, 295 insertions(+), 13 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubConfigurations.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubConfigurations.kt index 869866929..012f55717 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubConfigurations.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubConfigurations.kt @@ -12,6 +12,16 @@ import software.amazon.smithy.model.traits.HttpPayloadTrait import software.amazon.smithy.model.traits.MediaTypeTrait import software.amazon.smithy.protocol.traits.Rpcv2CborTrait +/** + * Enumeration of supported media types used by the generated service. + * + * These values define how payloads are encoded/decoded: + * - `CBOR` → Concise Binary Object Representation + * - `JSON` → JSON encoding + * - `PLAIN_TEXT` → Text/plain + * - `OCTET_STREAM` → Binary data + * - `ANY` → Fallback for arbitrary content types + */ enum class MediaType(val value: String) { CBOR("CBOR"), JSON("JSON"), @@ -57,6 +67,12 @@ enum class MediaType(val value: String) { } } +/** + * Enumeration of supported service frameworks for generated stubs. + * + * Currently only supports: + * - `KTOR`: Generates Ktor-based service stubs + */ enum class ServiceFramework(val value: String) { KTOR("ktor"), ; diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubGenerator.kt index 564937ebc..ef3a46a7b 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ServiceStubGenerator.kt @@ -10,10 +10,29 @@ import software.amazon.smithy.kotlin.codegen.core.withBlock import software.amazon.smithy.kotlin.codegen.core.withInlineBlock import software.amazon.smithy.model.knowledge.TopDownIndex +/** + * Interface representing a generator that produces service stubs (boilerplate code) for a Smithy service. + */ internal interface ServiceStubGenerator { + /** + * Render the stub code into the target files. + */ fun render() } +/** + * Abstract base class for generating service stubs. + * + * Provides a framework for generating common service artifacts such as: + * - Configuration (`ServiceFrameworkConfig.kt`) + * - Framework bootstrap (`ServiceFramework.kt`) + * - Plugins, utils, authentication, validators + * - Operation handlers and routing + * - Main launcher (`Main.kt`) + * + * Concrete subclasses must implement abstract methods for framework-specific + * code (e.g., Ktor). + */ internal abstract class AbstractStubGenerator( val ctx: GenerationContext, val delegator: KotlinDelegator, @@ -27,6 +46,10 @@ internal abstract class AbstractStubGenerator( val pkgName = ctx.settings.pkg.name + /** + * Render all service stub files by invoking the component renderers. + * This acts as the main entrypoint for code generation. + */ final override fun render() { renderServiceFrameworkConfig() renderServiceFramework() @@ -39,7 +62,16 @@ internal abstract class AbstractStubGenerator( renderMainFile() } - /** Emits the `ServiceFrameworkConfig.kt` file. */ + /** + * Generate the service configuration file (`ServiceFrameworkConfig.kt`). + * + * Defines enums for: + * - `LogLevel`: Logging verbosity levels + * - `ServiceEngine`: Available server engines (Netty, CIO, Jetty) + * + * Provides a singleton `ServiceFrameworkConfig` object that stores runtime + * settings such as port, engine, region, timeouts, and log level. + */ protected fun renderServiceFrameworkConfig() { delegator.useFileWriter("ServiceFrameworkConfig.kt", "${ctx.settings.pkg.name}.config") { writer -> writer.withBlock("internal enum class LogLevel(val value: String) {", "}") { @@ -143,7 +175,12 @@ internal abstract class AbstractStubGenerator( } } - /** Emits ServiceFramework.kt and other engine bootstrap code. */ + /** + * Generate the service framework interface and bootstrap (`ServiceFramework.kt`). + * + * Declares a common `ServiceFramework` interface with lifecycle methods and + * delegates framework-specific implementation details to subclasses. + */ protected fun renderServiceFramework() { delegator.useFileWriter("ServiceFramework.kt", "${ctx.settings.pkg.name}.framework") { writer -> @@ -157,27 +194,36 @@ internal abstract class AbstractStubGenerator( } } + /** Render the specific server framework implementation (e.g., Ktor). */ protected abstract fun renderServerFrameworkImplementation(writer: KotlinWriter) - /** Emits content-type guards, error handler plugins, … */ + /** Generate service plugins such as content-type guards, error handlers, etc. */ protected abstract fun renderPlugins() - /** Emits utils. */ + /** Generate supporting utility classes and functions. */ protected abstract fun renderUtils() - /** Auth interfaces & installers (bearer, IAM, …). */ + /** Generate authentication module interfaces and installers (e.g., bearer auth, SigV4, SigV4A). */ protected abstract fun renderAuthModule() - /** Request-level Smithy constraint validators. */ + /** Generate request-level constraint validators for Smithy model constraints. */ protected abstract fun renderConstraintValidators() - /** One handler file per Smithy operation. */ + /** Generate a request handler for each Smithy operation. */ protected abstract fun renderPerOperationHandlers() - /** Route table that maps operations → runtime endpoints. */ + /** Generate the route table that maps Smithy operations to runtime endpoints. */ protected abstract fun renderRouting() - /** Writes the top-level `Main.kt` launcher. */ + /** + * Generate the top-level `Main.kt` launcher file. + * + * This file provides the `main()` entrypoint: + * - Parses command-line arguments + * - Applies defaults for configuration values + * - Initializes the `ServiceFrameworkConfig` + * - Starts the appropriate service framework + */ protected fun renderMainFile() { val portName = "port" val engineFactoryName = "engineFactory" diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt index be808c63e..83a3bf71c 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintGenerator.kt @@ -10,6 +10,16 @@ import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.traits.RequiredTrait import kotlin.collections.iterator +/** + * Generates validation code for request constraints on Smithy operation inputs. + * + * For a given [operation], this generator traverses the input structure and: + * - Recursively inspects members of structures and lists. + * - Applies trait-based validations (e.g., required, length, range). + * - Emits Kotlin validation functions that check constraints at runtime. + * + * Output is written into a `RequestConstraints.kt` file in the generated `constraints` package. + */ internal class ConstraintGenerator( val ctx: GenerationContext, val operation: OperationShape, @@ -21,9 +31,23 @@ internal class ConstraintGenerator( val opName = operation.id.name val pkgName = ctx.settings.pkg.name + /** + * Entry point for emitting validation code for the operation’s request type. + * Delegates to [renderRequestConstraintsValidation]. + */ fun render() { renderRequestConstraintsValidation() } + + /** + * Recursively generates validation code for a given [memberShape]. + * + * - If the target is a list, iterates over elements and validates them. + * - If the target is a structure, recursively validates its members. + * - For each trait (on the member or its target), invokes the matching trait generator. + * - `@required` traits are always enforced. + * - Other traits are wrapped in a null check before validation. + */ private fun generateConstraintValidations(prefix: String, memberShape: MemberShape, writer: KotlinWriter) { val targetShape = ctx.model.expectShape(memberShape.target) @@ -59,6 +83,12 @@ internal class ConstraintGenerator( } } + /** + * Writes the top-level validation function for the operation’s input type. + * + * Inside, it calls [generateConstraintValidations] for each input member, + * ensuring all modeled constraints are enforced. + */ private fun renderRequestConstraintsValidation() { delegator.useFileWriter("${opName}RequestConstraints.kt", "$pkgName.constraints") { writer -> val inputShape = ctx.model.expectShape(operation.input.get()) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt index bda1a3b5b..c1ace3707 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/constraints/ConstraintUtilsGenerator.kt @@ -5,6 +5,15 @@ import software.amazon.smithy.kotlin.codegen.core.KotlinDelegator import software.amazon.smithy.kotlin.codegen.core.KotlinWriter import software.amazon.smithy.kotlin.codegen.core.withBlock +/** + * Generates utility functions to support constraint validation for Smithy models. + * + * This generator emits reusable helpers that can be called from operation-specific + * validation code (e.g., generated by [ConstraintGenerator]). These helpers enforce + * common traits like `@length` and `@uniqueItems`. + * + * Output is written into a `utils.kt` file under the generated `constraints` package. + */ internal class ConstraintUtilsGenerator( val ctx: GenerationContext, val delegator: KotlinDelegator, @@ -20,6 +29,16 @@ internal class ConstraintUtilsGenerator( } } + /** + * Emits the `sizeOf()` function. + * + * This utility computes a generalized "size" for multiple types: + * - Collections, arrays, maps → `size` + * - Strings → Unicode code point count + * - Byte arrays → length + * + * Any unsupported type will throw an `IllegalArgumentException`. + */ private fun renderLengthTraitUtils(writer: KotlinWriter) { writer.withBlock("internal fun sizeOf(value: Any?): Long = when (value) {", "}") { write("is Collection<*> -> value.size.toLong()") @@ -34,6 +53,16 @@ internal class ConstraintUtilsGenerator( } } + /** + * Emits the `hasAllUniqueElements()` function. + * + * This utility checks if a list contains only unique elements, where uniqueness + * is defined by deep structural equality: + * - Primitive wrappers (String, Boolean, Number, Instant) → compared by value + * - Byte arrays → compared by contents + * - Lists → recursively compared element by element + * - Maps → recursively compared entries by key/value + */ private fun renderUniqueItemsTraitUtils(writer: KotlinWriter) { writer.withBlock("internal fun hasAllUniqueElements(elements: List): Boolean {", "}") { withBlock("class Wrapped(private val v: Any?) {", "}") { diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Authentication.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Authentication.kt index 1dcc6eba7..5cac41a4b 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Authentication.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Authentication.kt @@ -7,6 +7,15 @@ import software.amazon.smithy.kotlin.codegen.core.withBlock import software.amazon.smithy.kotlin.codegen.model.getTrait import software.amazon.smithy.kotlin.codegen.service.ServiceTypes +/** + * Writes Ktor-based authentication support classes and configuration + * for a generated service. + * + * This generates three files: + * 1. UserPrincipal.kt → Represents the authenticated user. + * 2. Validation.kt → Provides bearer token validation logic. + * 3. Authentication.kt → Configures authentication providers in Ktor. + */ internal fun KtorStubGenerator.writeAuthentication() { delegator.useFileWriter("UserPrincipal.kt", "$pkgName.auth") { writer -> writer.withBlock("public data class UserPrincipal(", ")") { diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/AuthenticationAWS.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/AuthenticationAWS.kt index 5e258707d..e174f19c6 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/AuthenticationAWS.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/AuthenticationAWS.kt @@ -7,6 +7,14 @@ import software.amazon.smithy.kotlin.codegen.core.withBlock import software.amazon.smithy.kotlin.codegen.core.withInlineBlock import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes +/** + * Writes AWS-specific authentication support for Ktor service stubs. + * + * This generates the following files: + * - AWSValidation.kt → Stub stores for SigV4 credentials and SigV4A public keys. + * - AWSSigV4.kt → Ktor authentication provider and verifier for AWS Signature V4 (HMAC). + * - AWSSigV4A.kt → Ktor authentication provider and verifier for AWS Signature V4A (ECDSA). + */ internal fun KtorStubGenerator.writeAWSAuthentication() { delegator.useFileWriter("AWSValidation.kt", "$pkgName.auth") { writer -> writer.withBlock("internal object SigV4CredentialStore {", "}") { @@ -213,6 +221,10 @@ internal fun KtorStubGenerator.writeAWSAuthentication() { } } +/** + * Extracts and parses AWS authentication header information + * (Credential, SignedHeaders, Signature) from a request. + */ private fun retrieveAuthInformation(writer: KotlinWriter, algorithm: String) { writer.write("val authHeader = call.request.#T(#T.Authorization) ?: return null", RuntimeTypes.KtorServerRouting.requestHeader, RuntimeTypes.KtorServerHttp.HttpHeaders) .write("if (!authHeader.startsWith(#S, ignoreCase = true)) return null", algorithm) @@ -229,6 +241,9 @@ private fun retrieveAuthInformation(writer: KotlinWriter, algorithm: String) { .write("val accessKeyId = credential.substringBefore(#S).takeIf { it.matches(Regex(#S)) } ?: return null", "/", "^[A-Z0-9]{16,128}$") } +/** + * Validates signing date against request scope date and clock skew. + */ private fun authDateValidation(writer: KotlinWriter) { writer.write("val rawXAmzDate = call.request.#T(#S)", RuntimeTypes.KtorServerRouting.requestHeader, "X-Amz-Date") .write("val rawHttpDate = call.request.#T(#T.Date)", RuntimeTypes.KtorServerRouting.requestHeader, RuntimeTypes.KtorServerHttp.HttpHeaders) @@ -244,6 +259,10 @@ private fun authDateValidation(writer: KotlinWriter) { .write("if (signingInstant < now - maxClockSkew || signingInstant > now + maxClockSkew) return null") } +/** + * Builds a full HttpRequestBuilder object from the Ktor request, + * used for SigV4 canonical request signing. + */ private fun createHttpRequestBuilder(writer: KotlinWriter) { writer.write("val origin = call.request.local") .write("val payload: ByteArray = call.#T()", RuntimeTypes.KtorServerRouting.requestReceive) @@ -287,6 +306,9 @@ private fun createHttpRequestBuilder(writer: KotlinWriter) { } } +/** + * Builds a canonical request string for SigV4A verification. + */ private fun createCanonicalRequest(writer: KotlinWriter) { writer.write("val origin = call.request.local") .write("val payload: ByteArray = call.#T()", RuntimeTypes.KtorServerRouting.requestReceive) @@ -353,6 +375,9 @@ private fun createCanonicalRequest(writer: KotlinWriter) { } } +/** + * Performs AWS SigV4 signature validation against expected HMAC. + */ private fun validateSigV4(writer: KotlinWriter) { writer.withBlock("val signer = #T(", ")", RuntimeTypes.Auth.HttpAuthAws.AwsHttpSigner) { withBlock("#T.Config().apply {", "}", RuntimeTypes.Auth.HttpAuthAws.AwsHttpSigner) { @@ -389,6 +414,9 @@ private fun validateSigV4(writer: KotlinWriter) { .write("val expectedSig = expectedAuth.substringAfter(#S).trim()", "Signature=") } +/** + * Performs AWS SigV4A signature validation against ECDSA public key. + */ private fun validateSigV4A(writer: KotlinWriter) { writer.write("val crHashHex = sha256Hex(canonicalRequest.toByteArray())") .withBlock("val stringToSign = buildString {", "}") { @@ -405,6 +433,10 @@ private fun validateSigV4A(writer: KotlinWriter) { .write("val ok = verifier.verify(sigDer)") } +/** + * Writes common helper functions used by SigV4 and SigV4A verification, + * such as hashing, encoding, and canonical path/query building. + */ private fun renderHelperFunctions(writer: KotlinWriter) { writer.withBlock("private fun sha256Hex(bytes: ByteArray): String {", "}") { write("return java.security.MessageDigest.getInstance(#S).digest(bytes).joinToString(#S) { #S.format(it) }", "SHA-256", "", "%02x") diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt index aae041950..e578020e8 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/KtorStubGenerator.kt @@ -20,33 +20,48 @@ class LoggingWriter(parent: LoggingWriter? = null) : AbstractCodeWriter ConstraintGenerator(ctx, operation, delegator).render() } } - // Writes `Routing.kt` that maps Smithy operations → Ktor routes. + /** Generate routing file mapping Smithy operations to Ktor routes. */ override fun renderRouting() = writeRouting() + /** Generate plugin configurations (e.g., error handlers, guards). */ override fun renderPlugins() = writePlugins() - // Emits one stub handler per Smithy operation (`OperationNameHandler.kt`). + /** Generate stub handler files for each Smithy operation. */ override fun renderPerOperationHandlers() = writePerOperationHandlers() } diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/OperationHandlers.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/OperationHandlers.kt index 6ad170e4f..b9be8a925 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/OperationHandlers.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/OperationHandlers.kt @@ -2,6 +2,18 @@ package software.amazon.smithy.kotlin.codegen.service.ktor import software.amazon.smithy.kotlin.codegen.core.withBlock +/** + * Generates stub handler files for each Smithy operation. + * + * For every operation, this creates an `OperationNameOperation.kt` file + * under the `operations` package containing: + * - A `handleRequest()` function + * - TODO implementation guidance for constructing response objects + * - Documentation of available custom errors + * + * Each generated handler accepts the operation's input type and returns + * the operation's output type. + */ internal fun KtorStubGenerator.writePerOperationHandlers() { operations.forEach { shape -> val inputShape = ctx.model.expectShape(shape.input.get()) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Plugins.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Plugins.kt index 85f5fa04e..d39b519ee 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Plugins.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Plugins.kt @@ -5,12 +5,28 @@ import software.amazon.smithy.kotlin.codegen.core.withBlock import software.amazon.smithy.kotlin.codegen.core.withInlineBlock import software.amazon.smithy.kotlin.codegen.service.ServiceTypes +/** + * Entry point for writing plugin modules (error handling, content-type guard, accept-type guard). + * + * Generates three files under the `plugins` package: + * - `ErrorHandler.kt`: common error envelope and exception-to-response mapping + * - `ContentTypeGuard.kt`: validates request `Content-Type` header + * - `AcceptTypeGuard.kt`: validates request `Accept` header + */ internal fun KtorStubGenerator.writePlugins() { renderErrorHandler() renderContentTypeGuard() renderAcceptTypeGuard() } +/** + * Generates `ErrorHandler.kt`, which contains: + * - `ErrorEnvelope` exception wrapper for standard error responses + * - JSON and CBOR serialization for error payloads + * - Extension to respond with an `ErrorEnvelope` + * - `configureErrorHandling()` that installs a `StatusPages` plugin + * mapping HTTP status codes and exceptions → structured error responses + */ private fun KtorStubGenerator.renderErrorHandler() { delegator.useFileWriter("ErrorHandler.kt", "$pkgName.plugins") { writer -> writer.write("internal val ResponseHandledKey = #T(#S)", RuntimeTypes.KtorServerUtils.AttributeKey, "ResponseHandled") @@ -130,6 +146,12 @@ private fun KtorStubGenerator.renderErrorHandler() { } } +/** + * Generates `ContentTypeGuard.kt`, which installs a route-scoped plugin that: + * - Defines a configurable allow-list of acceptable request `Content-Type`s + * - Rejects unsupported media types with an `ErrorEnvelope` + * - Provides convenience configuration (e.g., `json()`, `cbor()`, `binary()`) + */ private fun KtorStubGenerator.renderContentTypeGuard() { delegator.useFileWriter("ContentTypeGuard.kt", "$pkgName.plugins") { writer -> @@ -192,6 +214,12 @@ private fun KtorStubGenerator.renderContentTypeGuard() { } } +/** + * Generates `AcceptTypeGuard.kt`, which installs a route-scoped plugin that: + * - Defines a configurable allow-list of acceptable `Accept` header values + * - Rejects unsupported response types with an `ErrorEnvelope` + * - Provides convenience configuration (e.g., `json()`, `cbor()`, `text()`) + */ private fun KtorStubGenerator.renderAcceptTypeGuard() { delegator.useFileWriter("AcceptTypeGuard.kt", "${ctx.settings.pkg.name}.plugins") { writer -> diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt index fcadf0f2a..905cb0d91 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt @@ -33,6 +33,14 @@ import software.amazon.smithy.model.traits.HttpTrait import software.amazon.smithy.model.traits.MediaTypeTrait import software.amazon.smithy.model.traits.TimestampFormatTrait +/** + * Generates Ktor server routing for all operations in the service model. + * + * - Creates `Routing.kt` file. + * - Installs appropriate content-type and accept-type guards. + * - Handles request deserialization, validation, business logic invocation, + * response serialization, and error handling. + */ internal fun KtorStubGenerator.writeRouting() { delegator.useFileWriter("Routing.kt", pkgName) { writer -> operations.forEach { shape -> @@ -206,6 +214,10 @@ internal fun KtorStubGenerator.writeRouting() { } } +/** + * Reads `HttpLabelTrait` annotated members from request URI parameters + * and casts them to appropriate Kotlin types before populating request object. + */ private fun KtorStubGenerator.readHttpLabel(shape: OperationShape, writer: KotlinWriter) { val inputShape = ctx.model.expectShape(shape.input.get()) inputShape.allMembers @@ -229,6 +241,11 @@ private fun KtorStubGenerator.readHttpLabel(shape: OperationShape, writer: Kotli } } +/** + * Reads `HttpQueryTrait` and `HttpQueryParamsTrait` annotated members + * from query parameters. Handles both simple and list-valued query params, + * casting them to correct Kotlin types before populating request object. + */ private fun KtorStubGenerator.readHttpQuery(shape: OperationShape, writer: KotlinWriter) { val inputShape = ctx.model.expectShape(shape.input.get()) val httpQueryKeys = mutableSetOf() @@ -298,6 +315,11 @@ private fun KtorStubGenerator.readHttpQuery(shape: OperationShape, writer: Kotli } } +/** + * Configures authentication for a given operation shape. + * Determines available authentication strategies (Bearer, SigV4, SigV4A) + * at service and operation level and installs them in Ktor's `authenticate` block. + */ private fun KtorStubGenerator.renderRoutingAuth(w: KotlinWriter, shape: OperationShape) { val serviceAuthTrait = serviceShape.getTrait() val hasServiceHttpBearerAuthTrait = serviceShape.hasTrait(HttpBearerAuthTrait.ID) @@ -328,6 +350,10 @@ private fun KtorStubGenerator.renderRoutingAuth(w: KotlinWriter, shape: Operatio ) } +/** + * Reads and appends HTTP headers from response object fields annotated + * with `HttpHeaderTrait` to the Ktor response. + */ private fun KtorStubGenerator.readResponseHttpHeader(dataName: String, shapeId: ShapeId, writer: KotlinWriter) { val shape = ctx.model.expectShape(shapeId) shape.allMembers @@ -339,6 +365,10 @@ private fun KtorStubGenerator.readResponseHttpHeader(dataName: String, shapeId: } } +/** + * Reads and appends HTTP prefix headers from response object fields annotated + * with `HttpPrefixHeadersTrait`. Dynamically appends prefixed headers with suffix values. + */ private fun KtorStubGenerator.readResponseHttpPrefixHeader(dataName: String, shapeId: ShapeId, writer: KotlinWriter) { val shape = ctx.model.expectShape(shapeId) shape.allMembers @@ -352,6 +382,13 @@ private fun KtorStubGenerator.readResponseHttpPrefixHeader(dataName: String, sha } } +/** + * Writes the Ktor call to send the response back to the client. + * + * - Selects correct responder (`respondBytes` or `responseText`) based on content type. + * - Sets appropriate content type and HTTP status code. + * - Supports CBOR, JSON, text, binary, and dynamic media types. + */ private fun KtorStubGenerator.renderResponseCall( responseName: String, w: KotlinWriter, diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/ServerFrameworkImplementation.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/ServerFrameworkImplementation.kt index de6583675..6ac2ea678 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/ServerFrameworkImplementation.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/ServerFrameworkImplementation.kt @@ -7,6 +7,14 @@ import software.amazon.smithy.kotlin.codegen.core.withInlineBlock import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes import software.amazon.smithy.kotlin.codegen.service.ServiceTypes +/** + * Writes the server framework implementation for the generated Ktor service. + * + * - Defines the `Application.module()` entry point for configuring the Ktor pipeline + * (logging, body size limits, double receive, error handling, authentication, routing). + * - Emits a concrete `KtorServiceFramework` implementation of `ServiceFramework` + * that manages lifecycle of the Ktor embedded server engine. + */ internal fun KtorStubGenerator.writeServerFrameworkImplementation(writer: KotlinWriter) { writer.withBlock("internal fun #T.module(): Unit {", "}", RuntimeTypes.KtorServerCore.Application) { write("#T()", ServiceTypes(pkgName).configureLogging) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Utils.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Utils.kt index 98491daa9..57a68f19f 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Utils.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Utils.kt @@ -4,10 +4,26 @@ import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes import software.amazon.smithy.kotlin.codegen.core.withBlock import software.amazon.smithy.kotlin.codegen.service.ServiceTypes +/** + * Entry point for generating utility files required by the Ktor server stub. + * + * Currently delegates to [renderLogging] to generate logging configuration. + */ internal fun KtorStubGenerator.writeUtils() { renderLogging() } +/** + * Generates logging configuration for the generated Ktor service. + * + * - Creates a `Logging.kt` file with `configureLogging()` extension function for + * the Ktor `Application`, setting up SLF4J/Logback integration. + * - Maps service log levels to SLF4J/Logback levels. + * - Configures Ktor's `CallLogging` plugin to log HTTP method, URI, and status. + * - Registers lifecycle log messages (`starting`, `started`, `stopping`, `stopped`). + * - Writes a default `logback.xml` file into `src/main/resources` to ensure + * console logging is available out of the box. + */ private fun KtorStubGenerator.renderLogging() { delegator.useFileWriter("Logging.kt", "$pkgName.utils") { writer -> diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/utils.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/utils.kt index dd6001dfc..22e40ee7a 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/utils.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/utils.kt @@ -5,6 +5,10 @@ import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes import software.amazon.smithy.model.shapes.ShapeType import software.amazon.smithy.model.traits.TimestampFormatTrait +/** + * Renders Kotlin code that casts a variable to the correct primitive type + * based on its Smithy [ShapeType]. + */ fun renderCastingPrimitiveFromShapeType( variable: String, type: ShapeType, From 2e061383b61ccdecf4da662afcda0ca0e57384ae Mon Sep 17 00:00:00 2001 From: luigi Date: Tue, 19 Aug 2025 16:46:25 -0700 Subject: [PATCH 3/7] fix --- .../amazon/smithy/kotlin/codegen/service/ktor/Routing.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt index 905cb0d91..2a09b38cf 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/ktor/Routing.kt @@ -130,7 +130,7 @@ internal fun KtorStubGenerator.writeRouting() { write( "throw #T(ex?.message ?: #S, ex)", RuntimeTypes.KtorServerCore.BadRequestException, - "Malformed CBOR input", + "Malformed input data", ) } if (ctx.model.expectShape(shape.input.get()).allMembers.isNotEmpty()) { @@ -155,7 +155,7 @@ internal fun KtorStubGenerator.writeRouting() { write( "throw #T(ex?.message ?: #S, ex)", RuntimeTypes.KtorServerCore.BadRequestException, - "Malformed CBOR output", + "Malformed output data", ) } call { readResponseHttpHeader("responseObj", shape.output.get(), writer) } From 4e7fd91ade7e4008f4c237bca9d4f567a152edf4 Mon Sep 17 00:00:00 2001 From: luigi Date: Wed, 20 Aug 2025 00:10:15 -0700 Subject: [PATCH 4/7] add script to build --- .../smithy/kotlin/codegen/CodegenVisitor.kt | 3 ++ .../codegen/service/BuildScriptGenerator.kt | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt index 1447363d4..dab46eb78 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt @@ -21,6 +21,7 @@ import software.amazon.smithy.kotlin.codegen.rendering.* import software.amazon.smithy.kotlin.codegen.rendering.protocol.ApplicationProtocol import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator import software.amazon.smithy.kotlin.codegen.service.AbstractStubGenerator +import software.amazon.smithy.kotlin.codegen.service.buildScript import software.amazon.smithy.model.Model import software.amazon.smithy.model.knowledge.ServiceIndex import software.amazon.smithy.model.neighbor.Walker @@ -156,6 +157,8 @@ class CodegenVisitor(context: PluginContext) : ShapeVisitor.Default() { if (generateServiceProject) { val serviceStubGenerator: AbstractStubGenerator = settings.serviceStub.framework.getServiceFrameworkGenerator(baseGenerationContext, writers, fileManifest) serviceStubGenerator.render() + + buildScript(fileManifest) } writers.finalize() diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt new file mode 100644 index 000000000..16791516c --- /dev/null +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt @@ -0,0 +1,46 @@ +package software.amazon.smithy.kotlin.codegen.service + +import software.amazon.smithy.build.FileManifest + +internal fun buildScript(fileManifest: FileManifest) { + val bashScript = """ + #!/bin/bash + + if [ -d "build" ]; then + read -p "The 'build' directory already exists. Removing it will delete previous build artifacts. Continue? (y/n): " choice + case "${'$'}choice" in + y|Y ) + gradle clean + echo "Previous build directory removed." + ;; + * ) + echo "Aborted." + exit 1 + ;; + esac + fi + + gradle build + + """.trimIndent() + fileManifest.writeFile("build.sh", bashScript) + + val batchScript = """ + @echo off + if exist build ( + set /p choice="The 'build' directory already exists. Removing it will delete previous build artifacts. Continue? (y/n): " + if /i "%choice%"=="y" ( + gradle clean + echo Previous build directory removed. + ) else ( + echo Aborted. + exit /b 1 + ) + ) + + gradle build + + """.trimIndent() + + fileManifest.writeFile("build.bat", batchScript) +} From ee3c5de27d16b291f241218877e644ab8a7d3b43 Mon Sep 17 00:00:00 2001 From: luigi Date: Wed, 20 Aug 2025 00:23:13 -0700 Subject: [PATCH 5/7] modify read me --- .../smithy/kotlin/codegen/service/README.md | 1 + .../codegen/service/docs/GettingStarted.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md index 18832f7e6..f60863a3a 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md @@ -29,6 +29,7 @@ While Ktor is the default backend, the architecture is framework-agnostic, allow - `ServiceStubGenerator.kt` – abstract service stub generator file. - `ServiceTypes.kt` – file that includes service component symbols. - `utils.kt` – utilities file. +- `BuildScriptGenerator.kt` – build scripts generator file. ### Testing diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md index 1f6d8c9bd..132e56172 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md @@ -136,6 +136,22 @@ Run: gradle build ``` +⚠️ Running gradle build will delete the previous build output before creating a new one. + +If you want to prevent accidentally losing previous build, use the provided scripts instead: + +Linux / macOS: +```bash + chmod +x build.sh + ./build.sh +``` + +Windows: +```bash + icacls build.bat /grant %USERNAME%:RX + .\build.bat +``` + If you want to clean previously generated code: ```bash gradle clean From 3de7603f0bdb5b29d3011ea2c0fb18bc5a372b5c Mon Sep 17 00:00:00 2001 From: luigi Date: Wed, 20 Aug 2025 00:56:54 -0700 Subject: [PATCH 6/7] fix --- .../smithy/kotlin/codegen/CodegenVisitor.kt | 3 -- .../codegen/service/BuildScriptGenerator.kt | 46 ------------------- .../smithy/kotlin/codegen/service/README.md | 1 - .../codegen/service/docs/GettingStarted.md | 4 +- examples/service-codegen/build.bat | 13 ++++++ examples/service-codegen/build.sh | 17 +++++++ .../com/test/ServiceEngineFactoryTest.kt | 1 + 7 files changed, 33 insertions(+), 52 deletions(-) delete mode 100644 codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt create mode 100644 examples/service-codegen/build.bat create mode 100644 examples/service-codegen/build.sh diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt index dab46eb78..1447363d4 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/CodegenVisitor.kt @@ -21,7 +21,6 @@ import software.amazon.smithy.kotlin.codegen.rendering.* import software.amazon.smithy.kotlin.codegen.rendering.protocol.ApplicationProtocol import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator import software.amazon.smithy.kotlin.codegen.service.AbstractStubGenerator -import software.amazon.smithy.kotlin.codegen.service.buildScript import software.amazon.smithy.model.Model import software.amazon.smithy.model.knowledge.ServiceIndex import software.amazon.smithy.model.neighbor.Walker @@ -157,8 +156,6 @@ class CodegenVisitor(context: PluginContext) : ShapeVisitor.Default() { if (generateServiceProject) { val serviceStubGenerator: AbstractStubGenerator = settings.serviceStub.framework.getServiceFrameworkGenerator(baseGenerationContext, writers, fileManifest) serviceStubGenerator.render() - - buildScript(fileManifest) } writers.finalize() diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt deleted file mode 100644 index 16791516c..000000000 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/BuildScriptGenerator.kt +++ /dev/null @@ -1,46 +0,0 @@ -package software.amazon.smithy.kotlin.codegen.service - -import software.amazon.smithy.build.FileManifest - -internal fun buildScript(fileManifest: FileManifest) { - val bashScript = """ - #!/bin/bash - - if [ -d "build" ]; then - read -p "The 'build' directory already exists. Removing it will delete previous build artifacts. Continue? (y/n): " choice - case "${'$'}choice" in - y|Y ) - gradle clean - echo "Previous build directory removed." - ;; - * ) - echo "Aborted." - exit 1 - ;; - esac - fi - - gradle build - - """.trimIndent() - fileManifest.writeFile("build.sh", bashScript) - - val batchScript = """ - @echo off - if exist build ( - set /p choice="The 'build' directory already exists. Removing it will delete previous build artifacts. Continue? (y/n): " - if /i "%choice%"=="y" ( - gradle clean - echo Previous build directory removed. - ) else ( - echo Aborted. - exit /b 1 - ) - ) - - gradle build - - """.trimIndent() - - fileManifest.writeFile("build.bat", batchScript) -} diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md index f60863a3a..18832f7e6 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/README.md @@ -29,7 +29,6 @@ While Ktor is the default backend, the architecture is framework-agnostic, allow - `ServiceStubGenerator.kt` – abstract service stub generator file. - `ServiceTypes.kt` – file that includes service component symbols. - `utils.kt` – utilities file. -- `BuildScriptGenerator.kt` – build scripts generator file. ### Testing diff --git a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md index 132e56172..73a7cdb34 100644 --- a/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md +++ b/codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/service/docs/GettingStarted.md @@ -140,13 +140,13 @@ Run: If you want to prevent accidentally losing previous build, use the provided scripts instead: -Linux / macOS: +You can find script for Linux / macOS [here](../../../../../../../../../../../../examples/service-codegen/build.sh): ```bash chmod +x build.sh ./build.sh ``` -Windows: +You can find script for Windows [here](../../../../../../../../../../../../examples/service-codegen/build.bat): ```bash icacls build.bat /grant %USERNAME%:RX .\build.bat diff --git a/examples/service-codegen/build.bat b/examples/service-codegen/build.bat new file mode 100644 index 000000000..2141f3f94 --- /dev/null +++ b/examples/service-codegen/build.bat @@ -0,0 +1,13 @@ +@echo off +if exist build ( + set /p choice="The 'build' directory already exists. Removing it will delete previous build artifacts. Continue? (y/n): " + if /i "%choice%"=="y" ( + gradle clean + echo Previous build directory removed. + ) else ( + echo Aborted. + exit /b 1 + ) +) + +gradle build diff --git a/examples/service-codegen/build.sh b/examples/service-codegen/build.sh new file mode 100644 index 000000000..dc22c98a9 --- /dev/null +++ b/examples/service-codegen/build.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -d "build" ]; then + read -p "The 'build' directory already exists. Removing it will delete previous build artifacts. Continue? (y/n): " choice + case "$choice" in + y|Y ) + gradle clean + echo "Previous build directory removed." + ;; + * ) + echo "Aborted." + exit 1 + ;; + esac +fi + +gradle build diff --git a/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt b/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt index 560412f1f..106e8c8c4 100644 --- a/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt +++ b/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt @@ -26,6 +26,7 @@ class ServiceEngineFactoryTest { fun `checks service with netty engine`() { val nettyPort: Int = ServerSocket(0).use { it.localPort } val nettyProc = startService("netty", nettyPort, closeGracePeriodMillis, closeTimeoutMillis, requestBodyLimit, projectDir) + val ready = waitForPort(nettyPort, portListenerTimeout) assertTrue(ready, "Service did not start within $portListenerTimeout s") cleanupService(nettyProc, gracefulWindow) From d1ef91bea0372eaa2366af412bed254a8aeb82f5 Mon Sep 17 00:00:00 2001 From: luigi Date: Wed, 20 Aug 2025 01:04:06 -0700 Subject: [PATCH 7/7] fix --- .../src/test/kotlin/com/test/ServiceEngineFactoryTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt b/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt index 106e8c8c4..560412f1f 100644 --- a/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt +++ b/tests/codegen/service-codegen-tests/src/test/kotlin/com/test/ServiceEngineFactoryTest.kt @@ -26,7 +26,6 @@ class ServiceEngineFactoryTest { fun `checks service with netty engine`() { val nettyPort: Int = ServerSocket(0).use { it.localPort } val nettyProc = startService("netty", nettyPort, closeGracePeriodMillis, closeTimeoutMillis, requestBodyLimit, projectDir) - val ready = waitForPort(nettyPort, portListenerTimeout) assertTrue(ready, "Service did not start within $portListenerTimeout s") cleanupService(nettyProc, gracefulWindow)