diff --git a/src/events/app/build.gradle b/src/events/app/build.gradle index 6872ea8f..181d4033 100644 --- a/src/events/app/build.gradle +++ b/src/events/app/build.gradle @@ -1,73 +1,94 @@ -plugins { - id("com.github.johnrengelman.shadow") version "7.1.2" - id("io.micronaut.application") version "3.6.2" -} - -group = "micronaut.mushop" - -repositories { - mavenCentral() -} - -micronaut { - runtime("netty") - testRuntime("junit5") - processing { - incremental(true) - annotations("events.*") - } -} - -dependencies { - annotationProcessor("io.micronaut.openapi:micronaut-openapi") - - implementation("io.micronaut:micronaut-http-client") - implementation("io.micronaut:micronaut-runtime") - implementation("io.micronaut:micronaut-validation") - - // Metrics - implementation("io.micronaut:micronaut-management") - implementation("io.micronaut.micrometer:micronaut-micrometer-core") - implementation("io.micronaut.micrometer:micronaut-micrometer-registry-prometheus") - - // Tracing - implementation("io.micronaut.tracing:micronaut-tracing-core") - implementation("io.micronaut.tracing:micronaut-tracing-zipkin") - - // Streaming - implementation("io.micronaut.kafka:micronaut-kafka") - - implementation("io.swagger.core.v3:swagger-annotations") - - runtimeOnly("ch.qos.logback:logback-classic") - - testImplementation(project(":tck")) - testImplementation("org.testcontainers:junit-jupiter") -} - -application { - mainClass.set("events.Application") -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - -if (javaBaseImage == "graalvm") { - dockerfile { - baseImage = "phx.ocir.io/oraclelabs/micronaut-showcase/mushop/base/graalvm-ce:java11-21.1.0" - } -} - -dockerBuild { - images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/$project.parent.name-$project.name-${javaBaseImage}:$project.version"] -} - -dockerBuildNative { - images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/${project.parent.name}-${project.name}-native:$project.version"] -} - -dockerfileNative { - instruction "RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.11/main' >> /etc/apk/repositories && apk update && apk add 'zlib<1.2.12'" -} +plugins { + id("com.github.johnrengelman.shadow") version "8.1.1" + id("io.micronaut.application") version "4.3.4" + id("io.micronaut.aot") version "4.3.4" + id("io.micronaut.test-resources") version "4.3.4" +} + +group = "micronaut.mushop" + +repositories { + mavenCentral() +} + +micronaut { + runtime("netty") + testRuntime("junit5") + processing { + incremental(true) + annotations("events.*") + } + aot { + optimizeServiceLoading = false + convertYamlToJava = false + precomputeOperations = true + cacheEnvironment = true + optimizeClassLoading = true + deduceEnvironment = true + optimizeNetty = true + } +} + +dependencies { + annotationProcessor("io.micronaut.openapi:micronaut-openapi") + annotationProcessor("io.micronaut:micronaut-http-validation") + annotationProcessor("io.micronaut.tracing:micronaut-tracing-opentelemetry-annotation") + annotationProcessor("io.micronaut.serde:micronaut-serde-processor") + annotationProcessor("io.micronaut.validation:micronaut-validation-processor") + annotationProcessor("io.micronaut.micrometer:micronaut-micrometer-annotation") + + implementation("io.micronaut:micronaut-http-client") + implementation("io.micronaut.serde:micronaut-serde-jackson") + implementation("io.micronaut.validation:micronaut-validation") + implementation("io.micronaut:micronaut-retry") + implementation("jakarta.validation:jakarta.validation-api") + // Metrics + implementation("io.micronaut:micronaut-management") + implementation("io.micronaut.micrometer:micronaut-micrometer-core") + implementation("io.micronaut.micrometer:micronaut-micrometer-registry-prometheus") + + // Tracing + implementation("io.micronaut.tracing:micronaut-tracing-core") + implementation("io.micronaut.tracing:micronaut-tracing-opentelemetry-http") + implementation("io.opentelemetry:opentelemetry-exporter-zipkin") + + // Streaming + implementation("io.micronaut.kafka:micronaut-kafka") + + implementation("io.swagger.core.v3:swagger-annotations") + + runtimeOnly("ch.qos.logback:logback-classic") + + compileOnly("io.micronaut.openapi:micronaut-openapi-annotations") + + runtimeOnly("org.yaml:snakeyaml") + testImplementation(project(":tck")) + testImplementation("io.micronaut:micronaut-http-client") +} + +application { + mainClass.set("events.Application") +} + +java { + sourceCompatibility = JavaVersion.toVersion("21") + targetCompatibility = JavaVersion.toVersion("21") +} + +if (javaBaseImage == "graalvm") { + dockerfile { + baseImage = "ghcr.io/graalvm/native-image-community:21" + } +} + +dockerBuild { + images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/$project.parent.name-$project.name-${javaBaseImage}:$project.version"] +} + +dockerBuildNative { + images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/${project.parent.name}-${project.name}-native:$project.version"] +} + +dockerfileNative { + instruction "RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.11/main' >> /etc/apk/repositories && apk update && apk add 'zlib<1.2.12'" +} diff --git a/src/events/app/src/main/java/events/controllers/EventController.java b/src/events/app/src/main/java/events/controllers/EventController.java index 8e7bdb9e..b8102910 100644 --- a/src/events/app/src/main/java/events/controllers/EventController.java +++ b/src/events/app/src/main/java/events/controllers/EventController.java @@ -1,37 +1,35 @@ -package events.controllers; - -import events.model.Event; -import events.model.EventsReceived; -import events.service.EventService; -import io.micronaut.http.MediaType; -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Post; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; - -@Controller("/events") -class EventController { - - private final EventService eventService; - - EventController(EventService eventService) { - this.eventService = eventService; - } - - /** - * Submit events endpoint. - * - * @param source The source of the event - * @param track The event to track - * @param events The events to post - * @return Whether the events were received or not - */ - @Post(processes = MediaType.APPLICATION_JSON) - EventsReceived postEvents( - @NotBlank String source, - @NotBlank String track, - @Min(1) Event...events) { - return eventService.postEvents(source, track, events); - } -} +package events.controllers; + +import events.model.Event; +import events.model.EventsReceived; +import events.service.EventService; +import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Post; +import jakarta.validation.constraints.NotBlank; + +@Controller("/events") +class EventController { + + private final EventService eventService; + + EventController(EventService eventService) { + this.eventService = eventService; + } + + /** + * Submit events endpoint. + * + * @param source The source of the event + * @param track The event to track + * @param events The events to post + * @return Whether the events were received or not + */ + @Post(processes = MediaType.APPLICATION_JSON) + EventsReceived postEvents( + @NotBlank String source, + @NotBlank String track, + Event...events) { + return eventService.postEvents(source, track, events); + } +} diff --git a/src/events/app/src/main/java/events/model/Event.java b/src/events/app/src/main/java/events/model/Event.java index a53b812f..43593105 100644 --- a/src/events/app/src/main/java/events/model/Event.java +++ b/src/events/app/src/main/java/events/model/Event.java @@ -1,30 +1,15 @@ -package events.model; - -import io.micronaut.core.annotation.Introspected; - -import java.util.Collections; -import java.util.Map; -import java.util.Objects; - -/** - * The event to track. - */ -@Introspected -public class Event { - - private final String type; - private final Map detail; - - public Event(String type, Map detail) { - this.type = Objects.requireNonNull(type, "Type cannot be null"); - this.detail = detail != null ? detail : Collections.emptyMap(); - } - - public String getType() { - return type; - } - - public Map getDetail() { - return detail; - } -} +package events.model; + +import io.micronaut.serde.annotation.Serdeable; + + +import java.util.Map; + + +/** + * The event to track. + */ +@Serdeable +public record Event(String type,Map detail){ +} + diff --git a/src/events/app/src/main/java/events/model/EventRecord.java b/src/events/app/src/main/java/events/model/EventRecord.java index 3eafb471..e906d666 100644 --- a/src/events/app/src/main/java/events/model/EventRecord.java +++ b/src/events/app/src/main/java/events/model/EventRecord.java @@ -1,48 +1,35 @@ -package events.model; - -import io.micronaut.core.annotation.Creator; -import io.micronaut.core.annotation.Introspected; - -import java.time.Instant; -import java.util.Map; -import java.util.Objects; - -/** - * Event record. - */ -@Introspected -public class EventRecord extends Event { - - private final String source; - private final String track; - private final Instant time; - - public EventRecord(String source, - String track, - Event event) { - this(source, track, Objects.requireNonNull(event, "Event cannot be null").getType(), event.getDetail()); - } - - @Creator - public EventRecord(String source, - String track, - String type, - Map detail) { - super(type, detail); - this.source = source; - this.track = track; - time = Instant.now(); - } - - public String getSource() { - return source; - } - - public String getTrack() { - return track; - } - - public Instant getTime() { - return time; - } -} +package events.model; + +import io.micronaut.core.annotation.Creator; +import io.micronaut.serde.annotation.Serdeable; + +import java.time.Instant; +import java.util.Map; +import java.util.Objects; + +/** + * Event record. + */ + + +@Serdeable +public record EventRecord(String source, String track, Instant time, Event event) { + + @Creator + public EventRecord(String source, String track, Event event) { + this(source, track, Instant.now(), Objects.requireNonNull(event, "Event cannot be null")); + } + + + public EventRecord(String source, String track, String type, Map detail) { + this(source, track, Instant.now(), new Event(type, detail)); + } + + public String type() { + return event.type(); + } + + public Map detail() { + return event.detail(); + } +} \ No newline at end of file diff --git a/src/events/app/src/main/java/events/model/EventsReceived.java b/src/events/app/src/main/java/events/model/EventsReceived.java index 806717a9..69eaefd9 100644 --- a/src/events/app/src/main/java/events/model/EventsReceived.java +++ b/src/events/app/src/main/java/events/model/EventsReceived.java @@ -1,32 +1,11 @@ -package events.model; - -import io.micronaut.core.annotation.Introspected; - -/** - * Defines whether events were received. - */ -@Introspected -public class EventsReceived { - - private final boolean success; - private final int events; - - public EventsReceived(boolean success, int events) { - this.success = success; - this.events = events; - } - - /** - * True if the events were successfully received - */ - public boolean isSuccess() { - return success; - } - - /** - * The number of successfully received events - */ - public int getEvents() { - return events; - } -} +package events.model; + +import io.micronaut.serde.annotation.Serdeable; + +/** + * Defines whether events were received. + */ +@Serdeable +public record EventsReceived(boolean success ,int events){ +} + diff --git a/src/events/app/src/main/java/events/service/EventProducer.java b/src/events/app/src/main/java/events/service/EventProducer.java index 794b6f0d..27be0897 100644 --- a/src/events/app/src/main/java/events/service/EventProducer.java +++ b/src/events/app/src/main/java/events/service/EventProducer.java @@ -1,19 +1,19 @@ -package events.service; - -import events.model.EventRecord; -import io.micronaut.configuration.kafka.annotation.KafkaClient; -import io.micronaut.configuration.kafka.annotation.Topic; - -/** - * The messaging Kafka {@link EventRecord} producer. - * - * The annotation {@link KafkaClient} is handled by {@link io.micronaut.configuration.kafka.intercept.KafkaClientIntroductionAdvice} - * which introduces new bean that is able to handle publishing of {@link EventRecord}s to the Kafka. - */ -@KafkaClient(batch = true) -public interface EventProducer { - String EVENT_TOPIC_NAME = "events"; - - @Topic(EVENT_TOPIC_NAME) - void send(EventRecord... eventRecords); -} +package events.service; + +import events.model.EventRecord; +import io.micronaut.configuration.kafka.annotation.KafkaClient; +import io.micronaut.configuration.kafka.annotation.Topic; + +/** + * The messaging Kafka {@link EventRecord} producer. + * + * The annotation {@link KafkaClient} is handled by {@link io.micronaut.configuration.kafka.intercept.KafkaClientIntroductionAdvice} + * which introduces new bean that is able to handle publishing of {@link EventRecord}s to the Kafka. + */ +@KafkaClient(batch = true) +public interface EventProducer { + String EVENT_TOPIC_NAME = "events"; + + @Topic(EVENT_TOPIC_NAME) + void send(EventRecord...eventRecords); +} diff --git a/src/events/app/src/main/java/events/service/EventService.java b/src/events/app/src/main/java/events/service/EventService.java index a54677a9..63bc08a1 100644 --- a/src/events/app/src/main/java/events/service/EventService.java +++ b/src/events/app/src/main/java/events/service/EventService.java @@ -1,47 +1,47 @@ -package events.service; - -import events.model.Event; -import events.model.EventRecord; -import events.model.EventsReceived; -import io.micronaut.tracing.annotation.NewSpan; -import io.micronaut.tracing.annotation.SpanTag; -import jakarta.inject.Singleton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; - -@Singleton -public class EventService { - - private static final Logger LOG = LoggerFactory.getLogger(EventService.class); - - private final EventProducer eventProducer; - - public EventService(EventProducer eventProducer) { - this.eventProducer = eventProducer; - } - - @NewSpan("receive events") - public EventsReceived postEvents(@SpanTag String source, - String track, - Event... events) { - final int numEvents = events.length; - try { - LOG.debug("Posting Events (source: {}, track {}, length {})", source, track, numEvents); - if (numEvents == 0) { - return new EventsReceived(false, 0); - } - - final EventRecord[] eventRecords = Arrays.stream(events) - .map(ev -> new EventRecord(source, track, ev)) - .toArray(EventRecord[]::new); - - eventProducer.send(eventRecords); - return new EventsReceived(true, events.length); - } catch (Exception e) { - LOG.error("Unable to process events: {}", e.getMessage(), e); - return new EventsReceived(false, events.length); - } - } -} +package events.service; + +import events.model.Event; +import events.model.EventRecord; +import events.model.EventsReceived; +import io.micronaut.tracing.annotation.NewSpan; +import io.micronaut.tracing.annotation.SpanTag; +import jakarta.inject.Singleton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; + +@Singleton +public class EventService { + + private static final Logger LOG = LoggerFactory.getLogger(EventService.class); + + private final EventProducer eventProducer; + + public EventService(EventProducer eventProducer) { + this.eventProducer = eventProducer; + } + + @NewSpan("receive events") + public EventsReceived postEvents(@SpanTag String source, + String track, + Event... events) { + final int numEvents = events.length; + try { + LOG.debug("Posting Events (source: {}, track {}, length {})", source, track, numEvents); + if (numEvents == 0) { + return new EventsReceived(false, 0); + } + + final EventRecord[] eventRecords = Arrays.stream(events) + .map(ev -> new EventRecord(source, track, ev)) + .toArray(EventRecord[]::new); + + eventProducer.send(eventRecords); + return new EventsReceived(true, events.length); + } catch (Exception e) { + LOG.error("Unable to process events: {}", e.getMessage(), e); + return new EventsReceived(false, events.length); + } + } +} diff --git a/src/events/app/src/main/resources/application-app.yml b/src/events/app/src/main/resources/application-app.yml deleted file mode 100644 index 9113c150..00000000 --- a/src/events/app/src/main/resources/application-app.yml +++ /dev/null @@ -1,3 +0,0 @@ -kafka: - bootstrap: - servers: localhost:9092 diff --git a/src/events/app/src/main/resources/logback.xml b/src/events/app/src/main/resources/logback.xml index 39d220dd..d5d612fa 100644 --- a/src/events/app/src/main/resources/logback.xml +++ b/src/events/app/src/main/resources/logback.xml @@ -1,18 +1,17 @@ - - - - true - - - %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n - - - - - - - - - - + + + + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + + + diff --git a/src/events/aws/build.gradle b/src/events/aws/build.gradle index db7cf955..e981cbf5 100644 --- a/src/events/aws/build.gradle +++ b/src/events/aws/build.gradle @@ -1,67 +1,76 @@ -plugins { - id("com.github.johnrengelman.shadow") version "7.1.2" - id("io.micronaut.application") version "3.6.2" -} - -group = "micronaut.mushop" - -repositories { - mavenCentral() -} - -micronaut { - runtime("netty") - testRuntime("junit5") - processing { - incremental(true) - annotations("events.*") - } -} - -dependencies { - implementation(project(":app")) - - // Metrics - implementation("io.micronaut.micrometer:micronaut-micrometer-registry-cloudwatch") - - // Kafka IAM - implementation("software.amazon.msk:aws-msk-iam-auth:1.0.0") - - // Configuration discovery - implementation("io.micronaut.aws:micronaut-aws-secretsmanager") - implementation("io.micronaut.aws:micronaut-aws-parameter-store") - - // Authentication - implementation("software.amazon.awssdk:sts") - - testImplementation(project(":tck")) - testImplementation("org.testcontainers:junit-jupiter") -} - -application { - mainClass.set("events.AwsApplication") -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - -if (javaBaseImage == "graalvm") { - dockerfile { - baseImage = "phx.ocir.io/oraclelabs/micronaut-showcase/mushop/base/graalvm-ce:java11-21.1.0" - } -} - -dockerBuild { - images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/$project.parent.name-$project.name-${javaBaseImage}:$project.version"] -} - -dockerBuildNative { - images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/${project.parent.name}-${project.name}-native:$project.version"] -} - -dockerfileNative { - baseImage = "phx.ocir.io/oraclelabs/micronaut-showcase/mushop/base/alpine-glibc:alpine-3.12" - instruction "RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.11/main' >> /etc/apk/repositories && apk update && apk add 'zlib<1.2.12'" -} +plugins { + id("com.github.johnrengelman.shadow") version "8.1.1" + id("io.micronaut.application") version "4.3.4" + id("io.micronaut.aot") version "4.3.4" + id("io.micronaut.test-resources") version "4.3.4" +} + +group = "micronaut.mushop" + +repositories { + mavenCentral() +} + +micronaut { + runtime("netty") + testRuntime("junit5") + processing { + incremental(true) + annotations("events.*") + }aot { + optimizeServiceLoading = false + convertYamlToJava = false + precomputeOperations = true + cacheEnvironment = true + optimizeClassLoading = true + deduceEnvironment = true + optimizeNetty = true + } +} + +dependencies { + implementation(project(":app")) + + // Metrics + implementation("io.micronaut.micrometer:micronaut-micrometer-registry-cloudwatch") + + // Kafka IAM + implementation("software.amazon.msk:aws-msk-iam-auth:1.0.0") + implementation("io.micronaut.kafka:micronaut-kafka") + // Configuration discovery + implementation("io.micronaut.aws:micronaut-aws-secretsmanager") + implementation("io.micronaut.aws:micronaut-aws-parameter-store") + + // Authentication + implementation("software.amazon.awssdk:sts") + + testImplementation(project(":tck")) +} + +application { + mainClass.set("events.AwsApplication") +} + +java { + sourceCompatibility = JavaVersion.toVersion("21") + targetCompatibility = JavaVersion.toVersion("21") +} + +if (javaBaseImage == "graalvm") { + dockerfile { + baseImage = "ghcr.io/graalvm/native-image-community:21" + } +} + +dockerBuild { + images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/$project.parent.name-$project.name-${javaBaseImage}:$project.version"] +} + +dockerBuildNative { + images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/${project.parent.name}-${project.name}-native:$project.version"] +} + +dockerfileNative { + baseImage = "phx.ocir.io/oraclelabs/micronaut-showcase/mushop/base/alpine-glibc:alpine-3.12" + instruction "RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.11/main' >> /etc/apk/repositories && apk update && apk add 'zlib<1.2.12'" +} diff --git a/src/events/buildSrc/build.gradle b/src/events/buildSrc/build.gradle new file mode 100644 index 00000000..049233d2 --- /dev/null +++ b/src/events/buildSrc/build.gradle @@ -0,0 +1,10 @@ +plugins { + id 'groovy-gradle-plugin' +} +repositories { + mavenCentral() + gradlePluginPortal() +} +dependencies { + implementation("com.bmuschko:gradle-docker-plugin:9.4.0") +} \ No newline at end of file diff --git a/src/events/gradle.properties b/src/events/gradle.properties index c83267ff..0ffe21ba 100644 --- a/src/events/gradle.properties +++ b/src/events/gradle.properties @@ -1,3 +1,3 @@ -micronautVersion=3.7.3 -version=2.0.0-SNAPSHOT -javaBaseImage=graalvm +micronautVersion=4.3.4 +version=2.0.0-SNAPSHOT +javaBaseImage=graalvm diff --git a/src/events/gradle/wrapper/gradle-wrapper.jar b/src/events/gradle/wrapper/gradle-wrapper.jar index 249e5832..d64cd491 100644 Binary files a/src/events/gradle/wrapper/gradle-wrapper.jar and b/src/events/gradle/wrapper/gradle-wrapper.jar differ diff --git a/src/events/gradle/wrapper/gradle-wrapper.properties b/src/events/gradle/wrapper/gradle-wrapper.properties index ae04661e..a80b22ce 100644 --- a/src/events/gradle/wrapper/gradle-wrapper.properties +++ b/src/events/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/events/gradlew b/src/events/gradlew index a69d9cb6..1aa94a42 100755 --- a/src/events/gradlew +++ b/src/events/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/src/events/gradlew.bat b/src/events/gradlew.bat index f127cfd4..7101f8e4 100755 --- a/src/events/gradlew.bat +++ b/src/events/gradlew.bat @@ -1,91 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/events/oci/build.gradle b/src/events/oci/build.gradle index 4f11e8e6..9bec8f75 100644 --- a/src/events/oci/build.gradle +++ b/src/events/oci/build.gradle @@ -1,56 +1,66 @@ -plugins { - id("com.github.johnrengelman.shadow") version "7.1.2" - id("io.micronaut.application") version "3.6.2" -} - -group = "micronaut.mushop" - -repositories { - mavenCentral() -} - -micronaut { - runtime("netty") - testRuntime("junit5") - processing { - incremental(true) - annotations("events.*") - } -} - -dependencies { - implementation(project(":app")) - - // Metrics - implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-micrometer") - - testImplementation(project(":tck")) - testImplementation("org.testcontainers:junit-jupiter") -} - -application { - mainClass.set("events.OciApplication") -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - -if (javaBaseImage == "graalvm") { - dockerfile { - baseImage = "phx.ocir.io/oraclelabs/micronaut-showcase/mushop/base/graalvm-ce:java11-21.1.0" - } -} - -dockerBuild { - images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/$project.parent.name-$project.name-${javaBaseImage}:$project.version"] -} - -dockerBuildNative { - images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/${project.parent.name}-${project.name}-native:$project.version"] -} - -dockerfileNative { - instruction "RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.11/main' >> /etc/apk/repositories && apk update && apk add 'zlib<1.2.12'" -} +plugins { + id("com.github.johnrengelman.shadow") version "8.1.1" + id("io.micronaut.application") version "4.3.4" + id("io.micronaut.aot") version "4.3.4" + id("io.micronaut.test-resources") version "4.3.4" +} + +group = "micronaut.mushop" + +repositories { + mavenCentral() +} + +micronaut { + runtime("netty") + testRuntime("junit5") + processing { + incremental(true) + annotations("events.*") + }aot { + optimizeServiceLoading = false + convertYamlToJava = false + precomputeOperations = true + cacheEnvironment = true + optimizeClassLoading = true + deduceEnvironment = true + optimizeNetty = true + } +} + +dependencies { + implementation(project(":app")) + + // Metrics + implementation("io.micronaut.oraclecloud:micronaut-oraclecloud-micrometer") + implementation("io.micronaut.kafka:micronaut-kafka") + testImplementation(project(":tck")) + +} + +application { + mainClass.set("events.OciApplication") +} + +java { + sourceCompatibility = JavaVersion.toVersion("21") + targetCompatibility = JavaVersion.toVersion("21") +} + +if (javaBaseImage == "graalvm") { + dockerfile { + baseImage = "ghcr.io/graalvm/native-image-community:21" + } +} + +dockerBuild { + images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/$project.parent.name-$project.name-${javaBaseImage}:$project.version"] +} + +dockerBuildNative { + images = ["phx.ocir.io/oraclelabs/micronaut-showcase/mushop/${project.parent.name}-${project.name}-native:$project.version"] +} + +dockerfileNative { + instruction "RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.11/main' >> /etc/apk/repositories && apk update && apk add 'zlib<1.2.12'" +} diff --git a/src/events/settings.gradle b/src/events/settings.gradle index 7959ff47..c674e695 100644 --- a/src/events/settings.gradle +++ b/src/events/settings.gradle @@ -1,9 +1,6 @@ -rootProject.name="events" - -include "app" -include "aws" -include "oci" -include "tck" - -startParameter.excludedTaskNames << ':tck:dockerPush' -startParameter.excludedTaskNames << ':tck:dockerPushNative' +rootProject.name="events" + +include "app" +include "aws" +include "oci" +include "tck" diff --git a/src/events/tck/build.gradle b/src/events/tck/build.gradle index 3a25528c..66610053 100644 --- a/src/events/tck/build.gradle +++ b/src/events/tck/build.gradle @@ -1,20 +1,17 @@ -plugins { - id("io.micronaut.application") version "3.6.2" -} - -group = "micronaut.mushop" - -repositories { - mavenCentral() -} - -dependencies { - implementation(project(":app")) - implementation("io.micronaut:micronaut-http-client") - implementation("io.micronaut.kafka:micronaut-kafka") - implementation("io.micronaut.test:micronaut-test-junit5") - implementation("org.testcontainers:junit-jupiter") - implementation("org.testcontainers:testcontainers") - implementation("org.testcontainers:kafka") - implementation("org.awaitility:awaitility:4.0.3") -} +plugins { + id("io.micronaut.application") version "4.3.4" +} + +group = "micronaut.mushop" + +repositories { + mavenCentral() +} + +dependencies { + implementation(project(":app")) + implementation("io.micronaut:micronaut-http-client") + implementation("io.micronaut.kafka:micronaut-kafka") + implementation("io.micronaut.test:micronaut-test-junit5") + implementation("org.awaitility:awaitility:4.2.0") +} diff --git a/src/events/tck/src/main/java/events/AbstractEventsTest.java b/src/events/tck/src/main/java/events/AbstractEventsTest.java index a71c2c2e..3b213bd9 100644 --- a/src/events/tck/src/main/java/events/AbstractEventsTest.java +++ b/src/events/tck/src/main/java/events/AbstractEventsTest.java @@ -1,121 +1,103 @@ -package events; - -import events.model.Event; -import events.model.EventRecord; -import events.model.EventsReceived; -import events.service.EventService; -import io.micronaut.configuration.kafka.annotation.KafkaListener; -import io.micronaut.configuration.kafka.annotation.OffsetReset; -import io.micronaut.configuration.kafka.annotation.Topic; -import io.micronaut.core.annotation.NonNull; -import io.micronaut.http.MediaType; -import io.micronaut.http.annotation.Post; -import io.micronaut.http.client.annotation.Client; -import io.micronaut.test.support.TestPropertyProvider; -import jakarta.inject.Inject; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.testcontainers.containers.KafkaContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentLinkedDeque; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.awaitility.Awaitility.await; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Testcontainers -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -abstract class AbstractEventsTest implements TestPropertyProvider { - - @Container - static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest")); - - @Inject - EventsListener eventsListener; - - @Inject - EventService eventService; - - @Inject - EventsClient client; - - @Test - void testEventAndReceive() { - final Map details = Collections.singletonMap("product", "product-001"); - final String source = "client"; - final String track = "abcxyz"; - final String type = "pageView"; - eventService.postEvents( - source, - track, - new Event(type, details) - ); - - assertEventReceived(source, track, type, details); - } - - @Test - void testPostEvents() { - final Map details = Collections.singletonMap("product", "product-001"); - final String source = "client"; - final String track = "abcxyz"; - final String type = "pageView"; - final EventsReceived eventsReceived = client.postEvents( - source, - track, - new Event(type, details) - ); - - assertNotNull(eventsReceived); - assertTrue(eventsReceived.isSuccess()); - assertEquals(1, eventsReceived.getEvents()); - assertEventReceived(source, track, type, details); - } - - private void assertEventReceived(String source, String track, String type, Map details) { - await().atMost(30, SECONDS).until(() -> !eventsListener.received.isEmpty()); - - final EventRecord eventRecord = eventsListener.received.stream().findFirst().orElse(null); - assertNotNull(eventRecord); - assertEquals(source, eventRecord.getSource()); - assertEquals(track, eventRecord.getTrack()); - assertNotNull(eventRecord.getTime()); - assertEquals(type, eventRecord.getType()); - assertEquals(details, eventRecord.getDetail()); - } - - @NonNull - @Override - public Map getProperties() { - return Collections.singletonMap( - "kafka.bootstrap.servers", kafka.getBootstrapServers() - ); - } - - @KafkaListener(offsetReset = OffsetReset.EARLIEST) - static class EventsListener { - private final Collection received = new ConcurrentLinkedDeque<>(); - - @Topic("events") - void receive(EventRecord eventRecord) { - received.add(eventRecord); - } - } - - @Client("/events") - interface EventsClient { - @Post(processes = MediaType.APPLICATION_JSON) - EventsReceived postEvents( - String source, - String track, - Event...events); - } -} +package events; + +import events.model.Event; +import events.model.EventRecord; +import events.model.EventsReceived; +import events.service.EventService; +import io.micronaut.configuration.kafka.annotation.KafkaListener; +import io.micronaut.configuration.kafka.annotation.OffsetReset; +import io.micronaut.configuration.kafka.annotation.Topic; +import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Post; +import io.micronaut.http.client.annotation.Client; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedDeque; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +abstract class AbstractEventsTest { + + @Inject + EventsListener eventsListener; + + @Inject + EventService eventService; + + @Inject + EventsClient client; + + @Test + void testEventAndReceive() { + final Map details = Collections.singletonMap("product", "product-001"); + final String source = "client"; + final String track = "abcxyz"; + final String type = "pageView"; + eventService.postEvents( + source, + track, + new Event(type, details) + ); + + assertEventReceived(source, track, type, details); + } + + @Test + void testPostEvents() { + final Map details = Collections.singletonMap("product", "product-001"); + final String source = "client"; + final String track = "abcxyz"; + final String type = "pageView"; + System.out.println("Client posting event: " + type); + final EventsReceived eventsReceived = client.postEvents( + source, + track, + new Event(type, details) + ); + + assertNotNull(eventsReceived); + assertTrue(eventsReceived.success()); + assertEquals(1, eventsReceived.events()); + assertEventReceived(source, track, type, details); + } + + private void assertEventReceived(String source, String track, String type, Map details) { + await().atMost(60, SECONDS).until(() -> !eventsListener.received.isEmpty()); + + final EventRecord eventRecord = eventsListener.received.stream().findFirst().orElse(null); + assertNotNull(eventRecord); + assertEquals(source, eventRecord.source()); + assertEquals(track, eventRecord.track()); + assertNotNull(eventRecord.time()); + assertEquals(type, eventRecord.type()); + assertEquals(details, eventRecord.detail()); + } + + + @KafkaListener(offsetReset = OffsetReset.EARLIEST) + static class EventsListener { + private final Collection received = new ConcurrentLinkedDeque<>(); + + @Topic("events") + void receive(EventRecord eventRecord) { + received.add(eventRecord); + } + } + + @Client("/events") + interface EventsClient { + @Post(processes = MediaType.APPLICATION_JSON) + EventsReceived postEvents( + String source, + String track, + Event...events); + } +}