From 6af56b262a91ab89c3822c7479d63e6d6be750b0 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 13:00:05 -0500 Subject: [PATCH 01/10] Add examples for SE and MP to update counters of HTTP response status ranges (1xx, 2xx, etc.) --- .../http-status-count-se/.dockerignore | 1 + .../metrics/http-status-count-se/Dockerfile | 30 ++++ .../http-status-count-se/Dockerfile.jlink | 25 +++ .../http-status-count-se/Dockerfile.native | 42 +++++ .../metrics/http-status-count-se/README.md | 169 ++++++++++++++++++ .../metrics/http-status-count-se/app.yaml | 32 ++++ examples/metrics/http-status-count-se/pom.xml | 83 +++++++++ .../se/httpstatuscount/GreetService.java | 137 ++++++++++++++ .../HttpStatusMetricService.java | 85 +++++++++ .../examples/se/httpstatuscount/Main.java | 97 ++++++++++ .../httpstatuscount/SimpleGreetService.java | 74 ++++++++ .../se/httpstatuscount/package-info.java | 1 + .../META-INF/native-image/reflect-config.json | 1 + .../src/main/resources/application.yaml | 8 + .../src/main/resources/logging.properties | 18 ++ .../examples/se/httpstatuscount/MainTest.java | 127 +++++++++++++ .../se/httpstatuscount/StatusService.java | 49 +++++ .../se/httpstatuscount/StatusTest.java | 130 ++++++++++++++ .../src/test/resources/application.yaml | 10 ++ examples/metrics/pom.xml | 1 + .../http-status-count-mp/README.md | 78 ++++++++ .../http-status-count-mp/app.yaml | 32 ++++ .../microprofile/http-status-count-mp/pom.xml | 116 ++++++++++++ .../mp/httpstatuscount/GreetResource.java | 115 ++++++++++++ .../mp/httpstatuscount/GreetingProvider.java | 35 ++++ .../HttpStatusMetricFilter.java | 83 +++++++++ .../examples/mp/httpstatuscount/Message.java | 31 ++++ .../httpstatuscount/SimpleGreetResource.java | 71 ++++++++ .../mp/httpstatuscount/package-info.java | 2 + .../src/main/resources/META-INF/beans.xml | 8 + .../META-INF/microprofile-config.properties | 11 ++ .../META-INF/native-image/reflect-config.json | 1 + .../src/main/resources/application.yaml | 0 .../src/main/resources/logging.properties | 22 +++ .../examples/mp/httpstatuscount/MainTest.java | 105 +++++++++++ .../mp/httpstatuscount/StatusResource.java | 51 ++++++ .../mp/httpstatuscount/StatusTest.java | 101 +++++++++++ .../src/test/resources/application.yaml | 2 + examples/microprofile/pom.xml | 1 + 39 files changed, 1985 insertions(+) create mode 100644 examples/metrics/http-status-count-se/.dockerignore create mode 100644 examples/metrics/http-status-count-se/Dockerfile create mode 100644 examples/metrics/http-status-count-se/Dockerfile.jlink create mode 100644 examples/metrics/http-status-count-se/Dockerfile.native create mode 100644 examples/metrics/http-status-count-se/README.md create mode 100644 examples/metrics/http-status-count-se/app.yaml create mode 100644 examples/metrics/http-status-count-se/pom.xml create mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java create mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java create mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java create mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java create mode 100644 examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java create mode 100644 examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json create mode 100644 examples/metrics/http-status-count-se/src/main/resources/application.yaml create mode 100644 examples/metrics/http-status-count-se/src/main/resources/logging.properties create mode 100644 examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java create mode 100644 examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java create mode 100644 examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java create mode 100644 examples/metrics/http-status-count-se/src/test/resources/application.yaml create mode 100644 examples/microprofile/http-status-count-mp/README.md create mode 100644 examples/microprofile/http-status-count-mp/app.yaml create mode 100644 examples/microprofile/http-status-count-mp/pom.xml create mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java create mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java create mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java create mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java create mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java create mode 100644 examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java create mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml create mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties create mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json create mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/application.yaml create mode 100644 examples/microprofile/http-status-count-mp/src/main/resources/logging.properties create mode 100644 examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java create mode 100644 examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java create mode 100644 examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java create mode 100644 examples/microprofile/http-status-count-mp/src/test/resources/application.yaml diff --git a/examples/metrics/http-status-count-se/.dockerignore b/examples/metrics/http-status-count-se/.dockerignore new file mode 100644 index 00000000000..c8b241f2215 --- /dev/null +++ b/examples/metrics/http-status-count-se/.dockerignore @@ -0,0 +1 @@ +target/* \ No newline at end of file diff --git a/examples/metrics/http-status-count-se/Dockerfile b/examples/metrics/http-status-count-se/Dockerfile new file mode 100644 index 00000000000..9a7f2d6a3b1 --- /dev/null +++ b/examples/metrics/http-status-count-se/Dockerfile @@ -0,0 +1,30 @@ + +# 1st stage, build the app +FROM maven:3.6-jdk-11 as build + +WORKDIR /helidon + +# Create a first layer to cache the "Maven World" in the local repository. +# Incremental docker builds will always resume after that, unless you update +# the pom +ADD pom.xml . +RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip + +# Do the Maven build! +# Incremental docker builds will resume here when you change sources +ADD src src +RUN mvn package -DskipTests + +RUN echo "done!" + +# 2nd stage, build the runtime image +FROM openjdk:11-jre-slim +WORKDIR /helidon + +# Copy the binary built in the 1st stage +COPY --from=build /helidon/target/http-status-count-se.jar ./ +COPY --from=build /helidon/target/libs ./libs + +CMD ["java", "-jar", "http-status-count-se.jar"] + +EXPOSE 8080 diff --git a/examples/metrics/http-status-count-se/Dockerfile.jlink b/examples/metrics/http-status-count-se/Dockerfile.jlink new file mode 100644 index 00000000000..dc9f8c99f04 --- /dev/null +++ b/examples/metrics/http-status-count-se/Dockerfile.jlink @@ -0,0 +1,25 @@ + +# 1st stage, build the app +FROM maven:3.6.3-jdk-11-slim as build + +WORKDIR /helidon + +# Create a first layer to cache the "Maven World" in the local repository. +# Incremental docker builds will always resume after that, unless you update +# the pom +ADD pom.xml . +RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip + +# Do the Maven build to create the custom Java Runtime Image +# Incremental docker builds will resume here when you change sources +ADD src src +RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN echo "done!" + +# 2nd stage, build the final image with the JRI built in the 1st stage + +FROM debian:stretch-slim +WORKDIR /helidon +COPY --from=build /helidon/target/http-status-count-se-jri ./ +ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] +EXPOSE 8080 diff --git a/examples/metrics/http-status-count-se/Dockerfile.native b/examples/metrics/http-status-count-se/Dockerfile.native new file mode 100644 index 00000000000..865813c0b7b --- /dev/null +++ b/examples/metrics/http-status-count-se/Dockerfile.native @@ -0,0 +1,42 @@ + +# 1st stage, build the app +FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build + +# Install native-image +RUN gu install native-image + +WORKDIR /usr/share + +# Install maven +RUN set -x && \ + curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ + tar -xvf apache-maven-*-bin.tar.gz && \ + rm apache-maven-*-bin.tar.gz && \ + mv apache-maven-* maven && \ + ln -s /usr/share/maven/bin/mvn /bin/ + +WORKDIR /helidon + +# Create a first layer to cache the "Maven World" in the local repository. +# Incremental docker builds will always resume after that, unless you update +# the pom +ADD pom.xml . +RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip + +# Do the Maven build! +# Incremental docker builds will resume here when you change sources +ADD src src +RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests + +RUN echo "done!" + +# 2nd stage, build the runtime image +FROM scratch +WORKDIR /helidon + +# Copy the binary built in the 1st stage +COPY --from=build /helidon/target/http-status-count-se . + +ENTRYPOINT ["./http-status-count-se"] + +EXPOSE 8080 diff --git a/examples/metrics/http-status-count-se/README.md b/examples/metrics/http-status-count-se/README.md new file mode 100644 index 00000000000..b7626363563 --- /dev/null +++ b/examples/metrics/http-status-count-se/README.md @@ -0,0 +1,169 @@ +# http-status-count-se + +This Helidon SE project illustrates a service which updates a family of counters based on the HTTP status returned in each response. + +The main source in this example is identical to that in the Helidon SE QuickStart application except in these ways: +* The `HttpStatusMetricService` class creates and updates the status metrics. +* The `Main` class has a two small enhancements: + * The `createRouting` method instantiates `HttpStatusMetricService` and sets up routing for it. + * The `startServer` method has an additional variant to simplify a new unit test. + +## Incorporating status metrics into your own application +Use this example for inspiration in writing your own service or just use the `HttpStatusMetricService` directly in your own application. + +1. Copy and paste the `HttpStatusMetricService` class into your application, adjusting the package declaration as needed. +2. Register routing for an instance of `HttpStatusMetricService`, as shown here: + ```java + Routing.Builder builder = Routing.builder() + ... + .register(HttpStatusMetricService.create() + ... + ``` + +## Build and run + + +With JDK17+ +```bash +mvn package +java -jar target/http-status-count-se.jar +``` + +## Exercise the application +```bash +curl -X GET http://localhost:8080/simple-greet +``` +```listing +{"message":"Hello World!"} +``` + +```bash +curl -X GET http://localhost:8080/greet +``` +```listing +{"message":"Hello World!"} +``` +```bash +curl -X GET http://localhost:8080/greet/Joe +``` +```listing +{"message":"Hello Joe!"} +``` +```bash +curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting + +curl -X GET http://localhost:8080/greet/Jose +``` +```listing +{"message":"Hola Jose!"} +``` + +## Try metrics +```bash +# Prometheus Format +curl -s -X GET http://localhost:8080/metrics/application +``` + +```listing +... +# TYPE application_httpStatus_total counter +# HELP application_httpStatus_total Counts the number of HTTP responses in each status category (1xx, 2xx, etc.) +application_httpStatus_total{range="1xx"} 0 +application_httpStatus_total{range="2xx"} 5 +application_httpStatus_total{range="3xx"} 0 +application_httpStatus_total{range="4xx"} 0 +application_httpStatus_total{range="5xx"} 0 +... +``` +# JSON Format + +```bash +curl -H "Accept: application/json" -X GET http://localhost:8080/metrics +``` +```json +{ +... + "httpStatus;range=1xx": 0, + "httpStatus;range=2xx": 5, + "httpStatus;range=3xx": 0, + "httpStatus;range=4xx": 0, + "httpStatus;range=5xx": 0, +... +``` + +## Try health + +```bash +curl -s -X GET http://localhost:8080/health +``` +```listing +{"outcome":"UP",... + +``` + + + +## Building a Native Image + +Make sure you have GraalVM locally installed: + +``` +$GRAALVM_HOME/bin/native-image --version +``` + +Build the native image using the native image profile: + +``` +mvn package -Pnative-image +``` + +This uses the helidon-maven-plugin to perform the native compilation using your installed copy of GraalVM. It might take a while to complete. +Once it completes start the application using the native executable (no JVM!): + +``` +./target/http-status-count-se +``` + +Yep, it starts fast. You can exercise the application’s endpoints as before. + + +## Build the Docker Image +``` +docker build -t http-status-count-se . +``` + + +## Building a Custom Runtime Image + +Build the custom runtime image using the jlink image profile: + +``` +mvn package -Pjlink-image +``` + +This uses the helidon-maven-plugin to perform the custom image generation. +After the build completes it will report some statistics about the build including the reduction in image size. + +The target/http-status-count-se-jri directory is a self contained custom image of your application. It contains your application, +its runtime dependencies and the JDK modules it depends on. You can start your application using the provide start script: + +``` +./target/http-status-count-se-jri/bin/start +``` + +Class Data Sharing (CDS) Archive +Also included in the custom image is a Class Data Sharing (CDS) archive that improves your application’s startup +performance and in-memory footprint. You can learn more about Class Data Sharing in the JDK documentation. + +The CDS archive increases your image size to get these performance optimizations. It can be of significant size (tens of MB). +The size of the CDS archive is reported at the end of the build output. + +If you’d rather have a smaller image size (with a slightly increased startup time) you can skip the creation of the CDS +archive by executing your build like this: + +``` +mvn package -Pjlink-image -Djlink.image.addClassDataSharingArchive=false +``` + +For more information on available configuration options see the helidon-maven-plugin documentation. + diff --git a/examples/metrics/http-status-count-se/app.yaml b/examples/metrics/http-status-count-se/app.yaml new file mode 100644 index 00000000000..84a113bd34e --- /dev/null +++ b/examples/metrics/http-status-count-se/app.yaml @@ -0,0 +1,32 @@ +# +# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +kind: Service +apiVersion: v1 +metadata: + name: http-status-count-se + labels: + app: http-status-count-se +spec: + type: NodePort + selector: + app: http-status-count-se + ports: + - port: 8080 + targetPort: 8080 + name: http +--- + diff --git a/examples/metrics/http-status-count-se/pom.xml b/examples/metrics/http-status-count-se/pom.xml new file mode 100644 index 00000000000..677c8ff3481 --- /dev/null +++ b/examples/metrics/http-status-count-se/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + io.helidon.applications + helidon-se + 3.0.0-SNAPSHOT + + + io.helidon.examples + http-status-count-se + 1.0-SNAPSHOT + + + io.helidon.examples.se.httpstatuscount.Main + + + + + io.helidon.webserver + helidon-webserver + + + io.helidon.config + helidon-config-yaml + + + io.helidon.metrics + helidon-metrics + + + io.helidon.health + helidon-health + + + io.helidon.health + helidon-health-checks + + + io.helidon.media + helidon-media-jsonp + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + io.helidon.webclient + helidon-webclient + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + io.helidon.build-tools + helidon-maven-plugin + + + third-party-license-report + + + + + + diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java new file mode 100644 index 00000000000..68aa9d3746d --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java @@ -0,0 +1,137 @@ + +package io.helidon.examples.se.httpstatuscount; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.json.Json; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; + +import io.helidon.common.http.Http; +import io.helidon.config.Config; +import io.helidon.webserver.Routing; +import io.helidon.webserver.ServerRequest; +import io.helidon.webserver.ServerResponse; +import io.helidon.webserver.Service; + +/** + * A simple service to greet you. Examples: + * + * Get default greeting message: + * curl -X GET http://localhost:8080/greet + * + * Get greeting message for Joe: + * curl -X GET http://localhost:8080/greet/Joe + * + * Change greeting + * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting + * + * The message is returned as a JSON object + */ + +public class GreetService implements Service { + + /** + * The config value for the key {@code greeting}. + */ + private final AtomicReference greeting = new AtomicReference<>(); + + private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); + + private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); + + GreetService(Config config) { + greeting.set(config.get("app.greeting").asString().orElse("Ciao")); + } + + /** + * A service registers itself by updating the routing rules. + * @param rules the routing rules. + */ + @Override + public void update(Routing.Rules rules) { + rules + .get("/", this::getDefaultMessageHandler) + .get("/{name}", this::getMessageHandler) + .put("/greeting", this::updateGreetingHandler); + } + + /** + * Return a worldly greeting message. + * @param request the server request + * @param response the server response + */ + private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { + sendResponse(response, "World"); + } + + /** + * Return a greeting message using the name that was provided. + * @param request the server request + * @param response the server response + */ + private void getMessageHandler(ServerRequest request, ServerResponse response) { + String name = request.path().param("name"); + sendResponse(response, name); + } + + private void sendResponse(ServerResponse response, String name) { + String msg = String.format("%s %s!", greeting.get(), name); + + JsonObject returnObject = JSON.createObjectBuilder() + .add("message", msg) + .build(); + response.send(returnObject); + } + + private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { + + if (ex.getCause() instanceof JsonException){ + + LOGGER.log(Level.FINE, "Invalid JSON", ex); + JsonObject jsonErrorObject = JSON.createObjectBuilder() + .add("error", "Invalid JSON") + .build(); + response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); + } else { + + LOGGER.log(Level.FINE, "Internal error", ex); + JsonObject jsonErrorObject = JSON.createObjectBuilder() + .add("error", "Internal error") + .build(); + response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); + } + + return null; + } + + private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { + if (!jo.containsKey("greeting")) { + JsonObject jsonErrorObject = JSON.createObjectBuilder() + .add("error", "No greeting provided") + .build(); + response.status(Http.Status.BAD_REQUEST_400) + .send(jsonErrorObject); + return; + } + + greeting.set(jo.getString("greeting")); + response.status(Http.Status.NO_CONTENT_204).send(); + } + + /** + * Set the greeting to use in future messages. + * @param request the server request + * @param response the server response + */ + private void updateGreetingHandler(ServerRequest request, + ServerResponse response) { + request.content().as(JsonObject.class) + .thenAccept(jo -> updateGreetingFromJson(jo, response)) + .exceptionally(ex -> processErrors(ex, request, response)); + } +} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java new file mode 100644 index 00000000000..364a08927d1 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.examples.se.httpstatuscount; + +import io.helidon.metrics.api.RegistryFactory; +import io.helidon.webserver.Routing; +import io.helidon.webserver.ServerRequest; +import io.helidon.webserver.ServerResponse; +import io.helidon.webserver.Service; + +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; +import org.eclipse.microprofile.metrics.MetricUnits; +import org.eclipse.microprofile.metrics.Tag; + +/** + * Helidon SE service to update a family of counters based on the HTTP status of each response. Add an instance of this service + * to the application's routing. + *

+ * The service uses one {@link org.eclipse.microprofile.metrics.Counter} for each HTTP status family (1xx, 2xx, etc.). + * All counters share the same name--{@value STATUS_COUNTER_NAME}--and each has the tag {@value STATUS_TAG_NAME} with + * value {@code 1xx}, {@code 2xx}, etc. + *

+ */ +public class HttpStatusMetricService implements Service { + + static final String STATUS_COUNTER_NAME = "httpStatus"; + + static final String STATUS_TAG_NAME = "range"; + + private final Counter[] responseCounters = new Counter[6]; + + static HttpStatusMetricService create() { + return new HttpStatusMetricService(); + } + + private HttpStatusMetricService() { + MetricRegistry appRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); + Metadata metadata = Metadata.builder() + .withName(STATUS_COUNTER_NAME) + .withDisplayName("HTTP response values") + .withDescription("Counts the number of HTTP responses in each status category (1xx, 2xx, etc.)") + .withType(MetricType.COUNTER) + .withUnit(MetricUnits.NONE) + .build(); + // Declare the counters and keep references to them. + for (int i = 1; i < responseCounters.length; i++) { + responseCounters[i] = appRegistry.counter(metadata, new Tag(STATUS_TAG_NAME, i + "xx")); + } + } + + @Override + public void update(Routing.Rules rules) { + rules.any(this::updateRange); + } + + // Edited to adopt Ciaran's fix later in the thread. + private void updateRange(ServerRequest request, ServerResponse response) { + response.whenSent() + .thenAccept(this::logMetric); + request.next(); + } + + private void logMetric(ServerResponse response) { + int range = response.status().code() / 100; + if (range > 0 && range < responseCounters.length) { + responseCounters[range].inc(); + } + } +} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java new file mode 100644 index 00000000000..a7de6ca7bb2 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java @@ -0,0 +1,97 @@ +package io.helidon.examples.se.httpstatuscount; + + +import io.helidon.media.jsonp.JsonpSupport; +import io.helidon.metrics.MetricsSupport; +import io.helidon.health.HealthSupport; +import io.helidon.health.checks.HealthChecks; +import io.helidon.common.LogConfig; +import io.helidon.common.reactive.Single; +import io.helidon.config.Config; +import io.helidon.webserver.Routing; +import io.helidon.webserver.WebServer; + + + +/** + * The application main class. + */ +public final class Main { + + /** + * Cannot be instantiated. + */ + private Main() { + } + + /** + * Application main entry point. + * @param args command line arguments. + */ + public static void main(final String[] args) { + startServer(); + } + + /** + * Start the server. + * @return the created {@link WebServer} instance + */ + static Single startServer() { + return startServer(createRouting(Config.create())); + } + + static Single startServer(Routing.Builder routingBuilder) { + + // load logging configuration + LogConfig.configureRuntime(); + + // By default this will pick up application.yaml from the classpath + Config config = Config.create(); + + WebServer server = WebServer.builder(routingBuilder) + .config(config.get("server")) + .addMediaSupport(JsonpSupport.create()) + .build(); + + Single webserver = server.start(); + + // Try to start the server. If successful, print some info and arrange to + // print a message at shutdown. If unsuccessful, print the exception. + webserver.thenAccept(ws -> { + System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); + ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); + }) + .exceptionallyAccept(t -> { + System.err.println("Startup failed: " + t.getMessage()); + t.printStackTrace(System.err); + }); + + return webserver; + } + + /** + * Creates new {@link Routing}. + * + * @return routing configured with JSON support, a health check, and a service + * @param config configuration of this server + */ + static Routing.Builder createRouting(Config config) { + SimpleGreetService simpleGreetService = new SimpleGreetService(config); + GreetService greetService = new GreetService(config); + + HealthSupport health = HealthSupport.builder() + .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks + .build(); + + Routing.Builder builder = Routing.builder() + .register(MetricsSupport.create()) // Metrics at "/metrics" + .register(health) // Health at "/health" + .register(HttpStatusMetricService.create()) // no endpoint, just metrics updates + .register("/simple-greet", simpleGreetService) + .register("/greet", greetService) +; + + + return builder; + } +} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java new file mode 100644 index 00000000000..a87010b1b0c --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java @@ -0,0 +1,74 @@ +package io.helidon.examples.se.httpstatuscount; + +import java.util.Collections; +import java.util.logging.Logger; + +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Counter; +import io.helidon.metrics.api.RegistryFactory; +import jakarta.json.Json; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonObject; + +import io.helidon.config.Config; +import io.helidon.webserver.Routing; +import io.helidon.webserver.ServerRequest; +import io.helidon.webserver.ServerResponse; +import io.helidon.webserver.Service; + +/** + * A simple service to greet you. Examples: + * + * Get default greeting message: + * curl -X GET http://localhost:8080/simple-greet + * + * The message is returned as a JSON object + */ +public class SimpleGreetService implements Service { + + private static final Logger LOGGER = Logger.getLogger(SimpleGreetService.class.getName()); + private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); + + private final MetricRegistry registry = RegistryFactory.getInstance() + .getRegistry(MetricRegistry.Type.APPLICATION); + private final Counter accessCtr = registry.counter("accessctr"); + + private final String greeting; + + SimpleGreetService(Config config) { + greeting = config.get("app.greeting").asString().orElse("Ciao"); + } + + + /** + * A service registers itself by updating the routing rules. + * + * @param rules the routing rules. + */ + @Override + public void update(Routing.Rules rules) { + rules.get("/", this::getDefaultMessageHandler); + rules.get("/greet-count", this::countAccess, this::getDefaultMessageHandler); + } + + /** + * Return a worldly greeting message. + * + * @param request the server request + * @param response the server response + */ + private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { + String msg = String.format("%s %s!", greeting, "World"); + LOGGER.info("Greeting message is " + msg); + JsonObject returnObject = JSON.createObjectBuilder() + .add("message", msg) + .build(); + response.send(returnObject); + } + + + private void countAccess(ServerRequest request, ServerResponse response) { + accessCtr.inc(); + request.next(); + } +} diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java new file mode 100644 index 00000000000..b43262099db --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java @@ -0,0 +1 @@ +package io.helidon.examples.se.httpstatuscount; diff --git a/examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json b/examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1 @@ +[] diff --git a/examples/metrics/http-status-count-se/src/main/resources/application.yaml b/examples/metrics/http-status-count-se/src/main/resources/application.yaml new file mode 100644 index 00000000000..6b26b0d2185 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/resources/application.yaml @@ -0,0 +1,8 @@ +server: + port: 8080 + host: 0.0.0.0 + +app: + greeting: "Hello" + + diff --git a/examples/metrics/http-status-count-se/src/main/resources/logging.properties b/examples/metrics/http-status-count-se/src/main/resources/logging.properties new file mode 100644 index 00000000000..4d1080e8a45 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/main/resources/logging.properties @@ -0,0 +1,18 @@ +# Example Logging Configuration File +# For more information see $JAVA_HOME/jre/lib/logging.properties + +# Send messages to the console +handlers=io.helidon.common.HelidonConsoleHandler + +# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n + +# Global logging level. Can be overridden by specific loggers +.level=INFO + +# Component specific log levels +#io.helidon.webserver.level=INFO +#io.helidon.config.level=INFO +#io.helidon.security.level=INFO +#io.helidon.common.level=INFO +#io.netty.level=INFO diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java new file mode 100644 index 00000000000..e3d2dbde030 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java @@ -0,0 +1,127 @@ + +package io.helidon.examples.se.httpstatuscount; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.Collections; +import jakarta.json.Json; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonObject; + +import io.helidon.media.jsonp.JsonpSupport; +import io.helidon.common.http.Http; +import io.helidon.webclient.WebClient; +import io.helidon.webclient.WebClientResponse; +import io.helidon.webserver.WebServer; + +import org.junit.jupiter.api.Order; +import jakarta.json.JsonObject; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.MethodOrderer.MethodName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +@TestMethodOrder(MethodOrderer.MethodName.class) +public class MainTest { + + private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); + private static final JsonObject TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() + .add("greeting", "Hola") + .build(); + + private static WebServer webServer; + private static WebClient webClient; + + @BeforeAll + public static void startTheServer() { + webServer = Main.startServer().await(); + + webClient = WebClient.builder() + .baseUri("http://localhost:" + webServer.port()) + .addMediaSupport(JsonpSupport.create()) + .build(); + } + + @AfterAll + public static void stopServer() throws Exception { + if (webServer != null) { + webServer.shutdown() + .toCompletableFuture() + .get(10, TimeUnit.SECONDS); + } + } + + + @Test + public void testMicroprofileMetrics() { + String get = webClient.get() + .path("/simple-greet/greet-count") + .request(String.class) + .await(); + + assertThat(get, containsString("Hello World!")); + + String openMetricsOutput = webClient.get() + .path("/metrics") + .request(String.class) + .await(); + + assertThat("Metrics output", openMetricsOutput, containsString("application_accessctr_total")); + } + + @Test + public void testMetrics() throws Exception { + WebClientResponse response = webClient.get() + .path("/metrics") + .request() + .await(); + assertThat(response.status().code(), is(200)); + } + + @Test + public void testHealth() throws Exception { + WebClientResponse response = webClient.get() + .path("health") + .request() + .await(); + assertThat(response.status().code(), is(200)); + } + + @Test + public void testSimpleGreet() throws Exception { + JsonObject jsonObject = webClient.get() + .path("/simple-greet") + .request(JsonObject.class) + .await(); + assertThat(jsonObject.getString("message"), is("Hello World!")); + } + @Test + public void testGreetings() { + JsonObject jsonObject; + WebClientResponse response; + + jsonObject = webClient.get() + .path("/greet/Joe") + .request(JsonObject.class) + .await(); + assertThat(jsonObject.getString("message"), is("Hello Joe!")); + + response = webClient.put() + .path("/greet/greeting") + .submit(TEST_JSON_OBJECT) + .await(); + assertThat(response.status().code(), is(204)); + + jsonObject = webClient.get() + .path("/greet/Joe") + .request(JsonObject.class) + .await(); + assertThat(jsonObject.getString("message"), is("Hola Joe!")); + } +} diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java new file mode 100644 index 00000000000..68816a3c0b6 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.examples.se.httpstatuscount; + +import io.helidon.common.http.Http; +import io.helidon.webserver.Routing; +import io.helidon.webserver.ServerRequest; +import io.helidon.webserver.ServerResponse; +import io.helidon.webserver.Service; + +/** + * Test-only service that allows the client to specify what HTTP status the service should return in its response. + * This allows the client to know which status family counter should be updated. + */ +public class StatusService implements Service { + + @Override + public void update(Routing.Rules rules) { + rules.get("/{status}", this::respondWithRequestedStatus); + } + + private void respondWithRequestedStatus(ServerRequest request, ServerResponse response) { + String statusText = request.path().param("status"); + int status; + String msg; + try { + status = Integer.parseInt(statusText); + msg = "Successful conversion"; + } catch (NumberFormatException ex) { + status = Http.Status.INTERNAL_SERVER_ERROR_500.code(); + msg = "Unsuccessful conversion"; + } + response.status(status) + .send(msg); + } +} diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java new file mode 100644 index 00000000000..b6cb621d326 --- /dev/null +++ b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.examples.se.httpstatuscount; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import io.helidon.common.http.Http; +import io.helidon.common.http.MediaType; +import io.helidon.config.Config; +import io.helidon.media.jsonp.JsonpSupport; +import io.helidon.metrics.api.RegistryFactory; +import io.helidon.webclient.WebClient; +import io.helidon.webclient.WebClientResponse; +import io.helidon.webserver.Routing; +import io.helidon.webserver.WebServer; + +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.MetricID; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Tag; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class StatusTest { + + private static WebServer webServer; + private static WebClient webClient; + + private Counter[] STATUS_COUNTERS = new Counter[6]; + + private MetricRegistry metricRegistry; + + @BeforeAll + static void init() { + Routing.Builder routingBuilder = Main.createRouting(Config.create()); + routingBuilder.register("/status", new StatusService()); + + webServer = Main.startServer(routingBuilder).await(); + + webClient = WebClient.builder() + .baseUri("http://localhost:" + webServer.port()) + .addMediaSupport(JsonpSupport.create()) + .build(); + } + + @AfterAll + public static void stopServer() throws Exception { + if (webServer != null) { + webServer.shutdown() + .toCompletableFuture() + .get(10, TimeUnit.SECONDS); + } + } + + @BeforeEach + void findStatusMetrics() { + metricRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); + for (int i = 1; i < 6; i++) { + STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricService.STATUS_COUNTER_NAME, + new Tag(HttpStatusMetricService.STATUS_TAG_NAME, i + "xx"))); + } + } + + @Test + void checkStatusMetrics() throws ExecutionException, InterruptedException { + checkAfterStatus(171); + checkAfterStatus(200); + checkAfterStatus(201); + checkAfterStatus(204); + checkAfterStatus(301); + checkAfterStatus(401); + checkAfterStatus(404); + } + + @Test + void checkStatusAfterGreet() throws ExecutionException, InterruptedException { + long[] before = new long[6]; + for (int i = 1; i < 6; i++) { + before[i] = STATUS_COUNTERS[i].getCount(); + } + WebClientResponse response = webClient.get() + .path("/greet") + .accept(MediaType.APPLICATION_JSON) + .request() + .get(); + assertThat("Status of /greet", response.status().code(), is(Http.Status.OK_200.code())); + checkCounters(response.status().code(), before); + } + + void checkAfterStatus(int status) throws ExecutionException, InterruptedException { + long[] before = new long[6]; + for (int i = 1; i < 6; i++) { + before[i] = STATUS_COUNTERS[i].getCount(); + } + WebClientResponse response = webClient.get() + .path("/status/" + status) + .accept(MediaType.APPLICATION_JSON) + .request() + .get(); + assertThat("Response status", response.status().code(), is(status)); + checkCounters(status, before); + } + + private void checkCounters(int status, long[] before) { + int family = status / 100; + for (int i = 1; i < 6; i++) { + long expectedDiff = i == family ? 1 : 0; + assertThat("Diff in counter " + family + "xx", STATUS_COUNTERS[i].getCount() - before[i], is(expectedDiff)); + } + } +} diff --git a/examples/metrics/http-status-count-se/src/test/resources/application.yaml b/examples/metrics/http-status-count-se/src/test/resources/application.yaml new file mode 100644 index 00000000000..9e1d48e547a --- /dev/null +++ b/examples/metrics/http-status-count-se/src/test/resources/application.yaml @@ -0,0 +1,10 @@ +server: + port: 8080 + host: 0.0.0.0 + +app: + greeting: "Hello" + +security: + enabled: false + diff --git a/examples/metrics/pom.xml b/examples/metrics/pom.xml index 87241d25482..e79d38d55c8 100644 --- a/examples/metrics/pom.xml +++ b/examples/metrics/pom.xml @@ -35,6 +35,7 @@ exemplar kpi filtering + http-status-count-se diff --git a/examples/microprofile/http-status-count-mp/README.md b/examples/microprofile/http-status-count-mp/README.md new file mode 100644 index 00000000000..0e574905de9 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/README.md @@ -0,0 +1,78 @@ +# http-status-count-mp + +This Helidon MP project illustrates a filter which updates a family of counters based on the HTTP status returned in each response. + +The addition of the single filter class `HttpStatusMetricFilter` is the only difference from the Helidon MP QuickStart project. + +## Incorporating status metrics into your own application +Use this example for inspiration in writing your own filter or just use the filter directly in your own application by copying and pasting the `HttpStatusMetricFilter` class into your application, adjusting the package declaration as needed. Helidon MP discovers and uses your filter automatically. + +## Build and run + + +With JDK17+ +```bash +mvn package +java -jar target/http-status-count-mp.jar +``` + +## Exercise the application +```bash +curl -X GET http://localhost:8080/simple-greet +``` +```listing +{"message":"Hello World!"} +``` + +```bash +curl -X GET http://localhost:8080/greet +``` +```listing +{"message":"Hello World!"} +``` +```bash +curl -X GET http://localhost:8080/greet/Joe +``` +```listing +{"message":"Hello Joe!"} +``` +```bash +curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting + +curl -X GET http://localhost:8080/greet/Jose +``` +```listing +{"message":"Hola Jose!"} +``` + +## Try metrics +```bash +# Prometheus Format +curl -s -X GET http://localhost:8080/metrics/application +``` + +```listing +... +# TYPE application_httpStatus_total counter +# HELP application_httpStatus_total Counts the number of HTTP responses in each status category (1xx, 2xx, etc.) +application_httpStatus_total{range="1xx"} 0 +application_httpStatus_total{range="2xx"} 5 +application_httpStatus_total{range="3xx"} 0 +application_httpStatus_total{range="4xx"} 0 +application_httpStatus_total{range="5xx"} 0 +... +``` +# JSON Format + +```bash +curl -H "Accept: application/json" -X GET http://localhost:8080/metrics +``` +```json +{ +... + "httpStatus;range=1xx": 0, + "httpStatus;range=2xx": 5, + "httpStatus;range=3xx": 0, + "httpStatus;range=4xx": 0, + "httpStatus;range=5xx": 0, +... diff --git a/examples/microprofile/http-status-count-mp/app.yaml b/examples/microprofile/http-status-count-mp/app.yaml new file mode 100644 index 00000000000..7f243250ec8 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/app.yaml @@ -0,0 +1,32 @@ +# +# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +kind: Service +apiVersion: v1 +metadata: + name: http-status-count-mp + labels: + app: http-status-count-mp +spec: + type: NodePort + selector: + app: http-status-count-mp + ports: + - port: 8080 + targetPort: 8080 + name: http +--- + diff --git a/examples/microprofile/http-status-count-mp/pom.xml b/examples/microprofile/http-status-count-mp/pom.xml new file mode 100644 index 00000000000..1a2d1d731a4 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + + io.helidon.applications + helidon-mp + 3.0.0-RC2 + + + io.helidon.examples + http-status-count-mp + 1.0-SNAPSHOT + + + 3.0.0-RC2 + + + + + io.helidon.microprofile.bundles + helidon-microprofile + + + com.fasterxml.jackson.core + jackson-databind + + + io.helidon.media + helidon-media-jackson + + + org.eclipse.microprofile.metrics + microprofile-metrics-api + + + io.helidon.microprofile.metrics + helidon-microprofile-metrics + + + io.helidon.microprofile.health + helidon-microprofile-health + + + org.jboss + jandex + runtime + + + jakarta.activation + jakarta.activation-api + runtime + + + io.helidon.microprofile.bundles + helidon-microprofile-core + + + org.glassfish.jersey.media + jersey-media-json-binding + runtime + + + io.helidon.webclient + helidon-webclient + + + org.junit.jupiter + junit-jupiter-api + test + + + io.helidon.microprofile.tests + helidon-microprofile-tests-junit5 + test + + + org.hamcrest + hamcrest-all + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + io.helidon.build-tools + helidon-maven-plugin + + + third-party-license-report + + + + + org.jboss.jandex + jandex-maven-plugin + + + make-index + + + + + + diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java new file mode 100644 index 00000000000..573abf9a1f9 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java @@ -0,0 +1,115 @@ + +package io.helidon.examples.mp.httpstatuscount; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; + +/** + * A simple JAX-RS resource to greet you. Examples: + * + * Get default greeting message: + * curl -X GET http://localhost:8080/greet + * + * Get greeting message for Joe: + * curl -X GET http://localhost:8080/greet/Joe + * + * Change greeting + * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting + * + * The message is returned as a JSON object. + */ +@Path("/greet") +@RequestScoped +public class GreetResource { + + /** + * The greeting message provider. + */ + private final GreetingProvider greetingProvider; + + /** + * Using constructor injection to get a configuration property. + * By default this gets the value from META-INF/microprofile-config + * + * @param greetingConfig the configured greeting message + */ + @Inject + public GreetResource(GreetingProvider greetingConfig) { + this.greetingProvider = greetingConfig; + } + + /** + * Return a worldly greeting message. + * + * @return {@link Message} + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Message getDefaultMessage() { + return createResponse("World"); + } + + /** + * Return a greeting message using the name that was provided. + * + * @param name the name to greet + * @return {@link Message} + */ + @Path("/{name}") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Message getMessage(@PathParam("name") String name) { + return createResponse(name); + } + + /** + * Set the greeting to use in future messages. + * + * @param jsonNode JSON containing the new greeting + * @return {@link Response} + */ + @Path("/greeting") + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @RequestBody(name = "greeting", + required = true, + content = @Content(mediaType = "application/json", + schema = @Schema(type = SchemaType.OBJECT, requiredProperties = { "greeting" }))) + @APIResponses({ + @APIResponse(name = "normal", responseCode = "204", description = "Greeting updated"), + @APIResponse(name = "missing 'greeting'", responseCode = "400", + description = "JSON did not contain setting for 'greeting'")}) + public Response updateGreeting(Message message) { + + if (message.getGreeting() == null || message.getGreeting().isEmpty()) { + Message error = new Message(); + error.setMessage("No greeting provided"); + return Response.status(Response.Status.BAD_REQUEST).entity(error).build(); + } + + greetingProvider.setMessage(message.getGreeting()); + return Response.status(Response.Status.NO_CONTENT).build(); + } + + private Message createResponse(String who) { + String msg = String.format("%s %s!", greetingProvider.getMessage(), who); + + return new Message(msg); + } +} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java new file mode 100644 index 00000000000..f525fce66fb --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java @@ -0,0 +1,35 @@ + +package io.helidon.examples.mp.httpstatuscount; + +import java.util.concurrent.atomic.AtomicReference; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +/** + * Provider for greeting message. + */ +@ApplicationScoped +public class GreetingProvider { + private final AtomicReference message = new AtomicReference<>(); + + /** + * Create a new greeting provider, reading the message from configuration. + * + * @param message greeting to use + */ + @Inject + public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) { + this.message.set(message); + } + + String getMessage() { + return message.get(); + } + + void setMessage(String message) { + this.message.set(message); + } +} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java new file mode 100644 index 00000000000..7f7ab5b12e0 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package io.helidon.examples.mp.httpstatuscount; + +import java.io.IOException; + +import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; +import jakarta.ws.rs.ConstrainedTo; +import jakarta.ws.rs.RuntimeType; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; +import jakarta.ws.rs.ext.Provider; +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.Metadata; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.MetricType; +import org.eclipse.microprofile.metrics.MetricUnits; +import org.eclipse.microprofile.metrics.Tag; + +/** + * REST service filter to update a family of counters based on the HTTP status of each response. + *

+ * The filter uses one {@link org.eclipse.microprofile.metrics.Counter} for each HTTP status family (1xx, 2xx, etc.). + * All counters share the same name--{@value STATUS_COUNTER_NAME}--and each has the tag {@value STATUS_TAG_NAME} with + * value {@code 1xx}, {@code 2xx}, etc. + *

+ */ +@ConstrainedTo(RuntimeType.SERVER) +@Provider +public class HttpStatusMetricFilter implements ContainerResponseFilter { + + static final String STATUS_COUNTER_NAME = "httpStatus"; + static final String STATUS_TAG_NAME = "range"; + + @Inject + private MetricRegistry metricRegistry; + + private final Counter[] responseCounters = new Counter[6]; + + @PostConstruct + private void init() { + Metadata metadata = Metadata.builder() + .withName(STATUS_COUNTER_NAME) + .withDisplayName("HTTP response values") + .withDescription("Counts the number of HTTP responses in each status category (1xx, 2xx, etc.)") + .withType(MetricType.COUNTER) + .withUnit(MetricUnits.NONE) + .build(); + // Declare the counters and keep references to them. + for (int i = 1; i < responseCounters.length; i++) { + responseCounters[i] = metricRegistry.counter(metadata, new Tag(STATUS_TAG_NAME, i + "xx")); + } + } + + @Override + public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) + throws IOException { + updateCountForStatus(containerResponseContext.getStatus()); + } + + private void updateCountForStatus(int statusCode) { + int range = statusCode / 100; + if (range > 0 && range < responseCounters.length) { + responseCounters[range].inc(); + } + } +} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java new file mode 100644 index 00000000000..ce68f3bd7ba --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java @@ -0,0 +1,31 @@ +package io.helidon.examples.mp.httpstatuscount; + +public class Message { + + private String message; + + private String greeting; + + public Message() { + } + + public Message(String message) { + this.message = message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } + + public String getGreeting() { + return this.greeting; + } +} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java new file mode 100644 index 00000000000..817ea0f1962 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java @@ -0,0 +1,71 @@ + +package io.helidon.examples.mp.httpstatuscount; + +import java.util.Collections; + +import org.eclipse.microprofile.metrics.MetricUnits; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; +import jakarta.ws.rs.PathParam; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +/** + * A simple JAX-RS resource to greet you. Examples: + * + * Get default greeting message: + * curl -X GET http://localhost:8080/simple-greet + * + * The message is returned as a JSON object. + */ +@Path("/simple-greet") +public class SimpleGreetResource { + + private static final String PERSONALIZED_GETS_COUNTER_NAME = "personalizedGets"; + private static final String PERSONALIZED_GETS_COUNTER_DESCRIPTION = "Counts personalized GET operations"; + private static final String GETS_TIMER_NAME = "allGets"; + private static final String GETS_TIMER_DESCRIPTION = "Tracks all GET operations"; + private final String message; + + @Inject + public SimpleGreetResource(@ConfigProperty(name = "app.greeting") String message) { + this.message = message; + } + + /** + * Return a worldly greeting message. + * + * @return {@link Message} + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Message getDefaultMessage() { + String msg = String.format("%s %s!", message, "World"); + Message message = new Message(); + message.setMessage(msg); + return message; + } + + + @Path("/{name}") + @GET + @Produces(MediaType.APPLICATION_JSON) + @Counted(name = PERSONALIZED_GETS_COUNTER_NAME, + absolute = true, + description = PERSONALIZED_GETS_COUNTER_DESCRIPTION) + @Timed(name = GETS_TIMER_NAME, + description = GETS_TIMER_DESCRIPTION, + unit = MetricUnits.SECONDS, + absolute = true) + public String getMessage(@PathParam("name") String name) { + return String.format("Hello %s", name); + } + +} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java new file mode 100644 index 00000000000..5e036488ef9 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java @@ -0,0 +1,2 @@ + +package io.helidon.examples.mp.httpstatuscount; diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000000..5d94aab5a26 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml @@ -0,0 +1,8 @@ + + + diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..e3b22ac3a9b --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1,11 @@ +# Microprofile server properties +server.port=8080 +server.host=0.0.0.0 + +# Change the following to true to enable the optional MicroProfile Metrics REST.request metrics +metrics.rest-request.enabled=false + +# Application properties. This is the default greeting +app.greeting=Hello + + diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1 @@ +[] diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml b/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties b/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties new file mode 100644 index 00000000000..5157244b93c --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties @@ -0,0 +1,22 @@ + +# Example Logging Configuration File +# For more information see $JAVA_HOME/jre/lib/logging.properties + +# Send messages to the console +handlers=io.helidon.common.HelidonConsoleHandler + +# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n + +# Global logging level. Can be overridden by specific loggers +.level=INFO + +# Quiet Weld +org.jboss.level=WARNING + +# Component specific log levels +#io.helidon.webserver.level=INFO +#io.helidon.config.level=INFO +#io.helidon.security.level=INFO +#io.helidon.common.level=INFO +#io.netty.level=INFO diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java new file mode 100644 index 00000000000..a77030fedc8 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java @@ -0,0 +1,105 @@ + +package io.helidon.examples.mp.httpstatuscount; + +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.MetricRegistry; +import jakarta.inject.Inject; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.MediaType; + +import io.helidon.media.jackson.JacksonSupport; +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.MethodOrderer.MethodName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +@HelidonTest +@TestMethodOrder(MethodOrderer.MethodName.class) +public class MainTest { + + @Inject + private MetricRegistry registry; + + @Inject + private WebTarget target; + + + @Test + public void testMicroprofileMetrics() { + String message = target.path("simple-greet/Joe") + .request() + .get(String.class); + + assertThat(message, is("Hello Joe")); + Counter counter = registry.counter("personalizedGets"); + double before = counter.getCount(); + + message = target.path("simple-greet/Eric") + .request() + .get(String.class); + + assertThat(message, is("Hello Eric")); + double after = counter.getCount(); + assertEquals(1d, after - before, "Difference in personalized greeting counter between successive calls"); + } + + @Test + public void testMetrics() throws Exception { + Response response = target + .path("metrics") + .request() + .get(); + assertThat(response.getStatus(), is(200)); + } + + @Test + public void testHealth() throws Exception { + Response response = target + .path("health") + .request() + .get(); + assertThat(response.getStatus(), is(200)); + } + + @Test + public void testGreet() throws Exception { + Message message = target + .path("simple-greet") + .request() + .get(Message.class); + assertThat(message.getMessage(), is("Hello World!")); + } + + @Test + public void testGreetings() throws Exception { + Message jsonMessage = target + .path("greet/Joe") + .request() + .get(Message.class); + assertThat(jsonMessage.getMessage(), is("Hello Joe!")); + + try (Response r = target + .path("greet/greeting") + .request() + .put(Entity.entity("{\"greeting\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { + assertThat(r.getStatus(), is(204)); + } + + jsonMessage = target + .path("greet/Jose") + .request() + .get(Message.class); + assertThat(jsonMessage.getMessage(), is("Hola Jose!")); + } + +} diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java new file mode 100644 index 00000000000..f900d6f3ce3 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.examples.mp.httpstatuscount; + +import io.helidon.common.http.Http; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +/** + * Test-only resource that allows the client to specify what HTTP status the service should return in its response. + * This allows the client to know which status family counter should be updated. + */ +@RequestScoped +@Path("/status") +public class StatusResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + @Path("/{status}") + public Response reportStatus(@PathParam("status") String statusText) { + int status; + String msg; + try { + status = Integer.parseInt(statusText); + msg = "Successful conversion"; + } catch (NumberFormatException ex) { + status = Http.Status.INTERNAL_SERVER_ERROR_500.code(); + msg = "Unsuccessful conversion"; + } + return Response.status(status).entity(msg).build(); + } +} diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java new file mode 100644 index 00000000000..c64c4e2a3a5 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.examples.mp.httpstatuscount; + +import io.helidon.common.http.Http; +import io.helidon.microprofile.tests.junit5.AddBean; +import io.helidon.microprofile.tests.junit5.HelidonTest; + +import jakarta.inject.Inject; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.MetricID; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Tag; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +@HelidonTest +@AddBean(StatusResource.class) +public class StatusTest { + + @Inject + private WebTarget webTarget; + + @Inject + private MetricRegistry metricRegistry; + + private Counter[] STATUS_COUNTERS = new Counter[6]; + + @BeforeEach + void findStatusMetrics() { + for (int i = 1; i < 6; i++) { + STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricFilter.STATUS_COUNTER_NAME, + new Tag(HttpStatusMetricFilter.STATUS_TAG_NAME, i + "xx"))); + } + } + + @Test + void checkStatusMetrics() { + checkAfterStatus(171); + checkAfterStatus(200); + checkAfterStatus(201); + checkAfterStatus(204); + checkAfterStatus(301); + checkAfterStatus(401); + checkAfterStatus(404); + } + + @Test + void checkStatusAfterGreet() { + long[] before = new long[6]; + for (int i = 1; i < 6; i++) { + before[i] = STATUS_COUNTERS[i].getCount(); + } + Response response = webTarget.path("/greet") + .request(MediaType.APPLICATION_JSON) + .get(); + assertThat("Status of /greet", response.getStatus(), is(Http.Status.OK_200.code())); + checkCounters(response.getStatus(), before); + } + + void checkAfterStatus(int status) { + String path = "/status/" + status; + long[] before = new long[6]; + for (int i = 1; i < 6; i++) { + before[i] = STATUS_COUNTERS[i].getCount(); + } + Response response = webTarget.path(path) + .request(MediaType.TEXT_PLAIN_TYPE) + .get(); + assertThat("Response status", response.getStatus(), is(status)); + checkCounters(status, before); + } + + private void checkCounters(int status, long[] before) { + int family = status / 100; + for (int i = 1; i < 6; i++) { + long expectedDiff = i == family ? 1 : 0; + assertThat("Diff in counter " + family + "xx", STATUS_COUNTERS[i].getCount() - before[i], is(expectedDiff)); + } + } + +} diff --git a/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml b/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml new file mode 100644 index 00000000000..94f34514486 --- /dev/null +++ b/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml @@ -0,0 +1,2 @@ +security: + enabled: false \ No newline at end of file diff --git a/examples/microprofile/pom.xml b/examples/microprofile/pom.xml index 45c3a228a6c..e332ce84f81 100644 --- a/examples/microprofile/pom.xml +++ b/examples/microprofile/pom.xml @@ -47,5 +47,6 @@ tls multiport bean-validation + http-status-count-mp From a4b63a64fa920d7ec50ea383262aaa00b523d5d6 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 14:13:16 -0500 Subject: [PATCH 02/10] Add copyrights missing from generated quick-start sources --- .../http-status-count-se/.dockerignore | 1 - .../metrics/http-status-count-se/Dockerfile | 30 --------- .../http-status-count-se/Dockerfile.jlink | 25 ------- .../http-status-count-se/Dockerfile.native | 42 ------------ .../metrics/http-status-count-se/README.md | 67 ------------------- .../metrics/http-status-count-se/app.yaml | 32 --------- examples/metrics/http-status-count-se/pom.xml | 20 ++++++ .../se/httpstatuscount/GreetService.java | 16 ++++- .../examples/se/httpstatuscount/Main.java | 18 ++++- .../httpstatuscount/SimpleGreetService.java | 15 +++++ .../se/httpstatuscount/package-info.java | 18 +++++ .../META-INF/native-image/reflect-config.json | 1 - .../src/main/resources/application.yaml | 16 +++++ .../src/main/resources/logging.properties | 16 +++++ .../examples/se/httpstatuscount/MainTest.java | 21 ++++-- .../src/test/resources/application.yaml | 16 +++++ .../microprofile/http-status-count-mp/pom.xml | 20 ++++++ 17 files changed, 166 insertions(+), 208 deletions(-) delete mode 100644 examples/metrics/http-status-count-se/.dockerignore delete mode 100644 examples/metrics/http-status-count-se/Dockerfile delete mode 100644 examples/metrics/http-status-count-se/Dockerfile.jlink delete mode 100644 examples/metrics/http-status-count-se/Dockerfile.native delete mode 100644 examples/metrics/http-status-count-se/app.yaml delete mode 100644 examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json diff --git a/examples/metrics/http-status-count-se/.dockerignore b/examples/metrics/http-status-count-se/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/metrics/http-status-count-se/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/metrics/http-status-count-se/Dockerfile b/examples/metrics/http-status-count-se/Dockerfile deleted file mode 100644 index 9a7f2d6a3b1..00000000000 --- a/examples/metrics/http-status-count-se/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ - -# 1st stage, build the app -FROM maven:3.6-jdk-11 as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM openjdk:11-jre-slim -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/http-status-count-se.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "http-status-count-se.jar"] - -EXPOSE 8080 diff --git a/examples/metrics/http-status-count-se/Dockerfile.jlink b/examples/metrics/http-status-count-se/Dockerfile.jlink deleted file mode 100644 index dc9f8c99f04..00000000000 --- a/examples/metrics/http-status-count-se/Dockerfile.jlink +++ /dev/null @@ -1,25 +0,0 @@ - -# 1st stage, build the app -FROM maven:3.6.3-jdk-11-slim as build - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build to create the custom Java Runtime Image -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests -RUN echo "done!" - -# 2nd stage, build the final image with the JRI built in the 1st stage - -FROM debian:stretch-slim -WORKDIR /helidon -COPY --from=build /helidon/target/http-status-count-se-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/metrics/http-status-count-se/Dockerfile.native b/examples/metrics/http-status-count-se/Dockerfile.native deleted file mode 100644 index 865813c0b7b..00000000000 --- a/examples/metrics/http-status-count-se/Dockerfile.native +++ /dev/null @@ -1,42 +0,0 @@ - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-ce:java17-21.3.0 as build - -# Install native-image -RUN gu install native-image - -WORKDIR /usr/share - -# Install maven -RUN set -x && \ - curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ - tar -xvf apache-maven-*-bin.tar.gz && \ - rm apache-maven-*-bin.tar.gz && \ - mv apache-maven-* maven && \ - ln -s /usr/share/maven/bin/mvn /bin/ - -WORKDIR /helidon - -# Create a first layer to cache the "Maven World" in the local repository. -# Incremental docker builds will always resume after that, unless you update -# the pom -ADD pom.xml . -RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM scratch -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/http-status-count-se . - -ENTRYPOINT ["./http-status-count-se"] - -EXPOSE 8080 diff --git a/examples/metrics/http-status-count-se/README.md b/examples/metrics/http-status-count-se/README.md index b7626363563..6eff1943ef3 100644 --- a/examples/metrics/http-status-count-se/README.md +++ b/examples/metrics/http-status-count-se/README.md @@ -100,70 +100,3 @@ curl -s -X GET http://localhost:8080/health {"outcome":"UP",... ``` - - - -## Building a Native Image - -Make sure you have GraalVM locally installed: - -``` -$GRAALVM_HOME/bin/native-image --version -``` - -Build the native image using the native image profile: - -``` -mvn package -Pnative-image -``` - -This uses the helidon-maven-plugin to perform the native compilation using your installed copy of GraalVM. It might take a while to complete. -Once it completes start the application using the native executable (no JVM!): - -``` -./target/http-status-count-se -``` - -Yep, it starts fast. You can exercise the application’s endpoints as before. - - -## Build the Docker Image -``` -docker build -t http-status-count-se . -``` - - -## Building a Custom Runtime Image - -Build the custom runtime image using the jlink image profile: - -``` -mvn package -Pjlink-image -``` - -This uses the helidon-maven-plugin to perform the custom image generation. -After the build completes it will report some statistics about the build including the reduction in image size. - -The target/http-status-count-se-jri directory is a self contained custom image of your application. It contains your application, -its runtime dependencies and the JDK modules it depends on. You can start your application using the provide start script: - -``` -./target/http-status-count-se-jri/bin/start -``` - -Class Data Sharing (CDS) Archive -Also included in the custom image is a Class Data Sharing (CDS) archive that improves your application’s startup -performance and in-memory footprint. You can learn more about Class Data Sharing in the JDK documentation. - -The CDS archive increases your image size to get these performance optimizations. It can be of significant size (tens of MB). -The size of the CDS archive is reported at the end of the build output. - -If you’d rather have a smaller image size (with a slightly increased startup time) you can skip the creation of the CDS -archive by executing your build like this: - -``` -mvn package -Pjlink-image -Djlink.image.addClassDataSharingArchive=false -``` - -For more information on available configuration options see the helidon-maven-plugin documentation. - diff --git a/examples/metrics/http-status-count-se/app.yaml b/examples/metrics/http-status-count-se/app.yaml deleted file mode 100644 index 84a113bd34e..00000000000 --- a/examples/metrics/http-status-count-se/app.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -kind: Service -apiVersion: v1 -metadata: - name: http-status-count-se - labels: - app: http-status-count-se -spec: - type: NodePort - selector: - app: http-status-count-se - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - diff --git a/examples/metrics/http-status-count-se/pom.xml b/examples/metrics/http-status-count-se/pom.xml index 677c8ff3481..a1be01b5786 100644 --- a/examples/metrics/http-status-count-se/pom.xml +++ b/examples/metrics/http-status-count-se/pom.xml @@ -1,4 +1,22 @@ + + @@ -13,6 +31,8 @@ http-status-count-se 1.0-SNAPSHOT + Helidon Examples Metrics HTTP Status Counters + io.helidon.examples.se.httpstatuscount.Main diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java index 68aa9d3746d..f0b6c598ba9 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java @@ -1,4 +1,18 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.helidon.examples.se.httpstatuscount; import java.util.Collections; diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java index a7de6ca7bb2..9cdc3c6aed0 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java @@ -1,6 +1,20 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.helidon.examples.se.httpstatuscount; - import io.helidon.media.jsonp.JsonpSupport; import io.helidon.metrics.MetricsSupport; import io.helidon.health.HealthSupport; @@ -11,8 +25,6 @@ import io.helidon.webserver.Routing; import io.helidon.webserver.WebServer; - - /** * The application main class. */ diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java index a87010b1b0c..f7ae6485987 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.helidon.examples.se.httpstatuscount; import java.util.Collections; diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java index b43262099db..747a5c3e1fc 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java @@ -1 +1,19 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * HTTP status count module + */ package io.helidon.examples.se.httpstatuscount; diff --git a/examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json b/examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json deleted file mode 100644 index fe51488c706..00000000000 --- a/examples/metrics/http-status-count-se/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/metrics/http-status-count-se/src/main/resources/application.yaml b/examples/metrics/http-status-count-se/src/main/resources/application.yaml index 6b26b0d2185..e1e6249d8d4 100644 --- a/examples/metrics/http-status-count-se/src/main/resources/application.yaml +++ b/examples/metrics/http-status-count-se/src/main/resources/application.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + server: port: 8080 host: 0.0.0.0 diff --git a/examples/metrics/http-status-count-se/src/main/resources/logging.properties b/examples/metrics/http-status-count-se/src/main/resources/logging.properties index 4d1080e8a45..d73eb5b6607 100644 --- a/examples/metrics/http-status-count-se/src/main/resources/logging.properties +++ b/examples/metrics/http-status-count-se/src/main/resources/logging.properties @@ -1,3 +1,19 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + # Example Logging Configuration File # For more information see $JAVA_HOME/jre/lib/logging.properties diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java index e3d2dbde030..a8dfdf64d0f 100644 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java +++ b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java @@ -1,7 +1,20 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.helidon.examples.se.httpstatuscount; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.Collections; import jakarta.json.Json; @@ -9,17 +22,13 @@ import jakarta.json.JsonObject; import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.common.http.Http; import io.helidon.webclient.WebClient; import io.helidon.webclient.WebClientResponse; import io.helidon.webserver.WebServer; -import org.junit.jupiter.api.Order; -import jakarta.json.JsonObject; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.MethodOrderer.MethodName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; diff --git a/examples/metrics/http-status-count-se/src/test/resources/application.yaml b/examples/metrics/http-status-count-se/src/test/resources/application.yaml index 9e1d48e547a..9684e5692c3 100644 --- a/examples/metrics/http-status-count-se/src/test/resources/application.yaml +++ b/examples/metrics/http-status-count-se/src/test/resources/application.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + server: port: 8080 host: 0.0.0.0 diff --git a/examples/microprofile/http-status-count-mp/pom.xml b/examples/microprofile/http-status-count-mp/pom.xml index 1a2d1d731a4..9b417d51b13 100644 --- a/examples/microprofile/http-status-count-mp/pom.xml +++ b/examples/microprofile/http-status-count-mp/pom.xml @@ -1,4 +1,22 @@ + + @@ -13,6 +31,8 @@ http-status-count-mp 1.0-SNAPSHOT + Helidon Examples Metrics HTTP Status Counters + 3.0.0-RC2 From de4cf9d36159289d62d82edce8cf0ec7e3701ba3 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 14:21:55 -0500 Subject: [PATCH 03/10] Fix pom parent --- examples/metrics/http-status-count-se/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/metrics/http-status-count-se/pom.xml b/examples/metrics/http-status-count-se/pom.xml index a1be01b5786..571ec5d6634 100644 --- a/examples/metrics/http-status-count-se/pom.xml +++ b/examples/metrics/http-status-count-se/pom.xml @@ -25,7 +25,7 @@ io.helidon.applications helidon-se 3.0.0-SNAPSHOT - + ../../../applications/se/pom.xml io.helidon.examples http-status-count-se From c0f4288ad42d04cd48e18e146045e6e6feded695 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 14:38:20 -0500 Subject: [PATCH 04/10] Style issues --- .../se/httpstatuscount/package-info.java | 2 +- .../mp/httpstatuscount/GreetResource.java | 18 +++++++++++++++-- .../mp/httpstatuscount/GreetingProvider.java | 18 +++++++++++++++-- .../examples/mp/httpstatuscount/Message.java | 16 +++++++++++++++ .../httpstatuscount/SimpleGreetResource.java | 20 +++++++++++++++---- .../mp/httpstatuscount/package-info.java | 20 ++++++++++++++++++- .../src/main/resources/application.yaml | 16 +++++++++++++++ .../src/main/resources/logging.properties | 16 ++++++++++++++- .../examples/mp/httpstatuscount/MainTest.java | 16 ++++++++++++++- 9 files changed, 130 insertions(+), 12 deletions(-) diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java index 747a5c3e1fc..d5b622ea310 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java @@ -14,6 +14,6 @@ * limitations under the License. */ /** - * HTTP status count module + * HTTP status count example. */ package io.helidon.examples.se.httpstatuscount; diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java index 573abf9a1f9..7686598cc3d 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java @@ -1,4 +1,19 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ package io.helidon.examples.mp.httpstatuscount; import jakarta.enterprise.context.RequestScoped; @@ -11,7 +26,6 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; - import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.media.Content; import org.eclipse.microprofile.openapi.annotations.media.Schema; diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java index f525fce66fb..92594448af4 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java @@ -1,11 +1,25 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ package io.helidon.examples.mp.httpstatuscount; import java.util.concurrent.atomic.AtomicReference; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; - import org.eclipse.microprofile.config.inject.ConfigProperty; /** diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java index ce68f3bd7ba..9b5d6ab8df1 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ package io.helidon.examples.mp.httpstatuscount; public class Message { diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java index 817ea0f1962..8d08a284bb6 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java @@ -1,14 +1,26 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ package io.helidon.examples.mp.httpstatuscount; -import java.util.Collections; - import org.eclipse.microprofile.metrics.MetricUnits; import org.eclipse.microprofile.metrics.annotation.Counted; import org.eclipse.microprofile.metrics.annotation.Timed; import jakarta.ws.rs.PathParam; -import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java index 5e036488ef9..8230c98afb1 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java @@ -1,2 +1,20 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * HTTP status count example. + */ package io.helidon.examples.mp.httpstatuscount; diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml b/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml index e69de29bb2d..3a5ab924b72 100644 --- a/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml +++ b/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +server.port: 8080 diff --git a/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties b/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties index 5157244b93c..337435218ef 100644 --- a/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties +++ b/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties @@ -1,4 +1,18 @@ - +# +# Copyright (c) 2022 Oracle and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# # Example Logging Configuration File # For more information see $JAVA_HOME/jre/lib/logging.properties diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java index a77030fedc8..5e29e4e2849 100644 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java +++ b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java @@ -1,4 +1,18 @@ - +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.helidon.examples.mp.httpstatuscount; import org.eclipse.microprofile.metrics.Counter; From 9e3748dbd58df9beeb4b3ca1f22297303c89885a Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 14:51:16 -0500 Subject: [PATCH 05/10] Style fixes --- .../examples/se/httpstatuscount/Main.java | 8 ++--- .../httpstatuscount/SimpleGreetService.java | 14 ++++----- .../mp/httpstatuscount/GreetResource.java | 2 +- .../examples/mp/httpstatuscount/Message.java | 29 +++++++++++++++++++ .../httpstatuscount/SimpleGreetResource.java | 7 ++--- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java index 9cdc3c6aed0..c638d94e2cb 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java @@ -15,13 +15,13 @@ */ package io.helidon.examples.se.httpstatuscount; -import io.helidon.media.jsonp.JsonpSupport; -import io.helidon.metrics.MetricsSupport; -import io.helidon.health.HealthSupport; -import io.helidon.health.checks.HealthChecks; import io.helidon.common.LogConfig; import io.helidon.common.reactive.Single; import io.helidon.config.Config; +import io.helidon.health.HealthSupport; +import io.helidon.health.checks.HealthChecks; +import io.helidon.media.jsonp.JsonpSupport; +import io.helidon.metrics.MetricsSupport; import io.helidon.webserver.Routing; import io.helidon.webserver.WebServer; diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java index f7ae6485987..f49f6bd580d 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java @@ -18,19 +18,19 @@ import java.util.Collections; import java.util.logging.Logger; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Counter; -import io.helidon.metrics.api.RegistryFactory; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - import io.helidon.config.Config; +import io.helidon.metrics.api.RegistryFactory; import io.helidon.webserver.Routing; import io.helidon.webserver.ServerRequest; import io.helidon.webserver.ServerResponse; import io.helidon.webserver.Service; +import jakarta.json.Json; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonObject; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Counter; + /** * A simple service to greet you. Examples: * diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java index 7686598cc3d..750b54aeecf 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java @@ -94,7 +94,7 @@ public Message getMessage(@PathParam("name") String name) { /** * Set the greeting to use in future messages. * - * @param jsonNode JSON containing the new greeting + * @param message the new greeting * @return {@link Response} */ @Path("/greeting") diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java index 9b5d6ab8df1..c595a737df4 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/Message.java @@ -16,31 +16,60 @@ */ package io.helidon.examples.mp.httpstatuscount; +/** + * Greeting message. + */ public class Message { private String message; private String greeting; + /** + * Creates a new instance. + */ public Message() { } + /** + * Creates a new instance with a preset message. + * + * @param message initial message + */ public Message(String message) { this.message = message; } + /** + * Sets the message content. + * + * @param message the new message + */ public void setMessage(String message) { this.message = message; } + /** + * + * @return the current message content + */ public String getMessage() { return this.message; } + /** + * Sets the greeting. + * + * @param greeting new greeting + */ public void setGreeting(String greeting) { this.greeting = greeting; } + /** + * + * @return the greeting + */ public String getGreeting() { return this.greeting; } diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java index 8d08a284bb6..07e534451a6 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java @@ -16,16 +16,15 @@ */ package io.helidon.examples.mp.httpstatuscount; -import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Timed; import jakarta.ws.rs.PathParam; - import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.metrics.MetricUnits; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; import org.eclipse.microprofile.config.inject.ConfigProperty; From d6a99acbebafde29d5752a1b245dd51e78f83260 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 15:01:56 -0500 Subject: [PATCH 06/10] More style fixes --- .../se/httpstatuscount/GreetService.java | 2 +- .../examples/se/httpstatuscount/Main.java | 3 +-- .../se/httpstatuscount/SimpleGreetService.java | 2 +- .../mp/httpstatuscount/SimpleGreetResource.java | 16 ++++++++++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java index f0b6c598ba9..fa54126b9c1 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java @@ -25,8 +25,8 @@ import jakarta.json.JsonException; import jakarta.json.JsonObject; -import io.helidon.common.http.Http; import io.helidon.config.Config; +import io.helidon.common.http.Http; import io.helidon.webserver.Routing; import io.helidon.webserver.ServerRequest; import io.helidon.webserver.ServerResponse; diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java index c638d94e2cb..2137d1a2bae 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java @@ -100,8 +100,7 @@ static Routing.Builder createRouting(Config config) { .register(health) // Health at "/health" .register(HttpStatusMetricService.create()) // no endpoint, just metrics updates .register("/simple-greet", simpleGreetService) - .register("/greet", greetService) -; + .register("/greet", greetService); return builder; diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java index f49f6bd580d..2d9508ab7e3 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java @@ -28,8 +28,8 @@ import jakarta.json.Json; import jakarta.json.JsonBuilderFactory; import jakarta.json.JsonObject; -import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.MetricRegistry; /** * A simple service to greet you. Examples: diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java index 07e534451a6..9e8d299f9b2 100644 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java +++ b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java @@ -16,18 +16,17 @@ */ package io.helidon.examples.mp.httpstatuscount; -import jakarta.ws.rs.PathParam; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.metrics.MetricUnits; import org.eclipse.microprofile.metrics.annotation.Counted; import org.eclipse.microprofile.metrics.annotation.Timed; -import org.eclipse.microprofile.config.inject.ConfigProperty; - /** * A simple JAX-RS resource to greet you. Examples: * @@ -45,6 +44,10 @@ public class SimpleGreetResource { private static final String GETS_TIMER_DESCRIPTION = "Tracks all GET operations"; private final String message; + /** + * Creates a new instance using the configured default greeting. + * @param message initial greeting message + */ @Inject public SimpleGreetResource(@ConfigProperty(name = "app.greeting") String message) { this.message = message; @@ -64,7 +67,12 @@ public Message getDefaultMessage() { return message; } - + /** + * Returns a personalized greeting. + * + * @param name name with which to personalize the greeting + * @return personalized greeting message + */ @Path("/{name}") @GET @Produces(MediaType.APPLICATION_JSON) From fca2c3dafbaba074b6d02c2beefd7097a01d16ec Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 15:12:27 -0500 Subject: [PATCH 07/10] Last(?) style fix --- .../examples/se/httpstatuscount/GreetService.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java index fa54126b9c1..ed284f618f8 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java @@ -20,11 +20,6 @@ import java.util.logging.Level; import java.util.logging.Logger; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; - import io.helidon.config.Config; import io.helidon.common.http.Http; import io.helidon.webserver.Routing; @@ -32,6 +27,12 @@ import io.helidon.webserver.ServerResponse; import io.helidon.webserver.Service; +import jakarta.json.Json; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; + + /** * A simple service to greet you. Examples: * From 14a0acdafb3be46a0864d1d3f9f1e0b83f1cdec4 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Tue, 26 Jul 2022 15:21:03 -0500 Subject: [PATCH 08/10] Import ordering --- .../io/helidon/examples/se/httpstatuscount/GreetService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java index ed284f618f8..ab9f1160781 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java @@ -20,8 +20,8 @@ import java.util.logging.Level; import java.util.logging.Logger; -import io.helidon.config.Config; import io.helidon.common.http.Http; +import io.helidon.config.Config; import io.helidon.webserver.Routing; import io.helidon.webserver.ServerRequest; import io.helidon.webserver.ServerResponse; From 33f2d81c2fc9709c5744667387b3bd283272d4e6 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Wed, 27 Jul 2022 13:46:53 -0500 Subject: [PATCH 09/10] Adopt review comments (whitespace, loop iteration) --- .../io/helidon/examples/se/httpstatuscount/GreetService.java | 4 +--- .../io/helidon/examples/se/httpstatuscount/StatusTest.java | 2 +- .../io/helidon/examples/mp/httpstatuscount/StatusTest.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java index ab9f1160781..9e94b7ea7ec 100644 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ b/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java @@ -105,15 +105,13 @@ private void sendResponse(ServerResponse response, String name) { private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { - if (ex.getCause() instanceof JsonException){ - + if (ex.getCause() instanceof JsonException) { LOGGER.log(Level.FINE, "Invalid JSON", ex); JsonObject jsonErrorObject = JSON.createObjectBuilder() .add("error", "Invalid JSON") .build(); response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); } else { - LOGGER.log(Level.FINE, "Internal error", ex); JsonObject jsonErrorObject = JSON.createObjectBuilder() .add("error", "Internal error") diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java index b6cb621d326..88893461097 100644 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java +++ b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java @@ -74,7 +74,7 @@ public static void stopServer() throws Exception { @BeforeEach void findStatusMetrics() { metricRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); - for (int i = 1; i < 6; i++) { + for (int i = 1; i < STATUS_COUNTERS.length; i++) { STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricService.STATUS_COUNTER_NAME, new Tag(HttpStatusMetricService.STATUS_TAG_NAME, i + "xx"))); } diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java index c64c4e2a3a5..01ad25bb35d 100644 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java +++ b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java @@ -47,7 +47,7 @@ public class StatusTest { @BeforeEach void findStatusMetrics() { - for (int i = 1; i < 6; i++) { + for (int i = 1; i < STATUS_COUNTERS.length; i++) { STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricFilter.STATUS_COUNTER_NAME, new Tag(HttpStatusMetricFilter.STATUS_TAG_NAME, i + "xx"))); } From 0822dccf835c2491e2219ffa20582e9e083705a6 Mon Sep 17 00:00:00 2001 From: "tim.quinn@oracle.com" Date: Wed, 27 Jul 2022 13:50:46 -0500 Subject: [PATCH 10/10] Slight stylistic improvements in test --- .../io/helidon/examples/se/httpstatuscount/StatusTest.java | 6 ++---- .../io/helidon/examples/mp/httpstatuscount/StatusTest.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java index 88893461097..5eee561e696 100644 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java +++ b/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java @@ -45,9 +45,7 @@ public class StatusTest { private static WebServer webServer; private static WebClient webClient; - private Counter[] STATUS_COUNTERS = new Counter[6]; - - private MetricRegistry metricRegistry; + private final Counter[] STATUS_COUNTERS = new Counter[6]; @BeforeAll static void init() { @@ -73,7 +71,7 @@ public static void stopServer() throws Exception { @BeforeEach void findStatusMetrics() { - metricRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); + MetricRegistry metricRegistry = RegistryFactory.getInstance().getRegistry(MetricRegistry.Type.APPLICATION); for (int i = 1; i < STATUS_COUNTERS.length; i++) { STATUS_COUNTERS[i] = metricRegistry.counter(new MetricID(HttpStatusMetricService.STATUS_COUNTER_NAME, new Tag(HttpStatusMetricService.STATUS_TAG_NAME, i + "xx"))); diff --git a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java index 01ad25bb35d..a124a1d3d1c 100644 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java +++ b/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java @@ -43,7 +43,7 @@ public class StatusTest { @Inject private MetricRegistry metricRegistry; - private Counter[] STATUS_COUNTERS = new Counter[6]; + private final Counter[] STATUS_COUNTERS = new Counter[6]; @BeforeEach void findStatusMetrics() {