Skip to content

Commit

Permalink
sdk-api-kotlin-gen (#240)
Browse files Browse the repository at this point in the history
* Factor out common codegen module in sdk-api-gen-common
* Implement sdk-api-kotlin-gen and test it
* Rewrite the kotlin example with sdk-api-kotlin-gen
  • Loading branch information
slinkydeveloper committed Mar 15, 2024
1 parent 3952fe5 commit ac82682
Show file tree
Hide file tree
Showing 34 changed files with 1,748 additions and 746 deletions.
4 changes: 2 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ For a sample project configuration and more elaborated examples, check out the [
Available examples:

* [`Counter`](src/main/java/my/restate/sdk/examples/Counter.java): Shows a simple virtual object using state primitives.
* [`Counter`](src/main/kotlin/my/restate/sdk/examples/Counter.kt): Same as `Counter` but using Kotlin.
* [`CounterKt`](src/main/kotlin/my/restate/sdk/examples/CounterKt.kt): Same as `Counter` but using Kotlin.
* [`LoanWorkflow`](src/main/java/my/restate/sdk/examples/LoanWorkflow.java): Shows a simple workflow example using the Workflow API.

## Package the examples for Lambda
Expand Down Expand Up @@ -35,7 +35,7 @@ You can run the Java Counter example via:
You can modify the class to run setting `-PmainClass=<FQCN>`, for example, in order to run the Kotlin implementation:

```shell
./gradlew :examples:run -PmainClass=my.restate.sdk.examples.CounterKt
./gradlew :examples:run -PmainClass=my.restate.sdk.examples.CounterKtKt
```

## Invoking the counter bindableComponent
Expand Down
18 changes: 10 additions & 8 deletions examples/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer

plugins {
java
kotlin("jvm")
kotlin("plugin.serialization")
application
id("com.github.johnrengelman.shadow").version("7.1.2")
alias(kotlinLibs.plugins.ksp)
id("com.github.johnrengelman.shadow").version("8.1.1")
}

dependencies {
ksp(project(":sdk-api-kotlin-gen"))
annotationProcessor(project(":sdk-api-gen"))

implementation(project(":sdk-api"))
Expand All @@ -19,13 +24,6 @@ dependencies {
implementation(platform(jacksonLibs.jackson.bom))
implementation(jacksonLibs.jackson.jsr310)

implementation(coreLibs.protobuf.java)
implementation(coreLibs.protobuf.kotlin)

implementation(platform(vertxLibs.vertx.bom))
implementation(vertxLibs.vertx.core)
implementation(vertxLibs.vertx.kotlin.coroutines)

implementation(kotlinLibs.kotlinx.coroutines)
implementation(kotlinLibs.kotlinx.serialization.core)
implementation(kotlinLibs.kotlinx.serialization.json)
Expand All @@ -38,3 +36,7 @@ application {
project.findProperty("mainClass")?.toString() ?: "my.restate.sdk.examples.Counter"
mainClass.set(mainClassValue)
}

tasks.withType<Jar> { this.enabled = false }

tasks.withType<ShadowJar> { transform(ServiceFileTransformer::class.java) }
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void register(RestateLambdaEndpointBuilder builder) {
if (Counter.class.getCanonicalName().equals(serviceClass)) {
builder.with(new Counter());
} else if (CounterKt.class.getCanonicalName().equals(serviceClass)) {
builder.with(CounterKt.getCounter());
builder.with(new CounterKt());
} else {
throw new IllegalArgumentException(
"Bad \"LAMBDA_FACTORY_SERVICE_CLASS\" env: " + serviceClass);
Expand Down
40 changes: 0 additions & 40 deletions examples/src/main/kotlin/my/restate/sdk/examples/Counter.kt

This file was deleted.

56 changes: 56 additions & 0 deletions examples/src/main/kotlin/my/restate/sdk/examples/CounterKt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package my.restate.sdk.examples

import dev.restate.sdk.annotation.Handler
import dev.restate.sdk.annotation.VirtualObject
import dev.restate.sdk.common.StateKey
import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder
import dev.restate.sdk.kotlin.KtSerdes
import dev.restate.sdk.kotlin.ObjectContext
import kotlinx.serialization.Serializable

@Serializable data class CounterUpdate(var oldValue: Long, val newValue: Long)

@VirtualObject
class CounterKt {

companion object {
private val TOTAL = StateKey.of<Long>("total", KtSerdes.json())
}

@Handler
suspend fun reset(ctx: ObjectContext) {
ctx.clear(TOTAL)
}

@Handler
suspend fun add(ctx: ObjectContext, value: Long) {
val currentValue = ctx.get(TOTAL) ?: 0L
val newValue = currentValue + value
ctx.set(TOTAL, newValue)
}

@Handler
suspend fun get(ctx: ObjectContext): Long {
return ctx.get(TOTAL) ?: 0L
}

@Handler
suspend fun getAndAdd(ctx: ObjectContext, value: Long): CounterUpdate {
val currentValue = ctx.get(TOTAL) ?: 0L
val newValue = currentValue + value
ctx.set(TOTAL, newValue)
return CounterUpdate(currentValue, newValue)
}
}

fun main() {
RestateHttpEndpointBuilder.builder().with(CounterKt()).buildAndListen()
}
13 changes: 13 additions & 0 deletions sdk-api-gen-common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
`java-library`
`library-publishing-conventions`
}

description = "Restate SDK API Gen Common"

dependencies {
compileOnly(coreLibs.jspecify)

api("com.github.jknack:handlebars:4.3.1")
api(project(":sdk-common"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.sdk.gen.model;

import dev.restate.sdk.common.ComponentType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

public class Component {

private final CharSequence targetPkg;
private final CharSequence targetFqcn;
private final String componentName;
private final ComponentType componentType;
private final List<Handler> handlers;

public Component(
CharSequence targetPkg,
CharSequence targetFqcn,
String componentName,
ComponentType componentType,
List<Handler> handlers) {
this.targetPkg = targetPkg;
this.targetFqcn = targetFqcn;
this.componentName = componentName;

this.componentType = componentType;
this.handlers = handlers;
}

public CharSequence getTargetPkg() {
return this.targetPkg;
}

public CharSequence getTargetFqcn() {
return this.targetFqcn;
}

public String getFullyQualifiedComponentName() {
return this.componentName;
}

public String getSimpleComponentName() {
return this.componentName.substring(this.componentName.lastIndexOf('.') + 1);
}

public CharSequence getGeneratedClassFqcnPrefix() {
if (this.targetPkg == null || this.targetPkg.length() == 0) {
return getSimpleComponentName();
}
return this.targetPkg + "." + getSimpleComponentName();
}

public ComponentType getComponentType() {
return componentType;
}

public List<Handler> getMethods() {
return handlers;
}

public static Builder builder() {
return new Builder();
}

public static class Builder {
private CharSequence targetPkg;
private CharSequence targetFqcn;
private String componentName;
private ComponentType componentType;
private final List<Handler> handlers = new ArrayList<>();

public Builder withTargetPkg(CharSequence targetPkg) {
this.targetPkg = targetPkg;
return this;
}

public Builder withTargetFqcn(CharSequence targetFqcn) {
this.targetFqcn = targetFqcn;
return this;
}

public Builder withComponentName(String componentName) {
this.componentName = componentName;
return this;
}

public Builder withComponentType(ComponentType componentType) {
this.componentType = componentType;
return this;
}

public Builder withHandlers(Collection<Handler> handlers) {
this.handlers.addAll(handlers);
return this;
}

public Builder withHandler(Handler handler) {
this.handlers.add(handler);
return this;
}

public CharSequence getTargetPkg() {
return targetPkg;
}

public CharSequence getTargetFqcn() {
return targetFqcn;
}

public String getComponentName() {
return componentName;
}

public ComponentType getComponentType() {
return componentType;
}

public List<Handler> getHandlers() {
return handlers;
}

public Component build() {
return new Component(
Objects.requireNonNull(targetPkg),
Objects.requireNonNull(targetFqcn),
Objects.requireNonNull(componentName),
Objects.requireNonNull(componentType),
handlers);
}
}
}
Loading

0 comments on commit ac82682

Please sign in to comment.